Uma Subquery (também conhecida como SUBCONSULTA ou SUBSELECT) é uma instrução do tipo SELECT dentro de outra instrução SQL, que efetua consultas que, de outra forma, seriam extremamente complicadas ou impossíveis de serem feitas.
Na Listagem 1 segue um exemplo de uma SUBQUERY.
SELECT
*
FROM
tabela1 AS T
WHERE
coluna1 IN
(
SELECT
coluna2
FROM
tabela2 AS T2
WHERE
T.id = T2.id
)
No exemplo acima temos uma primeira instrução SELECT realizando um filtro através da cláusula IN dentro de outro SELECT, ou seja, uma consulta dentro do resultado de outra consulta.
Como utilizar?
Existem algumas formas de utilizar subqueries. Neste artigo abordaremos os seguintes meios:
- Subquery como uma nova coluna da consulta (SELECT AS FIELD);
- Subquery como filtro de uma consulta (utilizando IN, EXISTS ou operadores de comparação);
- Subquery como fonte de dados de uma consulta principal (SELECT FROM SELECT).
Estrutura do banco de dados de exemplo
Para ilustração dos exemplos a seguir, considere a estrutura de tabelas apresentada na Figura 1, onde temos a tabela projetos (Tabela 1), a tabela comentarios (Tabela 2), a tabela usuarios (Tabela 3), a tabela likes_por_projeto (Tabela 4) e a tabela likes_por_comentarios (Tabela 5).
id | titulo | data |
---|---|---|
1 | Aplicação C# | 2018-04-01 |
2 | Aplicação Ionic | 2018-05-07 |
3 | Aplicação Python | 2018-08-05 |
id | comentario | id_projeto | id_usuario |
---|---|---|---|
1 | A Microsoft acertou com essa linguagem! | 1 | 1 |
2 | Parabéns pelo projeto! bem legal! | 1 | 3 |
3 | Super interessante! Fácil e rápido! | 2 | 4 |
4 | Cara, que simples fazer um app assim! | 2 | 1 |
5 | Linguagem muito diferente. | 3 | 3 |
6 | Adorei aprender Python! Parabéns! | 3 | 2 |
7 | Muito maneiro esse framework! | 2 | 2 |
id | nome | senha | |
---|---|---|---|
1 | Bruna Luiza | bruninha@gmail.com | abc123. |
2 | Thiago Braga | thiagobraga_1@hotmail.com | pena093 |
3 | Osvaldo Justino | osvaltino@yahoo.com.br | osvaldit1_s |
4 | Gabriel Fernando | gabriel_fnd@gmail.com | gabss34 |
id_projeto | id_usuario |
---|---|
1 | 1 |
1 | 3 |
2 | 1 |
2 | 2 |
2 | 3 |
2 | 4 |
3 | 2 |
id_comentario | id_usuario |
---|---|
7 | 1 |
7 | 2 |
7 | 4 |
Subquery como uma nova coluna da consulta
Uma das formas possíveis de realizar uma subquery é fazendo com que o resultado de outra consulta seja uma coluna dentro da sua consulta principal.
Como exemplo buscaremos o título de todos os projetos cadastrados e adicionaremos uma coluna com a quantidade de comentários existentes em cada projeto, realizando assim uma consulta principal na tabela projetos e uma subconsulta na tabela comentarios, que gerará uma nova coluna.
Veja o resultado esperado na Tabela 6.
titulo | Quantidade_Comentarios |
---|---|
Aplicação C# | 2 |
Aplicação Ionic | 3 |
Aplicação Python | 2 |
No resultado acima existem duas colunas: titulo e Quantidade_Comentarios. Essa tabela foi obtida através da consulta SQL da Listagem 2.
SELECT
P.titulo,
(SELECT
COUNT(C.id_projeto)
FROM
comentarios C
WHERE
C.id_projeto = P.id ) AS Quantidade_Comentarios
FROM
projetos P
GROUP BY
P.id
Observe na query acima que a consulta principal é feita na tabela projetos, porém, na seleção das colunas que virão no resultado existe uma outra consulta, essa na tabela comentarios, responsável por trazer o total de ocorrências do ID do projeto específico na tabela comentarios. Essa coluna foi nomeada de Quantidade_Comentarios.
Podemos utilizar o trecho de código da Listagem 3 para adicionar mais uma coluna a esta consulta. Adicionaremos, por exemplo, o valor total de likes recebidos por projeto.
SELECT
P.titulo,
(SELECT
COUNT(C.id_projeto)
FROM
comentarios C
WHERE
C.id_projeto = P.id ) AS Quantidade_Comentarios,
(SELECT
COUNT(LP.id_projeto)
FROM
likes_por_projeto LP
WHERE
LP.id_projeto = P.id ) AS Quantidade_Likes
FROM
projetos P
GROUP BY
P.id
Veja o resultado da query acima na Tabela 7.
titulo | Quantidade_Comentarios | Quantidade_likes |
---|---|---|
Aplicação C# | 2 | 2 |
Aplicação Ionic | 3 | 4 |
Aplicação Python | 2 | 1 |
Observe que no resultado acima existem três colunas, sendo que apenas a coluna titulo faz parte da tabela projetos. As colunas Quantidade_Comentarios e Quantidade_likes são providas pelas duas subqueries utilizadas em tabelas diferentes: comentarios e likes_por_projeto, respectivamente.
Subquery como filtro de uma nova consulta
Outro exemplo da utilização de subqueries é fazendo filtros no resultado de outras consultas. Para esse modelo podemos utilizar as cláusulas IN, EXISTS ou operadores de comparação, como =, >=, <=, dentre outros.
Para exemplificar buscaremos todos os projetos que possuam algum comentário, ou seja, uma consulta principal na tabela projetos, e filtrar o resultado com base no resultado da subconsulta na tabela comentarios.
Veja ao resultado esperado na Tabela 8.
id | titulo | data |
---|---|---|
1 | Aplicação C# | 2018-04-01 |
2 | Aplicação Ionic | 2018-05-07 |
3 | Aplicação Python | 2018-08-05 |
Observe no resultado acima que vieram apenas informações da tabela projetos, mas que foram filtradas com base em uma pesquisa pelo ID do projeto na tabela comentarios. Cada projeto listado neste resultado é um projeto que possui algum comentário. Essa informação foi obtida através da query da Listagem 4.
SELECT
P.id,
P.titulo,
P.data
FROM
projetos P
WHERE
P.id IN
(
SELECT
C.id_projeto
FROM
comentarios C
WHERE
P.id = C.id_projeto
);
Observe que na query acima a consulta principal é feita na tabela projetos, mas que em seguida utilizamos a cláusula WHERE para realizar um filtro na seleção, definindo através da cláusula IN que o valor da coluna ID deve estar incluso no resultado da subconsulta realizada, que no caso é feita na tabela comentarios.
Podemos utilizar uma subquery como filtro com a cláusula EXISTS. Para exemplificar podemos realizar a mesma consulta anterior e buscar todos os projetos que possuam algum comentário, como vemos na Listagem 5.
SELECT
P.id,
P.titulo,
P.data
FROM
projetos P
WHERE
EXISTS
(
SELECT
C.id_projeto
FROM
comentarios C
WHERE
P.id = C.id_projeto
);
Na query acima continuamos com o mesmo resultado que a query anterior, mudando apenas a forma como é feita a subquery. No caso da cláusula EXISTS, a query principal realiza uma verificação se o resultado da segunda query conseguiu encontrar algum valor, e em caso positivo, retorna esse item, ou seja, ao encontrar um comentário para algum projeto, os dados solicitados na consulta principal a respeito desse projeto serão exibidos.
Outro exemplo do mesmo modelo de subquery seria utilizando operadores lógicos. Buscaremos agora o título e a data do último projeto que recebeu likes, ou seja, uma consulta principal na tabela projetos com um filtro na tabela likes, como vemos na Listagem 6.
SELECT
P.titulo,
P.data
FROM
projetos P
WHERE
P.id = (SELECT
MAX(LP.id_projeto)
FROM
likes_por_projeto LP);
Observe que na query acima a consulta principal é feita na tabela projetos e o filtro realizado através da cláusula WHERE é que o ID do projeto seja IGUAL ao valor retornado pela subquery, que busca pelo MAIOR valor de ID do projeto na tabela likes_por_projeto. Veja o resultado obtido na Tabela 9.
titulo | data |
---|---|
Aplicação Python | 2018-08-05 |
Subquery como fonte de dados de uma consulta principal
Este outro formato faz com que o resultado de uma subquery seja utilizado como tabela fonte de dados de uma consulta principal.
Para exemplificar esse modelo realizaremos primeiro a query que servirá como fonte de dados para a consulta principal, como vemos na Listagem 7.
SELECT
P.id,
P.titulo,
(SELECT
COUNT(C.id_projeto)
FROM
comentarios C
WHERE
C.id_projeto = P.id ) AS Quantidade_Comentarios
FROM
projetos P
Veja na Tabela 10 o resultado da query acima.
titulo | Quantidade_Comentarios |
---|---|
Aplicação C# | 2 |
Aplicação Ionic | 3 |
Aplicação Python | 2 |
Com base no resultado acima, selecionaremos com o código da Listagem 8 apenas o projeto que teve a quantidade de comentários maior de 2, dessa forma, utilizaremos a query acima como fonte de dados.
SELECT
F.titulo,
F.Quantidade_Comentarios
FROM
(SELECT
P.id,
P.titulo,
(SELECT
COUNT(C.id_projeto)
FROM
comentarios C
WHERE
C.id_projeto = P.id ) AS Quantidade_Comentarios
FROM
projetos P
) as F
WHERE
F.Quantidade_Comentarios > 2
Observe que na query acima a consulta principal solicita através do FROM as colunas titulo, Quantidade_Comentarios da fonte de dados baseada em uma outra consulta, e por fim, realiza um filtro no resultado através da cláusula WHERE para buscar somente aqueles projetos com a quantidade de comentários maior que 2.
Sempre após a criação de uma subquery como fonte de dados de uma consulta principal será necessário definir um nome para esta fonte de dados, através da palavra reservada AS.
Para mais informações, temos aqui na DevMedia um curso exclusivo sobre este tema! Avançando com Subqueries
Saiba mais Veja a Série SQL nível Jedi: Subqueries