SQL: Sub Queries

SQL: Sub Queries

Introdução Uma subquery é uma consulta SQL aninhada dentro de outra. Assim como uma função pode chamar outra função, um SELECT pode conter outro SELECT — e o resultado do interno é usado pelo externo para filtrar, calcular ou compor o resultado final. Subqueries aparecem em três lugares possíveis: no SELECT, no FROM, ou no WHERE/HAVING. O comportamento muda dependendo do tipo de resultado que a subquery retorna — e é aí que a classificação em Scalar, Column, Row e Table faz sentido. Para os exemplos, usaremos: clientes: id, nome, cidade pedidos: id, cliente_id, valor, criado_em produtos: id, nome, preco, categoria_id categorias: id, nome Enter fullscreen mode Exit fullscreen mode Tipos por Resultado Retorna exatamente um valor: uma linha, uma coluna. Pode ser usada em qualquer lugar onde um valor único seria esperado — no SELECT, no WHERE, ou no HAVING. Scalar Subquery -- Qual cliente fez o pedido de maior valor? SELECT nome FROM clientes WHERE id = ( SELECT cliente_id FROM pedidos ORDER BY valor DESC LIMIT 1 ); Enter fullscreen mode Exit fullscreen mode A subquery interna retorna um único cliente_id — o do pedido mais caro. A externa usa esse valor para buscar o nome. Scalar subqueries também funcionam diretamente no SELECT, como uma coluna calculada: SELECT nome, (SELECT COUNT(*)FROM pedidosWHERE cliente_id= c.id)AS total_pedidos FROM clientes c; Enter fullscreen mode Exit fullscreen mode Se uma scalar subquery retornar mais de uma linha, o banco lança um erro. Por isso, é comum garantir isso com LIMIT 1 ou usando funções de agregação. Column Subquery Retorna múltiplas linhas de uma única coluna — essencialmente uma lista de valores. É usada principalmente com os operadores IN, NOT IN, ANY e ALL. -- Clientes que fizeram pelo menos um pedido acima de 1000 SELECT nome FROM clientes WHERE id IN ( SELECT DISTINCT cliente_id FROM pedidos WHERE valor > 1000 ); Enter fullscreen mode Exit fullscreen mode A subquery retorna uma coluna com os IDs dos clientes elegíveis. O IN da query externa verifica se cada id está nessa lista. O inverso com NOT IN é igualmente útil — mas exige cuidado: se a subquery retornar algum NULL, o NOT IN se comporta de forma contra-intuitiva e pode não retornar nenhuma linha. Nesse caso, prefira NOT EXISTS. ANY e ALL são alternativas mais expressivas em certos cenários: -- Produtos mais caros que QUALQUER produto da categoria 2 SELECT nome, preco FROM produtos WHERE preco > ANY ( SELECT preco FROM produtos WHERE categoria_id= 2 ); -- Produtos mais caros que TODOS os produtos da categoria 2 SELECT nome, preco FROM produtos WHERE preco > ALL ( SELECT preco FROM produtos WHERE categoria_id= 2 ); Enter fullscreen mode Exit fullscreen mode Row Subquery Retorna uma linha com múltiplas colunas. Menos comum, mas útil para comparar um conjunto de valores de uma vez só. -- Encontra o produto que tem exatamente esse nome e preço SELECT id FROM produtos WHERE (nome, preco)= ( SELECT nome, preco FROM produtos WHERE id = 10 ); Enter fullscreen mode Exit fullscreen mode A comparação de linha inteira evita escrever múltiplas condições AND. O suporte varia entre bancos — PostgreSQL e MySQL suportam bem; SQL Server tem suporte mais limitado. Table Subquery Retorna múltiplas linhas e colunas — um conjunto de dados completo que é tratado como se fosse uma tabela temporária. Também chamada de derived table ou inline view. Aparece no FROM e precisa de um alias. -- Receita por cliente, mas filtrando apenas quem passou de 500 SELECT cliente_nome, receita_total FROM ( SELECT c.nomeAS cliente_nome, SUM(p.valor) AS receita_total FROM clientes c JOIN pedidos p ON p.cliente_id= c.id GROUP BY c.nome ) AS resumo WHERE receita_total> 500; Enter fullscreen mode Exit fullscreen mode A subquery interna calcula a receita por cliente. A query externa trata esse resultado como uma tabela e aplica o filtro. Isso seria impossível diretamente porque WHERE é avaliado antes do GROUP BY — a table subquery contorna isso. Tipos por Comportamento Nested Subquery (Independente) Uma subquery é nested quando pode ser executada de forma completamente independente da query externa. Ela não referencia nenhuma coluna da tabela externa — é avaliada uma única vez, e o resultado é passado para a query externa usar. SELECT nome FROM clientes WHERE cidade= ( SELECT cidade FROM clientes WHERE id= 1 ); Enter fullscreen mode Exit fullscreen mode A subquery interna busca a cidade do cliente 1. Isso não depende de nenhum dado da query externa — roda uma vez, retorna 'São Paulo', e a query externa usa esse valor para filtrar todos os clientes. Por serem independentes, nested subqueries são geralmente eficientes — o banco as executa uma única vez e reutiliza o resultado. Correlated Subquery (Dependente) Uma subquery é correlacionada quando referencia colunas da query externa. Isso significa que ela é reavaliada para cada linha que a query externa processa — o que pode ser custoso em tabelas grandes, mas permite expressar consultas que seriam impossíveis de outra forma. -- Clientes cujo total de pedidos está acima da média geral SELECT nome FROM clientes c WHERE ( SELECT SUM(valor) FROM pedidos p WHERE p.cliente_id= c.id-- referência à query externa )> ( SELECT AVG(valor) FROM pedidos ); Enter fullscreen mode Exit fullscreen mode A subquery WHERE p.cliente_id = c.id referencia c.id, que vem da query externa. Para cada cliente que a query externa examina, a subquery roda novamente com o id daquele cliente específico. O uso mais clássico de correlated subquery é com EXISTS e NOT EXISTS: -- Clientes que fizeram pelo menos um pedido SELECT nome FROM clientes c WHERE EXISTS ( SELECT 1 FROM pedidos p WHERE p.cliente_id= c.id ); -- Clientes que nunca fizeram nenhum pedido SELECT nome FROM clientes c WHERE NOT EXISTS ( SELECT 1 FROM pedidos p WHERE p.cliente_id = c.id ); Enter fullscreen mode Exit fullscreen mode EXISTS retorna verdadeiro assim que encontra a primeira correspondência — não precisa contar nem trazer dados, apenas confirmar que existe ao menos uma linha. Por isso é mais eficiente que IN em muitos casos, especialmente quando a subquery pode retornar NULL. Subquery vs JOIN Muitas subqueries podem ser reescritas como JOINs, e vice-versa. A escolha entre os dois depende de legibilidade e, às vezes, de performance — embora os otimizadores modernos frequentemente gerem planos de execução idênticos para ambos. -- Com subquery SELECT nome FROM clientes WHERE id IN (SELECT cliente_id FROM pedidos WHERE valor > 1000); -- Com JOIN SELECT DISTINCT c.nome FROM clientes c INNER JOIN pedidos p ON p.cliente_id = c.id WHERE p.valor > 1000; Enter fullscreen mode Exit fullscreen mode O resultado é o mesmo. A subquery é mais próxima da forma como pensamos a pergunta em linguagem natural; o JOIN explicita a relação entre as tabelas. Use o que tornar a intenção mais clara — e prefira EXISTS a IN quando a subquery puder conter NULL ou retornar muitas linhas.

Original Source

Read the full article at Dev →

KhanList aggregates and links to publicly available news content. We do not host full articles from third-party sources. Always verify important information with original sources.