SQL SUM()
Quanto a Loja Aurora já vendeu? Quantas unidades estão paradas no depósito? Quanto a loja gastou com frete? Toda pergunta que começa com "quanto dá tudo junto" é uma soma, e em SQL quem soma é a função SUM() (do inglês sum, "soma"). Nesta aula você soma colunas, soma contas feitas linha a linha (quantidade × preço), aprende a ler os decimais do jeito que o SQLite os escreve e descobre por que a soma de nada não dá zero.
- Somar uma coluna inteira, ou só as linhas de um
WHERE. - Somar uma conta:
SUM(quantidade * preco_unitario), o faturamento. - Como o SQLite escreve os decimais (
18537.4, e não18537.40) e quando usarROUND(). - Por que a soma de nenhuma linha dá
NULL, e como trocar por 0. - A diferença entre
sum()etotal(), uma função só do SQLite. - As armadilhas:
SUM(DISTINCT …), somar texto e o estouro de inteiro.
A ideia: a fita da calculadora
Na Loja Aurora antiga, a Ana somava as vendas do dia numa calculadora de fita: digitava cada valor, apertava +, e no fim a fita mostrava o total. A SUM() é essa calculadora: ela passa por todas as linhas, pega o valor da coluna (ou da conta) que você pediu e vai somando. No fim, devolve um número só.
Duas regras que valem em toda a aula:
- A
SUM()soma números. Use-a em colunas comoestoque,preco,frete,salario. - Um
NULLé pulado: ele não conta como zero, ele simplesmente não entra na fita.
1. Somar uma coluna
Quantas unidades a loja tem no estoque, somando todos os produtos?
SELECT SUM(estoque) AS unidades FROM produtos;
- SUM
- A função de somar.
- (estoque)
- A coluna cujos valores vão ser somados, um de cada linha. Ao contrário do
COUNT, oSUMnão aceita*: ele precisa saber o que somar. - AS unidades
- O apelido da coluna do resultado.
- FROM produtos
- As 45 linhas que entram na soma.
Com WHERE, só as linhas escolhidas entram na fita. Quanto a loja gasta por mês com os salários dos vendedores e vendedoras?
SELECT SUM(salario) AS folha_vendas FROM funcionarios WHERE cargo LIKE 'Vendedor%';
O LIKE 'Vendedor%' (aula LIKE) pega "Vendedor" e "Vendedora": cinco pessoas. A soma dos cinco salários é 15657.55.
2. Como o SQLite escreve os números
Agora some uma coluna com decimais e compare com a soma do estoque:
SELECT SUM(estoque), typeof(SUM(estoque)),
SUM(preco), typeof(SUM(preco))
FROM produtos;
A função typeof() diz o tipo do valor (os tipos têm aula própria: Os Tipos no SQLite). Repare:
estoquesó tem números inteiros, então a soma é um inteiro,integer: 3301, sem vírgula nenhuma.precotem decimais (éREAL), então a soma também éreal: 2169.24.
E o jeito de escrever os decimais tem três detalhes que pegam quem vem da planilha:
| Você talvez espere | O SQLite escreve | Por quê |
|---|---|---|
2.169,24 | 2169.24 | O separador decimal é o ponto, como em inglês, e não existe separador de milhar |
18537,40 | 18537.4 | Ele não completa zeros à direita: 18537.4 e 18537.40 são o mesmo número |
9800 | 9800.0 | Um REAL sem parte decimal ganha .0, para mostrar que não é inteiro |
3. Somar uma conta: o faturamento
A tabela itens_pedido guarda, para cada produto de cada pedido, a quantidade e o preco_unitario (o preço do dia da compra). Ela não tem uma coluna "subtotal". Veja os três itens do pedido 1, com a conta feita linha a linha:
SELECT quantidade, preco_unitario,
quantidade * preco_unitario AS subtotal
FROM itens_pedido
WHERE pedido_id = 1;
Dentro do SUM pode ir uma conta, e não só uma coluna. O SQLite faz a conta em cada linha e soma os resultados:
SELECT SUM(quantidade * preco_unitario) AS produtos FROM itens_pedido WHERE pedido_id = 1;
- quantidade * preco_unitario
- A conta de cada linha: 2 × 12.35 = 24.7; 1 × 2.79 = 2.79; 3 × 1.15 = 3.45.
- SUM( … )
- Soma os três subtotais: 24.7 + 2.79 + 3.45 = 30.94, o valor dos produtos do pedido 1 (o frete fica à parte, na tabela
pedidos).
Sem o WHERE, você tem o faturamento da loja inteira, com todos os 220 itens vendidos:
SELECT SUM(quantidade * preco_unitario) AS faturamento FROM itens_pedido;
Atenção ao parêntese: é SUM(quantidade * preco_unitario), a soma das multiplicações. SUM(quantidade) * SUM(preco_unitario) seria outra coisa (o total de unidades vezes a soma de todos os preços), um número enorme e sem sentido.
Experimente: a consulta soma as unidades de Eletrônicos (categoria 2). A gerente quer o valor desse estoque em reais: o preço de cada produto vezes as unidades dele, tudo somado. Troque o que vai dentro do SUM.
SELECT SUM(estoque) AS valor_estoque FROM produtos WHERE categoria_id = 2;
SELECT SUM(preco * estoque) AS valor_estoque FROM produtos WHERE categoria_id = 2;
4. ROUND: o número que você vê e o número guardado
O computador guarda os números com decimais em binário, e muitos decimais "redondos" para nós, como 0.1 ou 1.15, não têm uma forma exata em binário. O SQLite esconde isso ao mostrar o número (ele escreve no máximo 15 algarismos), mas o valor guardado pode ter uma sobrinha minúscula lá no fim. Veja o pedido 1 de novo:
SELECT SUM(quantidade * preco_unitario) AS soma,
SUM(quantidade * preco_unitario) = 30.94 AS igual,
SUM(quantidade * preco_unitario) - 30.94 AS diferenca,
ROUND(SUM(quantidade * preco_unitario), 2) = 30.94 AS igual_com_round
FROM itens_pedido
WHERE pedido_id = 1;
A soma aparece como 30.94, mas a comparação = 30.94 dá 0 (falso)! A coluna diferenca mostra por quê: o valor guardado fica um tiquinho abaixo de 30.94. O e-15 quer dizer "vezes 10 elevado a −15": a diferença é de 0,0000000000000036, invisível na tela, mas suficiente para o = dizer "não é igual". Com ROUND(…, 2) ("arredondar", em inglês), o valor é arredondado para 2 casas e a comparação dá 1 (verdadeiro).
- ROUND(valor, 2)
- Arredonda o valor para 2 casas decimais. O segundo número é quantas casas manter:
ROUND(2169.24, 1)dá 2169.2; sem ele,ROUND(2169.24)arredonda para o inteiro e dá 2169.0.
A regra prática: dinheiro somado, arredonde com ROUND(…, 2) antes de comparar, de guardar ou de mostrar para alguém. O ROUND não acrescenta zeros: ROUND(18537.4, 2) continua 18537.4. Se você precisa do texto com duas casas, para um relatório, use printf('%.2f', …), que devolve o texto 18537.40 (mais em Funções Numéricas):
SELECT ROUND(SUM(quantidade * preco_unitario), 2) AS numero,
printf('%.2f', SUM(quantidade * preco_unitario)) AS texto
FROM itens_pedido;
5. A soma de nada é NULL
Quanto a loja vendeu de produtos acima de R$ 1000? Nenhum produto custa isso:
SELECT SUM(estoque) AS soma FROM produtos WHERE preco > 1000;
O resultado é NULL, e não 0. Para o SQL, a soma de nenhum valor é "desconhecida". Isso atrapalha num relatório ("vendemos NULL reais?") e em contas: NULL + 10 dá NULL. Para trocar por zero, embrulhe a soma em COALESCE ou IFNULL (aula IFNULL e COALESCE): eles devolvem o segundo valor quando o primeiro é NULL.
SELECT COALESCE(SUM(estoque), 0) AS com_coalesce,
IFNULL(SUM(estoque), 0) AS com_ifnull
FROM produtos
WHERE preco > 1000;
6. total(): a soma do SQLite que nunca dá NULL
O SQLite tem uma segunda função de soma, total(), que não existe nos outros bancos. Ela soma igualzinho, com duas diferenças:
SELECT SUM(estoque), TOTAL(estoque) FROM produtos;
SELECT SUM(estoque), TOTAL(estoque) FROM produtos WHERE preco > 1000;
SUM() | TOTAL() | |
|---|---|---|
Sem nenhuma linha (ou só NULL) | NULL | 0.0 |
| Soma de inteiros | Inteiro: 3301 | Sempre REAL: 3301.0 |
| Inteiros grandes demais | Erro integer overflow | Nunca dá erro |
| Existe em outros bancos? | Sim, é do padrão SQL | Não, só no SQLite |
Qual usar? SUM(), quase sempre: ela funciona em qualquer banco, e o NULL da soma vazia se resolve com COALESCE(SUM(x), 0), que também funciona em qualquer banco. A total() é um atalho para quando você sabe que o SQL vai rodar só no SQLite.
7. Formas diferentes de somar o frete
Quanto a loja pagou de frete nos pedidos de 2026? A coluna data está no formato AAAA-MM-DD, então "começa com 2026" serve de filtro:
SELECT SUM(frete) AS frete_2026 FROM pedidos WHERE data LIKE '2026%';
SELECT SUM(frete) AS frete_2026 FROM pedidos WHERE data BETWEEN '2026-01-01' AND '2026-12-31';
As duas dão 374.15. E uma terceira forma, que parece igual mas não é:
SELECT SUM(frete) AS todos,
SUM(DISTINCT frete) AS distintos
FROM pedidos;
O SUM(DISTINCT frete) soma cada valor de frete uma vez só: o 9.9, que aparece em vários pedidos, entra uma vez. Isso quase nunca é o que você quer num total de dinheiro: dois pedidos com o mesmo frete são dois pagamentos.
| Forma | Quando usar |
|---|---|
SUM(coluna) | O total de verdade. É quase sempre esta. |
SUM(conta) | Quando o valor de cada linha é uma conta, como quantidade * preco_unitario |
ROUND(SUM(…), 2) | Dinheiro: antes de comparar, guardar ou mostrar |
COALESCE(SUM(…), 0) | Quando o filtro pode não deixar passar nada e você quer 0, e não NULL |
SUM(DISTINCT coluna) | Raramente: somar os valores diferentes, não as linhas |
TOTAL(coluna) | Só no SQLite, quando quer 0.0 em vez de NULL |
Quando dá errado
A Ana queria contar os clientes e escreveu SUM no lugar de COUNT:
SELECT SUM(nome) FROM clientes;
O que aconteceu: nenhum erro, e o resultado é 0.0. O SQLite tenta transformar cada texto em número; um texto que não parece número, como "José Ribamar Silva", vale 0. Trinta zeros somados dão 0.0. O SQLite não reclama, então quem tem de perceber é você.
Como consertar: para contar, COUNT. SUM é só para colunas de números.
SELECT SUM(*) FROM itens_pedido;
A mensagem: wrong number of arguments to function SUM(), "número errado de argumentos para a função SUM()". O * só vale dentro do COUNT.
Como consertar: diga o que somar: SUM(quantidade), ou SUM(quantidade * preco_unitario).
SELECT SUM(quantidade, preco_unitario) FROM itens_pedido;
A mensagem: a mesma, wrong number of arguments to function SUM(). A vírgula separa argumentos, e o SUM aceita um só.
Como consertar: se você quer a soma das multiplicações, escreva a conta: SUM(quantidade * preco_unitario). Se quer duas somas, use dois SUM: SUM(quantidade), SUM(preco_unitario).
integer overflow
O maior inteiro que o SQLite guarda é 9223372036854775807 (mais de 9 quintilhões). Somar além disso com SUM dá erro. Para ver, a consulta abaixo usa uma tabelinha de duas linhas criada na hora com VALUES (a coluna dela se chama column1):
SELECT SUM(column1) FROM (VALUES (9223372036854775807), (1));
A mensagem: integer overflow, "estouro de inteiro": o resultado não cabe. A TOTAL(column1) não dá erro, porque soma em REAL; ela devolve 9.22337203685478e+18 (9,22 × 1018), um número aproximado. Na Loja Aurora isso nunca acontece, mas é bom saber que a mensagem existe.
total()é só do SQLite. Nos outros, useCOALESCE(SUM(x), 0), que funciona em todos. A documentação do PostgreSQL avisa o mesmo que você viu aqui: a soma de nenhuma linha éNULL, e não zero.- PostgreSQL:
SUMde uma colunaintegerdevolvebigint, um inteiro maior, e denumericdevolvenumeric, um decimal exato, sem a sobrinha binária da seção 4. - MySQL:
SUMde inteiros ou deDECIMALdevolveDECIMAL(exato); deFLOATouDOUBLE, devolveDOUBLE. - Nesses bancos, dinheiro costuma ficar em colunas
DECIMAL/NUMERIC, que guardam os centavos exatos. O SQLite não tem esse tipo; por isso oROUND(…, 2)é tão importante aqui (veja Os Tipos no SQLite).
Referência rápida
| Escrita | O que faz | Na Loja Aurora |
|---|---|---|
SUM(coluna) | Soma os valores, pulando NULL | SUM(estoque) = 3301 |
SUM(a * b) | Faz a conta em cada linha e soma | faturamento = 18537.4 |
ROUND(SUM(x), 2) | Arredonda a soma para 2 casas | |
COALESCE(SUM(x), 0) | 0 em vez de NULL quando não há linhas | |
SUM(DISTINCT x) | Soma cada valor diferente uma vez | SUM(DISTINCT frete) = 116.25 |
TOTAL(x) | Só SQLite: soma em REAL, 0.0 sem linhas, nunca estoura | TOTAL(estoque) = 3301.0 |
| Mensagem do SQLite | Quer dizer |
|---|---|
wrong number of arguments to function SUM() | SUM(*) ou mais de um valor dentro do SUM |
integer overflow | A soma de inteiros passou de 9223372036854775807 |
misuse of aggregate function SUM() | SUM dentro do WHERE (veja HAVING) |
Exercícios
1. Unidades vendidas
Complete para somar todas as unidades vendidas (a coluna quantidade de itens_pedido):
2. Duas casas
Complete para arredondar a soma dos fretes para 2 casas decimais:
3. Nenhum pedido tem frete acima de 100. O que devolve SELECT SUM(frete) FROM pedidos WHERE frete > 100;?
4. Como o SQLite escreve a soma de 9000.25 com 9000.15?
5. Qual consulta dá o faturamento (o valor de todos os itens vendidos)?
6. Qual a diferença entre SUM(estoque) e TOTAL(estoque) na tabela inteira de produtos?
Missão final: o faturamento de 2025
Missão: os pedidos de 2025 são os de id 33 a 64. A consulta soma as unidades vendidas nesses pedidos. A gerente quer o faturamento deles em reais: a soma de quantidade × preço unitário de todos os itens desses pedidos. Se quiser, arredonde para 2 casas.
SELECT SUM(quantidade) AS faturamento_2025 FROM itens_pedido WHERE pedido_id BETWEEN 33 AND 64;
SELECT ROUND(SUM(quantidade * preco_unitario), 2) AS faturamento_2025 FROM itens_pedido WHERE pedido_id BETWEEN 33 AND 64;
Resumo
SUM(coluna)soma os valores de todas as linhas (ou só as doWHERE), pulando osNULL.- Dentro do
SUMpode ir uma conta:SUM(quantidade * preco_unitario)faz a conta linha a linha e soma. - O SQLite escreve
18537.4: ponto decimal, sem separador de milhar, sem zeros à direita. Soma de inteiros dá inteiro; deREAL, dáREAL. - O decimal guardado pode ter uma sobrinha binária: arredonde dinheiro com
ROUND(…, 2)antes de comparar. - A soma de nenhuma linha é
NULL. Troque por zero comCOALESCE(SUM(x), 0). TOTAL()é a soma do SQLite que dá 0.0 em vez deNULLe sempre devolveREAL; não existe nos outros bancos.