Como Escrever Consultas SQL Usando Múltiplas Subconsultas

As subconsultas no SQL são uma técnica poderosa para executar uma consulta dentro de outra. Combinando várias subconsultas de forma eficaz, é possível realizar extrações e análises de dados complexas. Este artigo aborda desde os fundamentos das subconsultas, passando por subconsultas correlacionadas e a combinação de múltiplas subconsultas, até exemplos práticos de como escrever consultas SQL utilizando subconsultas. Por fim, também oferecemos dicas para otimizar o desempenho. Se você deseja aprimorar suas habilidades em SQL, não deixe de ler este artigo.

Índice

Fundamentos das Subconsultas

Uma subconsulta é uma consulta SQL inserida dentro de outra. As subconsultas são usadas para fornecer dados à consulta principal, e seus resultados são utilizados na consulta principal. Abaixo está um exemplo básico de subconsulta.

Estrutura Básica

Uma subconsulta básica é usada dentro de uma cláusula SELECT e é delimitada por parênteses. Por exemplo, uma subconsulta para encontrar o funcionário com o salário mais alto seria assim:

SELECT employee_name
FROM employees
WHERE salary = (SELECT MAX(salary) FROM employees);

Tipos de Subconsultas

Existem diferentes tipos de subconsultas:

  • Subconsulta de Linha Única: Retorna um único valor.
  • Subconsulta de Múltiplas Linhas: Retorna vários valores.
  • Subconsulta Correlacionada: Depende de cada linha da consulta principal.

Entender os fundamentos das subconsultas é o primeiro passo para criar consultas mais complexas. A seguir, vamos nos aprofundar nas subconsultas correlacionadas.

Subconsultas Correlacionadas

Uma subconsulta correlacionada é executada para cada linha da consulta principal e faz referência às colunas da consulta principal, permitindo extrações de dados mais dinâmicas e flexíveis.

Conceito de Subconsulta Correlacionada

Subconsultas correlacionadas dependem de cada linha da consulta principal, criando uma relação mútua entre ambas. Isso permite comparações e agregações de dados mais complexas.

Estrutura Básica da Subconsulta Correlacionada

A estrutura básica de uma subconsulta correlacionada é a seguinte. No exemplo abaixo, extraímos os funcionários cujo salário é superior à média salarial do departamento.

SELECT employee_name, salary
FROM employees e1
WHERE salary > (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e1.department_id = e2.department_id
);

Nesta consulta, a consulta externa (principal) e a subconsulta interna estão relacionadas pela coluna department_id, verificando se o salário de cada funcionário é superior à média salarial do departamento.

Vantagens das Subconsultas Correlacionadas

As subconsultas correlacionadas oferecem as seguintes vantagens:

  • Flexibilidade: Permitem a definição de condições complexas, possibilitando diferentes cálculos e comparações para cada linha da consulta principal.
  • Extração Dinâmica de Dados: Gera resultados dinamicamente com base nos dados da consulta principal.

A seguir, vamos explorar como combinar várias subconsultas para realizar extrações de dados mais complexas.

Como Combinar Múltiplas Subconsultas

Ao combinar várias subconsultas, você pode realizar extrações e análises de dados extremamente complexas e detalhadas. A seguir, explicamos como usar várias subconsultas de forma eficaz.

Subconsultas Aninhadas

Ao aninhar subconsultas dentro de outras, você pode realizar extrações de dados hierárquicas. No exemplo abaixo, obtemos o nome do departamento ao qual pertence o funcionário com o maior salário.

SELECT department_name
FROM departments
WHERE department_id = (
    SELECT department_id
    FROM employees
    WHERE salary = (
        SELECT MAX(salary)
        FROM employees
    )
);

Esta consulta encontra o funcionário com o salário mais alto e, em seguida, obtém o nome do departamento ao qual ele pertence.

Combinação com Subconsultas Correlacionadas

Também é possível combinar subconsultas correlacionadas com outras subconsultas. No exemplo abaixo, verificamos se o salário de cada funcionário é superior à média salarial do departamento e obtemos o nome do departamento.

SELECT employee_name, department_name
FROM employees e1
JOIN departments d ON e1.department_id = d.department_id
WHERE salary > (
    SELECT AVG(salary)
    FROM employees e2
    WHERE e1.department_id = e2.department_id
);

Essa consulta usa uma subconsulta correlacionada para verificar se o salário de cada funcionário é superior à média salarial do departamento e, com base nisso, obtém o nome do departamento.

Subconsultas Usando Múltiplas Cláusulas WITH

Ao usar várias subconsultas, a cláusula WITH (Expressão de Tabela Comum, CTE) pode tornar a consulta mais legível e fácil de manter. Abaixo está um exemplo de uso de CTE.

WITH MaxSalary AS (
    SELECT department_id, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department_id
),
HighEarners AS (
    SELECT e.employee_name, d.department_name, e.salary
    FROM employees e
    JOIN departments d ON

 e.department_id = d.department_id
    JOIN MaxSalary m ON e.department_id = m.department_id AND e.salary = m.max_salary
)
SELECT * FROM HighEarners;

Essa consulta primeiro obtém os funcionários com os maiores salários em cada departamento e depois seleciona seus nomes e nomes dos departamentos.

Em seguida, mostramos um exemplo prático de subconsultas aninhadas.

Exemplo Prático 1: Subconsultas Aninhadas

Subconsultas aninhadas são usadas para realizar extrações de dados hierárquicas. Nesta seção, explicamos como usar subconsultas aninhadas com um exemplo prático.

Exemplo: Obtenha o Funcionário com o Maior Salário em um Departamento Específico

Neste exemplo, obtemos o funcionário com o maior salário em um departamento específico (por exemplo, departamento ID 5).

SELECT employee_name, salary
FROM employees
WHERE salary = (
    SELECT MAX(salary)
    FROM employees
    WHERE department_id = 5
);

Esta consulta encontra o funcionário com o maior salário no departamento de ID 5 e, em seguida, retorna o nome e o salário do funcionário.

Exemplo: Obtenha o Funcionário com o Maior Salário em Cada Departamento

Como um exemplo mais complexo, aqui está como obter o funcionário com o maior salário em cada departamento.

SELECT employee_name, department_id, salary
FROM employees e1
WHERE salary = (
    SELECT MAX(salary)
    FROM employees e2
    WHERE e1.department_id = e2.department_id
);

Essa consulta usa uma subconsulta correlacionada para encontrar o funcionário com o maior salário em cada departamento. A subconsulta interna obtém o maior salário com base no department_id passado pela consulta externa, que então seleciona o funcionário correspondente.

Exemplo: Obtenha Detalhes do Funcionário com o Maior Salário em Cada Departamento

Por fim, veja como obter detalhes (nome, salário, nome do departamento) do funcionário com o maior salário em cada departamento.

SELECT e1.employee_name, e1.salary, d.department_name
FROM employees e1
JOIN departments d ON e1.department_id = d.department_id
WHERE e1.salary = (
    SELECT MAX(e2.salary)
    FROM employees e2
    WHERE e2.department_id = e1.department_id
);

Esta consulta primeiro encontra o funcionário com o maior salário em cada departamento e, em seguida, obtém detalhes sobre o funcionário juntamente com o nome do departamento.

A seguir, vamos explicar como organizar subconsultas complexas usando a cláusula WITH.

Exemplo Prático 2: Subconsultas Usando a Cláusula WITH

O uso da cláusula WITH (Expressão de Tabela Comum, CTE) permite organizar consultas complexas de forma clara e fácil de manter. Nesta seção, mostramos como simplificar subconsultas usando a cláusula WITH com exemplos práticos.

Exemplo: Obtenha o Funcionário com o Maior Salário em Cada Departamento

Primeiro, veja como obter o funcionário com o maior salário em cada departamento usando a cláusula WITH.

WITH MaxSalaries AS (
    SELECT department_id, MAX(salary) AS max_salary
    FROM employees
    GROUP BY department_id
)
SELECT e.employee_name, e.salary, d.department_name
FROM employees e
JOIN MaxSalaries m ON e.department_id = m.department_id AND e.salary = m.max_salary
JOIN departments d ON e.department_id = d.department_id;

Essa consulta usa uma CTE chamada MaxSalaries para calcular o maior salário em cada departamento, que é então usado na consulta principal. Isso torna a consulta como um todo mais legível.

Exemplo: Obtenha o Vendedor com o Maior Volume de Vendas

A seguir, mostramos um exemplo de como obter detalhes do vendedor com o maior volume de vendas.

WITH SalesData AS (
    SELECT salesperson_id, SUM(sales_amount) AS total_sales
    FROM sales
    GROUP BY salesperson_id
),
TopSalesperson AS (
    SELECT salesperson_id, MAX(total_sales) AS max_sales
    FROM SalesData
)
SELECT s.salesperson_name, sd.total_sales
FROM SalesData sd
JOIN TopSalesperson ts ON sd.salesperson_id = ts.salesperson_id AND sd.total_sales = ts.max_sales
JOIN salespersons s ON sd.salesperson_id = s.salesperson_id;

Esta consulta usa uma CTE chamada SalesData para calcular o volume total de vendas de cada vendedor e, em seguida, uma CTE chamada TopSalesperson para identificar o vendedor com o maior volume de vendas. Por fim, obtém-se os detalhes desse vendedor.

Exemplo: Obtenha a Média de Vendas de Cada Mês em um Ano Específico

Por fim, mostramos como usar a cláusula WITH para obter a média de vendas de cada mês em um ano específico.

WITH MonthlySales AS (
    SELECT DATE_TRUNC('month', sale_date) AS month, AVG(sales_amount) AS avg_sales
    FROM sales
    WHERE EXTRACT(year FROM sale_date) = 2023
    GROUP BY DATE_TRUNC('month', sale_date)
)
SELECT month, avg_sales
FROM MonthlySales
ORDER BY month;

Essa consulta usa uma CTE chamada MonthlySales para calcular a média de vendas de cada mês em 2023, e o resultado é usado na consulta principal. Isso facilita a obtenção da média de vendas mensal.

Em seguida, vamos explorar dicas e técnicas para otimizar o desempenho de consultas SQL que utilizam subconsultas.

Otimização de Desempenho

Consultas SQL que utilizam subconsultas são poderosas, mas podem apresentar problemas de desempenho. A seguir, apresentamos dicas e técnicas para otimizar o desempenho de consultas SQL que utilizam subconsultas.

Uso de Índices

Criar índices nas colunas usadas pelas subconsultas pode aumentar significativamente a velocidade de execução das consultas. É importante definir índices nas colunas frequentemente usadas nas subconsultas.

CREATE INDEX idx_department_id ON employees(department_id);

Neste exemplo, um índice é criado na coluna department_id para acelerar as pesquisas.

Evitar Subconsultas Desnecessárias

Algumas subconsultas são redundantes e podem ser simplificadas usando JOINs. Eliminar subconsultas desnecessárias pode melhorar o desempenho da consulta.

-- Exemplo usando subconsulta
SELECT e.employee_name, d.department_name
FROM employees e
WHERE e.department_id = (SELECT department_id FROM departments WHERE department_name = 'Sales');

-- Exemplo otimizado usando JOIN
SELECT e.employee_name, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = 'Sales';

Neste exemplo, a subconsulta é substituída por um JOIN, tornando a consulta mais simples e rápida.

Otimização com EXISTS

Ao usar o resultado de uma subconsulta para verificar a existência de linhas, o operador EXISTS pode melhorar o desempenho. EXISTS é eficiente porque interrompe o processamento assim que encontra uma linha correspondente.

-- Exemplo usando subconsulta
SELECT employee_name
FROM employees
WHERE department_id IN (SELECT department_id FROM departments WHERE location = 'New York');

-- Exemplo otimizado usando EXISTS
SELECT employee_name
FROM employees e
WHERE EXISTS (
    SELECT 1
    FROM departments d
    WHERE e.department_id = d.department_id AND d.location = 'New York'
);

Neste exemplo, o operador IN é substituído por EXISTS, aumentando a eficiência da execução da consulta.

Uso de Views

Se você executa frequentemente uma consulta complexa que inclui subconsultas, transformar essa subconsulta em uma view pode melhorar o desempenho. As views armazenam os resultados de consultas como tabelas virtuais, facilitando sua reutilização.

-- Criação de uma view
CREATE VIEW HighSalaryEmployees AS
SELECT employee_name, salary, department_id
FROM employees
WHERE salary > 100000;

-- Consulta usando a view
SELECT e.employee_name, d.department_name
FROM HighSalaryEmployees e
JOIN departments d ON e.department_id = d.department_id;

Neste exemplo, uma view chamada HighSalaryEmployees é criada e, em seguida, usada em uma consulta para melhorar a legibilidade e o desempenho.

Atualização de Estatísticas

Atualizar regularmente as estatísticas do banco de dados permite que o otimizador de consultas gere planos de execução mais eficientes. As estatísticas incluem informações sobre índices e cardinalidade de tabelas.

-- Atualização de estatísticas (exemplo: PostgreSQL)
ANALYZE employees;

Neste exemplo, as estatísticas da tabela employees são atualizadas para otimizar o desempenho da consulta.

Conclusão

Este artigo discutiu como escrever consultas SQL usando múltiplas subconsultas. Abordamos os fundamentos das subconsultas, subconsultas correlacionadas, como combinar múltiplas subconsultas, exemplos práticos de subconsultas aninhadas e usando a cláusula WITH, além de técnicas de otimização de desempenho. Ao utilizar essas técnicas, você poderá criar consultas SQL mais eficientes e poderosas. Aproveite essas habilidades para melhorar seu SQL e realizar extrações e análises de dados complexas.

Índice