O que é uma Subconsulta SQL (Subquery)
O que é uma Subconsulta SQL (Subquery)
Uma subconsulta é uma consulta embutida dentro de outra consulta, de forma aninhada, passando os resultados da consulta mais interna para a consulta mais externa por meio de uma cláusula WHERE ou de uma cláusula HAVING.
Desta forma, é possível restringir mais ainda os dados retornados por uma consulta, permitindo a criação de filtros bastante aprimorados. A subconsulta retorna os dados que serão empregado pela consulta “principal”, alimentando-a com informações a serem utilizadas como condições de filtragem.
Podemos utilizar subconsultas não apenas em consultas com a cláusula SELECT, mas também em operações INSERT, UPDATE e DELETE.
Quando usamos uma subconsulta em uma query, a subconsulta é resolvida primeiro, e então a consulta externa (principal) é resolvida de acordo com o resultado retornado pela subconsulta (subquery).
Regras gerais para aplicação de subconsultas
Algumas regras gerais precisam se seguidas para que seja possível empregar subconsultas. Entre elas, temos:
- A subconsulta pode ter apenas uma única coluna em sua cláusula SELECT, exceto quando a consulta principal tiver múltiplas colunas para comparação com as colunas selecionadas
- Se a subconsulta retornar mais de uma linha de dados, é necessário usar operadores de valores múltiplos, como o operador lógico IN
- As subconsultas são escritas dentro de parênteses
- Não é possível usar a cláusula ORDER BY em uma subconsulta – mas a consulta principal pode.
- É possível usar uma cláusula GROUP BY em uma subconsulta.
- Não podemos usar o operador BETWEEN com uma subconsulta (na consulta principal), mas podemos usar esse operador dentro da subconsulta.
Sintaxe Básica de uma Subconsulta SQL
A sintaxe básica para a criação de uma subconsulta SQL é a seguinte:
SELECT coluna(s) FROM tabela(s) WHERE coluna operador (SELECT coluna FROM tabela WHERE condições);
Onde operador pode ser qualquer operador lógico ou relacional, como >, <, >= ,<= ,=, <>, IN, NOT, AND, OR, etc.
Vejamos exemplos de aplicação de subconsultas SQL, usando o SGBD MySQL Server.
1. Subconsulta com operação SELECT
Vamos efetuar uma consulta à tabela de livros de nosso banco de dados db_biblioteca, retornando os livros (tbl_livro) publicados pela editora Wiley (tbl_editora), porém usando uma subconsulta em vez de usar INNER JOIN:
SELECT NomeLivro, PrecoLivro, IdEditora FROM tbl_livro WHERE IdEditora = (SELECT IdEditora FROM tbl_editora WHERE NomeEditora = 'Wiley');
Resultado:
2. Subconsulta com operação INSERT INTO
Podemos usar subconsultas também com a instrução de inserção de registros INSERT INTO, e outras instruções de linguagem de manipulação de dados (DML). Com a instrução INSERT INTO, os dados retornados por uma subconsulta são usados para realizar a inserção de um registro em outra tabela.
Sintaxe:
INSERT INTO tabela (colunas) (SELECT coluna(s) FROM tabela(s) WHERE coluna operador valor);
Exemplo: Vamos criar uma tabela de exemplo chamada de LivrosAssuntos, contendo os campos ID, NomeLivro e NomeAssunto:
CREATE TABLE LivrosAssuntos ( ID TINYINT PRIMARY KEY AUTO_INCREMENT, NomeLivro VARCHAR(50), NomeAssunto VARCHAR(40) )
Usando uma subconsulta, vamos popular esta nova tabela com os livros que tenham mais de 600 páginas e seus respectivos assuntos:
INSERT INTO LivrosAssuntos (NomeLivro, NomeAssunto) (SELECT L.NomeLivro, A,NomeAssunto FROM tbl_livro L INNER JOIN tbl_assunto A ON L.IdAssunto = A.IdAssunto WHERE L.NumPaginas >= 600);
Após executar o comando, efetuamos uma consulta à nova tabela para verificar se os dados foram inseridos com sucesso:
SELECT * FROM LivrosAssuntos
Resultado:
3. Subconsulta com operação UPDATE
Também podemos usar uma subconsulta com uma instrução UPDATE, permitindo atualizar os valores de registros de uma tabela com base no resultado retornado pela subconsulta.
Sintaxe:
UPDATE tabela SET coluna(s) = valor WHERE coluna operador (SELECT coluna(s) FROM tabela WHERE coluna operador valor);
Exemplo: Vamos aumentar os preços dos livros da editora Microsoft Press em 12% usando a declaração UPDATE. Como não sabemos o ID desta editora de memória, vamos usar uma subconsulta para nos auxiliar:
UPDATE tbl_livro SET PrecoLivro = PrecoLivro * 1.12 WHERE IdEditora = (SELECT IdEditora FROM tbl_Editora WHERE NomeEditora = 'Microsoft Press');
A subconsulta retorna o ID da editora de acordo com o nome da editora fornecido, e este ID é então empregado na consulta principal para aplicar a atualização nos valores dos registros desejados.
4. Subconsulta com operação DELETE
Finalmente, podemos usar subconsultas em instruções DELETE, selecionando o valor a ser excluído de uma tabela de acordo com o retorno da subconsulta.
Sintaxe:
DELETE FROM tabela WHERE coluna operador (SELECT coluna FROM tabela WHERE coluna operador valor);
Exemplo: Desejamos excluir os livros publicados cujo assunto é “Dinossauros“, porém não sabemos o ID deste assunto na tabela de livros. Suponha também que não sabemos com exatidão se o nome do assunto é “Dinossauros”, “Dinossauro” (no singular), “Dinos” ou algo do gênero – apenas os lembramos que o nome do assunto começa com “Dino”:
DELETE FROM tbl_livro WHERE IdAssunto = (SELECT IdAssunto FROM tbl_Assunto WHERE NomeAssunto LIKE 'Dino%');
Subconsultas encadeadas
Podemos aninhar uma subconsulta dentro de outra subconsulta, da mesma maneira que uma subconsulta é aninhada dentro de uma consulta principal. Neste caso, a subconsulta mais interna é resolvida primeiro, depois a subconsulta intermediária, e finalmente o resultado é repassado para a consulta principal.
Sintaxe básica:
SELECT coluna(s) FROM tabela(s) WHERE coluna operador (SELECT coluna FROM tabela WHERE coluna operador (SELECT coluna FROM tabela WHERE coluna operador valor);
Na prática, podemos pensar na subconsulta intermediária como fazendo o papel de uma consulta principal para a subconsulta de nível mais interno, e, assim, o processo é similar para quantos níveis de subconsultas forem aninhados.
Há um limite para a quantidade das subconsultas que podem ser aninhadas?
Isso depende muito da implementação de banco de dados que está sendo empregada. Por exemplo, o SGBDR Microsoft SQL Server suporta até 32 níveis de aninhamento (subconsulta dentro de subconsulta), porém esse limite pode ser diferente em outros sistemas, muitas vezes por conta de restrições de memória disponível ou da complexidade em si das consultas. Consulte sempre a documentação do sistema em uso para saber mais a respeito.
Confira também o conteúdo deste tutorial em uma aula em vídeo:
Veja também: Cláusula INNER JOIN – Retornar dados de duas ou mais tabelas relacionadas
boa noite sr Fábio. fiz o curso de MER e achei fantástico o seu método de ensino. estou tentando fazer agora o VB.net e nao estou conseguindo. como faco para obter as aulas deste curso?
obrigado
att Wagner
Parabens pelo video!!!
Preciso de ajuda em um projeto sobre futebol desde já agradeço, as consultas que preciso são: Total Frequencia + Assiduidade, sendo essa segunda mais complexa, exemplo:
Cada mês são 4 jogos (relatório é sempre puxado do total de 3 meses ou 90 dias), select abaixo já esta organizado por Total de frequencia, faltando organizar por assiduidade que deve ser comparada sempre a cada frequência anterior.
Exemplo:
Dois atletas empatam com 8 frequencias, sendo que o primeiro faltou o último jogo 07/04 e o segundo jogador não, então o segundo jogador fica na frente devido ordem de assiduidade, caso continuem empatados, precisa comparar o penultimo jogo que foi jogo 01/04, e assim por diante até chegar em um jogo que um faltou e esse ficará abaixo na ordem da relação: Total Frequencia + Assiduidade.
Tabelas resumidas são:
Jogador
ncod_jogador
cnome_joagador
Frequencias
ncod_jogador
nqtdeFrequencia
dt_Frequencia
Abaixo o select inicial que falta ordenar por assiduidade:
select
frequencias.ncod_jogador,
jogador.cnome_jogador
sum(nqtdeFrequencia) as Total_Freq
from frequencias
inner join jogador on (frequencias.ncod_jogador = jogador.ncod_jogador)
where CAST(frequencias.dt_frequencia as date)
BETWEEN cast( dateadd (day, -90,current_date) as date) and cast(current_date as date)
Group by
frequencias.ncod_jogador,
jogador.cnome_jogador
Order by Total_Freq DESC;