Subconsultas, ou consultas aninhadas, permitem resolver problemas que exigem múltiplas consultas em uma única instrução.
SELECT lista_colunas
FROM tabela
WHERE expressao operador
(SELECT lista_colunas
FROM tabela);
A subconsulta (consulta interna) é executada uma vez antes da consulta principal (externa), e seu resultado é utilizado pela consulta principal.
SELECT nome
FROM empregados
WHERE salario > (
SELECT salario FROM empregados WHERE nome = 'Carlos'
);
| NOME |
|---|
| Ana |
| Beatriz |
Isso equivale a duas consultas separadas: primeiro obter o salário de Carlos, e depois selecionar empregados com salário superior.
Diretrizes Importantes
- Subconsultas devem ser envolvidas por parênteses e posicionadas à direita da condição de comparação.
- Evite usar ORDER BY em subconsultas, exceto em análise Top-N.
- Operadores de linha única correspondem a subconsultas de linha única; operadores de múltiplas linhas, a subconsultas de múltiplas linhas.
Classificação das Subconsultas
Subconsultas são categorizadas em linha única e múltiplas linhas.
Subconsultas de Linha Única
Retornam uma única linha de dados e requerem operadores de comparação de linha única.
| Operador | Significado |
|---|---|
| = | Igual a |
| > | Maior que |
| >= | Maior ou igual a |
| < | Menor que |
| <= | Menor ou igual a |
| <> | Diferente de |
SELECT nome
FROM empregados
WHERE cargo = (
SELECT cargo
FROM empregados
WHERE nome = 'Laura'
)
AND salario > (
SELECT salario
FROM empregados
WHERE nome = 'Pedro'
);
| NOME |
|---|
| João |
| Laura |
Este exemplo seleciona empregados com o mesmo cargo que Laura e salário maior que o de Pedro.
Uso de Funções de Grupo em Subconsultas
SELECT nome
FROM empregados
WHERE salario > (
SELECT AVG(salario)
FROM empregados
);
| NOME |
|---|
| Ana |
| Beatriz |
Retorna empregados cujo salário é acima da média geral.
Subconsultas na Cláusula HAVING
SELECT cargo, AVG(salario)
FROM empregados
GROUP BY cargo
HAVING AVG(salario) > (
SELECT AVG(salario)
FROM empregados
);
| CARGO | AVG(SALARIO) |
|---|---|
| Gerente | 12000 |
Exibe cargos com salário médio superior à média global dos empregados.
Uso Ilegal de Subconsultas
Aplicar operadores de linha única a resultados de múltiplas linhas causa erros.
SELECT nome
FROM empregados
WHERE salario > (
SELECT AVG(salario)
FROM empregados
GROUP BY cargo
);
Isso gera um erro, pois a subconsulta retorna múltiplas linhas.
Subconsultas com Valores Nulos
SELECT nome
FROM empregados
WHERE salario > (
SELECT salario
FROM empregados
WHERE nome = 'Inexistente'
);
O resultado é vazio, pois a subconsulta não encontra crorespondência.
Subconsultas de Múltiplas Linhas
Retornam múltiplas linhas e utilizam operadores de múltiplas linhas.
| Operador | Significado |
|---|---|
| IN | Igual a qualquer valor da lista |
| ANY | Compara com qualquer valor retornado |
| ALL | Compara com todos os valores retornados |
Uso do Operador ANY
SELECT nome, cargo, salario
FROM empregados
WHERE salario < ANY (
SELECT salario
FROM empregados
WHERE cargo = 'TI'
)
AND cargo <> 'TI';
| NOME | CARGO | SALARIO |
|---|---|---|
| Roberto | Vendas | 4500 |
| Maria | Financeiro | 6000 |
Retorna empregados fora de TI com salário inferior a pelo menos um empregado de TI.
Uso do Operador ALL
SELECT nome, cargo, salario
FROM empregados
WHERE salario < ALL (
SELECT salario FROM empregados WHERE cargo = 'TI'
)
AND cargo <> 'TI';
| NOME | CARGO | SALARIO |
|---|---|---|
| Roberto | Vendas | 4500 |
Seleciona empregados fora de TI com salário menor que todos os de TI.
Uso do Operador IN
SELECT nome, cargo, salario
FROM empregados
WHERE id_empregado IN (
SELECT id_gerente
FROM empregados
);
| NOME | CARGO | SALARIO |
|---|---|---|
| Ana | Diretora | 15000 |
| Carlos | Coordenador | 8000 |
Identifica empregados que são gerentes.
Questões com Valores Nulos em Subconsultas
SELECT nome, cargo, salario
FROM empregados
WHERE id_empregado NOT IN (
SELECT id_gerente
FROM empregados
);
Isso retorna vazio se houver valores nulos na subconsulta. Corrija filtrando nulos:
SELECT nome, cargo, salario
FROM empregados
WHERE id_empregado NOT IN (
SELECT id_gerente
FROM empregados
WHERE id_gerente IS NOT NULL
);
| NOME | CARGO | SALARIO |
|---|---|---|
| Lucia | Analista | 7000 |
| Felipe | Assistente | 3500 |
Obtém empregados que não são gerentes.