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
    )
Listagem 1. Exemplo de subquery

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).

Estrutura do Banco
Figura 1. Modelagem do banco
id titulo data
1 Aplicação C# 2018-04-01
2 Aplicação Ionic 2018-05-07
3 Aplicação Python 2018-08-05
Tabela 1. Estrutura da tabela projetos
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
Tabela 2. Estrutura da tabela comentarios
id nome email 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
Tabela 3. Estrutura da tabela usuarios
id_projeto id_usuario
1 1
1 3
2 1
2 2
2 3
2 4
3 2
Tabela 4. Estrutura da tabela likes_por_projeto
id_comentario id_usuario
7 1
7 2
7 4
Tabela 5. Estrutura da tabela likes_por_comentarios

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
Tabela 6. Resultado da query

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
Listagem 2. Consulta SQL

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
Listagem 3. Consulta do valor total de likes recebidos por projeto

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
Tabela 7. Resultado da query

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.

Sempre após a criação de uma subquery como nova coluna será necessário definir um nome para esta coluna, através da palavra reservada AS. Uma subquery como nova coluna deve retornar apenas uma única coluna com um único valor.

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
Tabela 8. Resultado da query

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
    );
Listagem 4. Subquery que gerou a Tabela 8

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.

Uma subquery utilizada como filtro de uma consulta principal pode retornar N valores, porém, apenas uma única coluna.

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
            );
Listagem 5. Subquery com o uso de EXISTS

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);
Listagem 6. Subquery com o uso de operadores lógicos

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
Tabela 9. Resultado da query

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
Listagem 7. Fonte de dados

Veja na Tabela 10 o resultado da query acima.

titulo Quantidade_Comentarios
Aplicação C# 2
Aplicação Ionic 3
Aplicação Python 2
Tabela 10. Resultado da query

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
Listagem 8. Utilizando a fonte de dados

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