Aprender / Cheat sheet
Cheat sheet de SQL para testers
O SQL que testers usam para verificar os dados por trás de uma UI ou API: encontrar o registro, conferir se ele mudou e caçar duplicados, órfãos e NULLs que não deveriam estar lá. A sintaxe é SQL padrão, que roda em PostgreSQL, MySQL 8 e SQLite. Quando um banco de dados difere, a nota avisa.
Conferido com SQL padrão; conferido com PostgreSQL 16, MySQL 8 e SQLite 3
Encontrar linhas
| Tarefa | Código |
|---|---|
| Colunas de uma tabela | SELECT id, email FROM users; |
| Filtrar | SELECT * FROM orders WHERE status = 'paid' AND total > 100; |
| Um entre vários valores | WHERE status IN ('paid', 'shipped') |
| Intervalo (inclusivo nas duas pontas) | WHERE created_at BETWEEN '2026-01-01' AND '2026-01-31' |
| Padrão | WHERE email LIKE '%@example.com' |
| Valor ausente | WHERE phone IS NULL |
| Ordenar, mais recentes primeiro | ORDER BY created_at DESC |
| Primeiras 10 linhas | LIMIT 10 |
| Valores distintos | SELECT DISTINCT status FROM orders; |
O SQL Server usa SELECT TOP 10 em vez de LIMIT. BETWEEN em timestamps inclui só a meia-noite da data final; para dias inteiros, use < dia seguinte.
Agregar
| Tarefa | Código |
|---|---|
| Contar linhas | SELECT COUNT(*) FROM orders; |
| Contar valores não NULL | SELECT COUNT(shipped_at) FROM orders; |
| Contar distintos | SELECT COUNT(DISTINCT user_id) FROM orders; |
| Totais por grupo | SELECT status, COUNT(*), SUM(total) FROM orders GROUP BY status; |
| Filtrar grupos | SELECT user_id, COUNT(*) FROM orders GROUP BY user_id HAVING COUNT(*) > 5; |
| Mínimo, máximo, média | SELECT MIN(total), MAX(total), AVG(total) FROM orders; |
WHERE filtra as linhas antes do agrupamento; HAVING filtra os grupos depois.
Join
| Tarefa | Código |
|---|---|
| Só as linhas que casam | SELECT o.id, u.email FROM orders o JOIN users u ON u.id = o.user_id; |
| Manter todas as linhas da esquerda | SELECT u.email, o.id FROM users u LEFT JOIN orders o ON o.user_id = u.id; |
| Linhas sem correspondência (anti-join) | SELECT u.* FROM users u LEFT JOIN orders o ON o.user_id = u.id WHERE o.id IS NULL; |
| O mesmo, com NOT EXISTS | SELECT * FROM users u WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id); |
Um join em uma chave um-para-muitos repete o lado "um". Se o SUM() parecer grande demais depois de um join, o join multiplicou as linhas.
Checagens de dados que testers fazem
| Tarefa | Código |
|---|---|
| Duplicados | SELECT email, COUNT(*) FROM users GROUP BY email HAVING COUNT(*) > 1; |
| Órfãos (filho sem pai) | SELECT o.* FROM orders o LEFT JOIN users u ON u.id = o.user_id WHERE u.id IS NULL; |
| Campo obrigatório vazio | SELECT * FROM users WHERE email IS NULL OR TRIM(email) = ''; |
| Valores fora da faixa | SELECT * FROM order_items WHERE quantity <= 0 OR unit_price < 0; |
| Total do cabeçalho ≠ itens | SELECT o.id FROM orders o JOIN order_items i ON i.order_id = o.id GROUP BY o.id, o.total HAVING o.total <> SUM(i.quantity * i.unit_price); |
| Linha existe depois de uma ação na UI | SELECT * FROM orders WHERE user_id = 42 ORDER BY created_at DESC LIMIT 1; |
Armadilhas do NULL
| Armadilha | O que acontece |
|---|---|
| WHERE col = NULL | Nunca é verdadeiro. Use IS NULL / IS NOT NULL. |
| WHERE status <> 'paid' | Ignora as linhas em que status é NULL. Acrescente OR status IS NULL se quiser incluí-las. |
| NOT IN (subquery que retorna um NULL) | Não retorna nenhuma linha. Use NOT EXISTS. |
| COUNT(col) vs COUNT(*) | COUNT(col) ignora NULLs, COUNT(*) conta todas as linhas. |
| Aritmética com NULL | price + NULL é NULL. Use COALESCE(col, 0) se 0 for o padrão correto. |
Window functions
| Tarefa | Código |
|---|---|
| Numerar linhas por grupo | ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) |
| Linha mais recente por grupo | SELECT * FROM (SELECT o.*, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn FROM orders o) t WHERE rn = 1; |
| Ranking com empates | RANK() OVER (ORDER BY total DESC) / DENSE_RANK() … |
| Valor da linha anterior | LAG(status) OVER (PARTITION BY test_name ORDER BY run_at) |
| Total acumulado | SUM(total) OVER (ORDER BY created_at) |
Suportadas em PostgreSQL, MySQL 8+, SQLite 3.25+ e SQL Server. Uma window function não pode ser usada no WHERE; filtre em uma query externa.
Alterar dados com segurança
| Tarefa | Código |
|---|---|
| Inserir | INSERT INTO users (email, name) VALUES ('qa+1@example.com', 'QA One'); |
| Atualizar (sempre com WHERE) | UPDATE orders SET status = 'cancelled' WHERE id = 1043; |
| Excluir (sempre com WHERE) | DELETE FROM sessions WHERE user_id = 42; |
| Testar e depois desfazer | BEGIN; UPDATE orders SET status = 'cancelled' WHERE id = 1043; SELECT status FROM orders WHERE id = 1043; ROLLBACK; |
Rode primeiro o mesmo WHERE como SELECT e confira a quantidade de linhas antes de fazer UPDATE ou DELETE.