Provavelmente você já trombou com expressões condicionais em linguagens de programação: if-else, switch-case e essas paradas. No SQL tem sua própria ferramenta pra lidar com condições: é a expressão CASE. Ela deixa você tomar decisões direto na query: se a condição bate, faz uma coisa, se não bate — faz outra.
A estrutura CASE é especialmente útil quando você precisa lidar com dados que podem ter valores NULL. O sintaxe é simples, tipo cola de prova, olha só:
CASE
WHEN condição1 THEN resultado1
WHEN condição2 THEN resultado2
...
ELSE resultado_padrao
END
Parece lógico, né? "Se for assim, faz isso, senão faz aquilo". Fácil de lembrar: "WHEN — é o se, THEN — é o que fazer, ELSE — é o que fazer se nada encaixar".
Exemplo: classificação de produtos
Imagina que a gente tem uma tabela products, com uma coluna price, e queremos separar os produtos em grupos de acordo com o preço.
| id | name | price |
|---|---|---|
| 1 | Magic Wand | 120 |
| 2 | Potion Set | 45 |
| 3 | Crystal Ball | 75 |
| 4 | Enchanted Map | NULL |
| 5 | Broomstick | 99 |
| 6 | Spell Book | 180 |
SELECT
name AS product_name,
price,
CASE
WHEN price IS NULL THEN 'Desconhecido'
WHEN price < 50 THEN 'Econômico'
WHEN price BETWEEN 50 AND 100 THEN 'Padrão'
ELSE 'Premium'
END AS price_category
FROM products;
O que tá rolando aqui?
- Se o preço
pricedo produto não tá informadoNULL, a gente mostra a categoria como'Desconhecido'. - Se o preço for menor que 50, o produto é considerado econômico
'Econômico'. - Se o preço tá entre 50 e 100, ele cai na categoria
'Padrão'. - O resto — é produto premium
'Premium'.
Olha o resultado:
| product_name | price | price_category |
|---|---|---|
| Magic Wand | 120 | Premium |
| Potion Set | 45 | Econômico |
| Crystal Ball | 75 | Padrão |
| Enchanted Map | NULL | Desconhecido |
| Broomstick | 99 | Padrão |
| Spell Book | 180 | Premium |
O SQL, tipo um mago, lê as linhas da tabela products, aplica em cada uma e classifica de boa.
Trabalhando com NULL no CASE WHEN
Direto rola de ter valores faltando nos dados (salve, NULL), e aí tem que substituir por alguma coisa. Por exemplo, temos uma tabela users com a coluna email, e pros usuários sem email queremos mostrar 'Não informado'.
| user_id | name | |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | NULL |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | NULL |
| 5 | John Smith | john@wizard.org |
SELECT
user_id,
name,
CASE
WHEN email IS NULL THEN 'Não informado'
ELSE email
END AS email_address
FROM users;
| user_id | name | email_address |
|---|---|---|
| 1 | Alex Lin | alex@example.com |
| 2 | Maria Chi | Não informado |
| 3 | Anna Song | anna@magic.com |
| 4 | Otto Art | Não informado |
| 5 | John Smith | john@wizard.org |
O SQL aqui age tipo um xamã, dando vida pras linhas meio vazias. Se não tem email, ele troca por 'Não informado'. Se tem — só mostra mesmo.
Expressões condicionais com números
Às vezes não é só trocar valores, mas criar uma lógica nova. Por exemplo, imagina uma tabela students com as colunas score (nota) e name.
| name | score |
|---|---|
| Alex Lin | 95 |
| Maria Chi | 82 |
| Anna Song | 48 |
| Otto Art | NULL |
| John Smith | 67 |
| Zoe Black | 30 |
A gente quer avaliar os estudantes como "Excelente", "Passou" e "Reprovado", dependendo da nota deles.
SELECT
name AS student_name,
score,
CASE
WHEN score IS NULL THEN 'Sem Nota'
WHEN score >= 90 THEN 'Excelente'
WHEN score >= 50 THEN 'Passou'
ELSE 'Reprovado'
END AS performance_category
FROM students;
| student_name | score | performance_category |
|---|---|---|
| Alex Lin | 95 | Excelente |
| Maria Chi | 82 | Passou |
| Anna Song | 48 | Reprovado |
| Otto Art | NULL | Sem Nota |
| John Smith | 67 | Passou |
| Zoe Black | 30 | Reprovado |
O SQL distribui os estudantes, tipo um examinador rígido: 90 pontos ou mais — só "Excelente", de 50 pra cima — "Passou". Se não bate a nota... já era.
Agrupamento e tratamento de NULL
Trabalhar com grupos de dados é outro lugar onde CASE WHEN brilha. Imagina que temos uma tabela orders, e queremos contar o total de pedidos por status, incluindo os que têm status NULL.
| order_id | status |
|---|---|
| 1 | Completed |
| 2 | Pending |
| 3 | NULL |
| 4 | Shipped |
| 5 | Completed |
| 6 | NULL |
| 7 | Pending |
| 8 | Completed |
| 9 | Shipped |
| 10 | NULL |
SELECT
CASE
WHEN status IS NULL THEN 'Sem Status'
ELSE status
END AS order_status,
COUNT(*)
FROM orders
GROUP BY
CASE
WHEN status IS NULL THEN 'Sem Status'
ELSE status
END;
Essa query trata direitinho os status NULL e coloca 'Sem Status' no lugar, além de contar o total de pedidos em cada grupo. Olha o resultado:
| order_status | count |
|---|---|
| Completed | 3 |
| Pending | 2 |
| Shipped | 2 |
| Sem Status | 3 |
Casos práticos: "Truques" com CASE WHEN
Exemplo 1: Ordenação considerando NULL
Às vezes você quer mostrar valores NULL primeiro ou por último numa lista ordenada. Isso é comum, tipo em listas de tarefas, onde as tarefas prioritárias aparecem no topo e as sem prioridade (NULL) ficam no fim.
| task_id | task_name | priority |
|---|---|---|
| 1 | Fix bugs | 1 |
| 2 | Update documentation | 3 |
| 3 | Plan sprint | NULL |
| 4 | Code review | 2 |
| 5 | Organize meeting | NULL |
| 6 | Deploy release | 1 |
SELECT
task_name,
priority,
CASE
WHEN priority IS NULL THEN 1
ELSE 0
END AS priority_sort
FROM tasks
ORDER BY priority_sort ASC, priority ASC;
Aqui a gente criou uma coluna "virtual" priority_sort, que joga os NULL lá pra baixo, e o resto ordena do menor pro maior.
| task_name | priority | priority_sort |
|---|---|---|
| Deploy release | 1 | 0 |
| Fix bugs | 1 | 0 |
| Code review | 2 | 0 |
| Update documentation | 3 | 0 |
| Plan sprint | NULL | 1 |
| Organize meeting | NULL | 1 |
Exemplo 2: Cálculos considerando NULL
Agora imagina que a gente tá calculando o valor final do pedido na tabela orders, onde a coluna discount pode ser NULL se não tiver desconto.
| order_id | total_price | discount |
|---|---|---|
| 101 | 100 | 10 |
| 102 | 200 | NULL |
| 103 | 150 | 15 |
| 104 | 120 | NULL |
| 105 | 80 | 5 |
A gente precisa trocar NULL por 0, pra não quebrar a conta.
SELECT
order_id,
total_price,
discount,
total_price -
CASE
WHEN discount IS NULL THEN 0
ELSE discount
END AS final_price
FROM orders;
| order_id | total_price | discount | final_price |
|---|---|---|---|
| 101 | 100 | 10 | 90 |
| 102 | 200 | NULL | 200 |
| 103 | 150 | 15 | 135 |
| 104 | 120 | NULL | 120 |
| 105 | 80 | 5 | 75 |
Esse truque mágico com CASE garante que NULL não vai ferrar seus cálculos.
Pra orderid = 101: discount = 10. finalprice = 100 - 10 = 90. Pra orderid = 102: discount = NULL. CASE retorna 0. finalprice = 200 - 0 = 200. Pra orderid = 103: discount = 15. finalprice = 150 - 15 = 135. Pra orderid = 104: discount = NULL. CASE retorna 0. finalprice = 120 - 0 = 120. Pra orderid = 105: discount = 5. finalprice = 80 - 5 = 75.
Exemplo 3: Mostrando status customizado do usuário
No dia a dia rola de mostrar o status do usuário (tipo "Ativo" ou "Esperando") ou avisar que não tem dado. Por exemplo, na tabela users tem a coluna last_login, que guarda a data do último login.
| user_id | name | last_login |
|---|---|---|
| 1 | Alex Lin | 2024-12-10 |
| 2 | Maria Chi | 2025-04-20 |
| 3 | Anna Song | NULL |
| 4 | Otto Art | 2025-05-01 |
| 5 | Liam Park | 2025-05-25 |
SELECT
user_id,
name,
CASE
WHEN last_login IS NULL THEN 'Nunca entrou'
WHEN last_login < CURRENT_DATE - INTERVAL '30 days' THEN 'Inativo'
ELSE 'Ativo'
END AS user_status
FROM users;
Com essa query o sistema do admin ganha vida: usuários sem login são chamados de "Nunca entrou", quem não entra faz tempo é "Inativo". O resto tá ativo!
| user_id | name | user_status |
|---|---|---|
| 1 | Alex Lin | Inativo |
| 2 | Maria Chi | Inativo |
| 3 | Anna Song | Nunca entrou |
| 4 | Otto Art | Inativo |
| 5 | Liam Park | Ativo |
Erros comuns e como evitar
Esquecer o ELSE: Se você não colocar ELSE, o SQL só vai retornar NULL se nenhuma condição bater. Nem sempre é o que você quer. Então é melhor sempre colocar ELSE, mesmo se acha que cobriu tudo.
CASE
WHEN condição THEN resultado
-- ELSE 'Valor padrão' -- não esquece!
END
Condições complicadas sem parênteses: Se tiver várias condições com AND, OR ou NOT, sempre usa parênteses. Sem eles, sua query pode "pensar" errado.
CASE
WHEN (column1 IS NOT NULL AND column2 > 5) THEN 'Válido'
ELSE 'Inválido'
END
Trabalhando com NULL: Lembra que NULL nunca é igual (=) a nada. Por exemplo:
CASE
WHEN column = NULL THEN 'Nope!' -- Errado!
WHEN column IS NULL THEN 'Correto!' -- Assim que faz.
END
GO TO FULL VERSION