Folha de consulta de SQL (PostgreSQL)

As instruções de que você mais precisa, com um exemplo de cada. Os exemplos rodam no banco de dados de prática da padaria e usam a sintaxe do PostgreSQL. Outros bancos diferem em pequenos detalhes, que são indicados onde importam.

Ler e filtrar

SELECT escolhe as colunas, FROM indica a tabela, WHERE mantém as linhas que correspondem, ORDER BY ordena e LIMIT corta o resultado. Texto vai entre aspas simples.

Comentários são ignorados: `--` até o fim da linha, ou `/* ... */` em várias linhas. Use-os para explicar uma consulta, não no lugar de uma instrução clara.

SELECT name, unit_price
FROM products
WHERE category = 'pastry' AND unit_price < 3
ORDER BY unit_price DESC
LIMIT 5;

Resultado: Os produtos de pastelaria abaixo de 3.00, do mais caro para o mais barato.

Padrões, listas, intervalos e NULL

LIKE compara padrões (% é qualquer texto, _ é um caractere; ILIKE ignora maiúsculas e minúsculas). IN testa uma lista, BETWEEN testa um intervalo inclusivo, IS NULL encontra valores ausentes.

SELECT first_name, loyalty_tier
FROM customers
WHERE first_name LIKE 'A%' OR loyalty_tier IS NULL
ORDER BY first_name;

Resultado: Clientes cujo nome começa com A, ou que não têm nível de fidelidade.

Resumir com GROUP BY

COUNT, SUM, AVG, MIN e MAX transformam linhas em um valor por grupo. WHERE filtra as linhas antes do agrupamento, HAVING filtra os grupos.

SELECT channel, COUNT(*) AS orders
FROM orders
GROUP BY channel
HAVING COUNT(*) > 5
ORDER BY channel;

Resultado: Só o canal online, com 7 pedidos.

Juntar tabelas

INNER JOIN mantém as correspondências, LEFT JOIN mantém cada linha da tabela da esquerda. Dê apelidos curtos às tabelas e sempre faça a junção pela chave.

SELECT p.name, SUM(oi.quantity) AS units
FROM products AS p
JOIN order_items AS oi ON oi.product_id = p.product_id
GROUP BY p.name
ORDER BY units DESC, p.name
LIMIT 3;

Resultado: Os três produtos mais vendidos.

CASE: if/else em SQL

CASE retorna o valor da primeira condição verdadeira, como SES no Excel. Sem ELSE, ele retorna NULL.

SELECT name,
       CASE WHEN unit_price < 3 THEN 'budget' WHEN unit_price <= 4 THEN 'standard' ELSE 'premium' END AS band
FROM products
ORDER BY product_id;

Resultado: Cada produto rotulado como budget, standard ou premium.

Subconsultas e WITH

Uma subconsulta é uma consulta dentro de outra. WITH dá um nome a uma delas, para que você leia a consulta principal como uma história.

ANY e ALL comparam um valor com uma subconsulta inteira: `> ALL` significa maior que cada valor, `> ANY` maior que pelo menos um. `= ANY` é o mesmo que IN.

WITH spend AS (
  SELECT o.customer_id, SUM(oi.quantity * p.unit_price) AS total
  FROM orders AS o
  JOIN order_items AS oi ON oi.order_id = o.order_id
  JOIN products AS p ON p.product_id = oi.product_id
  GROUP BY o.customer_id
)
SELECT customer_id, total FROM spend WHERE total > 30 ORDER BY total DESC;

Resultado: Cliente 1 (Lopez) com 37.10 e cliente 3 (Dubois) com 36.00.

Funções de janela

OVER adiciona um cálculo entre linhas sem recolhê-las: classificações, totais acumulados, e LAG/LEAD para a linha anterior e a seguinte.

SELECT order_id, order_date,
       RANK() OVER (ORDER BY order_date) AS day_rank,
       LAG(order_date) OVER (ORDER BY order_id) AS prev_date
FROM orders
ORDER BY order_id;

Resultado: Cada pedido com sua classificação por data e a data do pedido anterior.

Alterar dados

INSERT adiciona linhas, UPDATE altera e DELETE remove. Sempre inclua WHERE em UPDATE e DELETE, e execute primeiro como SELECT para ver o que será afetado. Envolva alterações arriscadas em BEGIN e ROLLBACK.

`INSERT INTO t SELECT ...` copia linhas para uma tabela que já existe. `CREATE TABLE t AS SELECT ...` cria uma tabela nova a partir de uma consulta. Chaves inteiras podem se preencher com `GENERATED ALWAYS AS IDENTITY` (MySQL: AUTO_INCREMENT; SQL Server: IDENTITY).

UPDATE products
SET unit_price = unit_price + 0.10
WHERE category = 'drinks'
RETURNING name, unit_price;

Resultado: As duas bebidas com seus novos preços.

Perguntas comuns

Em que ordem o SQL executa uma consulta?
FROM e JOIN, depois WHERE, GROUP BY, HAVING, SELECT, ORDER BY e por fim LIMIT. Por isso um WHERE não pode usar um apelido de coluna do SELECT, mas o ORDER BY pode.
O SQL diferencia maiúsculas de minúsculas?
Palavras-chave e nomes de tabelas ou colunas não (o PostgreSQL converte nomes sem aspas para minúsculas). Valores de texto sim: 'Paris' e 'paris' são diferentes, a não ser que você use ILIKE ou LOWER().
Isso funciona no MySQL, no SQL Server ou no SQLite?
O núcleo (SELECT, WHERE, GROUP BY, JOIN, CASE) funciona. As diferenças estão em LIMIT (TOP no SQL Server), concatenação de texto, funções de data e RETURNING. Consulte a documentação do seu banco para esses pontos.
Como escrevo um comentário em SQL?
Uma linha começa com -- e vai até o fim dessa linha. Um comentário de bloco começa com /* e termina com */. O banco ignora os dois. O Microsoft Access não aceita comentários.

Pratique