Uma subconsulta (ou subquery) é uma consulta SQL aninhada dentro de outra consulta. Ela pode aparecer na cláusula WHERE, na cláusula FROM ou na cláusula SELECT. Subconsultas permitem expressar perguntas complexas que não podem ser respondidas com uma única consulta simples.
IN e NOT IN
O predicado IN verifica se um valor pertence ao conjunto retornado por uma subconsulta.
Alunos matriculados em disciplinas de Engenharia de Software:
-- Passo 1 (subconsulta): ids das disciplinas de ENS (id_curso = 311)-- Passo 2 (consulta principal): alunos que cursaram essas disciplinasSELECTDISTINCT a.nome, a.id_cursoFROM aluno aWHERE a.id_aluno IN (SELECT md.id_alunoFROM matricula_disciplina mdJOIN disciplina d ON d.id_disciplina = md.id_disciplinaWHERE d.id_curso =311)ORDERBY a.nome;
EXISTS verifica se a subconsulta retorna ao menos uma linha. É frequentemente usado com subconsultas correlacionadas, em que a subconsulta referencia colunas da consulta externa.
EXISTS: disciplinas que têm ao menos um pré-requisito:
Uma subconsulta pode ser usada como se fosse uma tabela na cláusula FROM. Ela deve receber um alias.
Cursos com carga horária média por disciplina acima de 70 h:
-- A subconsulta calcula a média por curso; a consulta externa filtraSELECT media_por_curso.id_curso,ROUND(media_por_curso.media, 2) AS media_cargaFROM (SELECT id_curso, AVG(carga_horaria) AS mediaFROM disciplinaGROUPBY id_curso) AS media_por_cursoWHERE media_por_curso.media >70ORDERBY media_por_curso.media DESC;
2 records
id_curso
media_carga
311
137.50
111
80.63
WITH: Expressões de Tabela Comuns (CTE)
A cláusula WITH define uma CTE (Common Table Expression), que é uma subconsulta nomeada e reutilizável na consulta principal. CTEs tornam consultas complexas mais legíveis.
Cursos com carga horária total e número de disciplinas:
-- Define a CTE com estatísticas por cursoWITH stats_curso AS (SELECT id_curso,COUNT(*) AS n_disciplinas,SUM(carga_horaria) AS carga_total,AVG(carga_horaria) AS carga_mediaFROM disciplinaGROUPBY id_curso)-- Usa a CTE junto com a tabela curso para obter o nome completoSELECT c.nome_curso, s.n_disciplinas, s.carga_total,ROUND(s.carga_media, 1) AS carga_mediaFROM stats_curso sJOIN curso c USING (id_curso)ORDERBY s.carga_total DESC;
3 records
nome_curso
n_disciplinas
carga_total
carga_media
Engenharia de Software
8
1100
137.5
Ciências Econômicas
8
645
80.6
Pedagogia
8
510
63.8
Vantagens das CTEs com WITH:
Melhoram a legibilidade ao dar nomes descritivos a subconsultas complexas.
Permitem reutilizar a mesma subconsulta várias vezes na consulta principal.
Em alguns SGBDs, podem ser usadas recursivamente para consultas hierárquicas (WITH RECURSIVE).
Para Praticar
-- Subconsulta escalar no SELECT: mostrar a diferença do salário em relação à médiaSELECT nome, id_escola, salario,ROUND(salario - (SELECTAVG(salario) FROM professor), 2) AS dif_mediaFROM professorORDERBY dif_media DESC;
7 records
nome
id_escola
salario
dif_media
Helena Carvalho
31
6700
1585.71
Carla Pinto
11
6600
1485.71
Bruno Teixeira
11
6500
1385.71
Felipe Araujo
21
6400
1285.71
Gustavo Costa
31
3300
-1814.29
Eduarda Souza
21
3200
-1914.29
Igor Melo
31
3100
-2014.29
-- ALL: professores com salário maior que TODOS os professores de 20hSELECT nome, id_escola, salarioFROM professorWHERE salario >ALL (SELECT salarioFROM professorWHERE ch_semanal =20)ORDERBY salario DESC;
4 records
nome
id_escola
salario
Helena Carvalho
31
6700
Carla Pinto
11
6600
Bruno Teixeira
11
6500
Felipe Araujo
21
6400
-- WITH RECURSIVE: encontrar todos os pré-requisitos transitivos de 3110801-- (pré-requisitos diretos e indiretos — cadeia completa)WITH RECURSIVE cadeia AS (-- Caso base: pré-requisitos diretos de 3110801SELECT id_prereq AS disciplina, 1AS nivelFROM prereqWHERE id_disciplina =3110801UNION-- Caso recursivo: pré-requisitos dos pré-requisitosSELECT p.id_prereq, c.nivel +1FROM prereq pJOIN cadeia c ON p.id_disciplina = c.disciplina)SELECT c.disciplina AS prereq_transitivo, c.nivel, d.nome_disciplinaFROM cadeia cJOIN disciplina d ON d.id_disciplina = c.disciplinaORDERBY c.nivel, c.disciplina;
5 records
prereq_transitivo
nivel
nome_disciplina
3110601
1
Bases da Eng. de Software 6
3110401
2
Bases da Eng. de Software 4
3110402
2
Projeto Aplicado 4 - blockchain
3110201
3
Bases da Eng. de Software 2
3110202
3
Projeto Aplicado 2 - site WEB
WITH RECURSIVE permite escrever consultas que percorrem estruturas hierárquicas ou grafos — como a cadeia de pré-requisitos. O PostgreSQL suporta esse recurso; outros SGBDs podem ter sintaxe ligeiramente diferente. O resultado mostra todos os pré-requisitos (diretos e indiretos) de 3110801 com o nível de profundidade na cadeia.