Capítulo 2
Subconsultas
As consultas SQL (e portanto do Mysql também) são feitas sobre uma relação, que pode estar materializada em formato de uma tabela ou não.
A relação pode, portanto, ser "materializada em forma de tabela" ou pode ser o resultado de uma seleção.
O fato de podermos usar relações não apenas como tabelas, possibilita a construção de "consultas aninhadas" ou "relacionadas" .
Essa possibilidade de relacionar consultas permite que sejam buscadas informações em múltiplas tabelas.
Da mesma forma que as junções as subconsultas (subqueries) são usadas para obtermos dados de diferentes tabelas.
Portanto na linguagem SQL (e obviamente no Mysql) podemos obter dados a partir de múltiplas tabelas usando junção (JOIN) ou a subconsulta (SUBQUERY).
Veremos mais adiante no curso que podemos também obter dados de múltiplas tabelas usando, Tabelas Aninhadas, Tabelas Temporárias ou Tabelas Derivadas.
Veremos também uma estrutura, CTE, Common Table Expression, que também possibilita a combinação de resultados.
O que são subconsultas
Subconsultas, ou consultas aninhadas, são "consultas dentro de consultas".
>Uma subconsulta (subquery) pode ser usada com SELECT, INSERT, UPDATE ou DELETE.
A idéia da subconsulta é usar o resultado de um comando SELECT como entrada para outro comando SELECT.
Definindo de forma simples, uma subconsulta é uma instrução SELECT que é escrita dentro de outra instrução SQL (que geralmente é, mas não precisa ser, outra SELECT). Para distinguir a subconsulta (ou também chamdada de consulta interna) de sua consulta delimitadora (ou consulta externa), ela deve ser colocada entre parênteses.
A subconsulta pode ser dois tipos −Tipos
- Correlacionada (Correlated subquery) - Na subconsulta correlacionada, a consulta interna depende da consulta externa. A consulta externa precisa ser executada antes da consulta interna
- Não Correlacionada (Non-Correlated subquery) - Na consulta não correlacionada, a consulta interna não depende da consulta externa. Ambos podem ser executados separadamente.
| Item | Conceito | Subconsulta Correlacionada | Subconsulta Não Correlacionada |
|---|---|---|---|
|
1 |
Definição |
Na subconsulta correlacionada, a consulta interna depende da consulta externa |
Na consulta não correlacionada, a consulta interna não depende da consulta externa |
2 |
Cláusula com IN e NOT IN | Não usa a cláusula IN e NOT IN |
A subconsulta não correlacionada é usada junto com a cláusula IN e NOT IN |
3 |
Consultas executadas separadamente |
A consulta interna não pode ser executada sozinha |
A consulta interna não pode ser executada sozinha e não depende da consulta externa |
4 |
Performance |
subconsultas correlacionadas são consultas mais lentas |
Eles são mais rápidas do que subconsultas correlacionadas |
Subconsultas na Cláusula WHERE
A utilização de subconsultas na cláusula WHERE é uma das formas de combinar duas ou mais consultas para um único resultado final. Nessas construções o resultado intermediário não é apresentado ao usuário. O SGBD obtém um "resultado temporário" para ser usado em outra consulta.
Existem dois tipos de subconsultas: correlacionadas e não-correlacionadas
Subconsultas Não Correlacionadas
Como vimos (aqui) usando o predicado IN é possível comparar o valor de uma coluna com uma lista de valores. Na subconsulta não-correlacionada, substitui-se a lista de valores do predicado IN por uma consulta (usando select).
A sintaxe básica de uma subconsulta não-correlacionada é:
Sintaxe Subconsulta não-correlacionada
SELECT col1, col2,...colN
FROM NOME_TABELA
WHERE COLM [NOT] IN {select COLX from NOME_TABELA2)
Note que a esquerda do predicado [not] IN existe uma coluna (COLM). A consulta interna (esquerda do predicado IN) não tem nenhuma relação com a consulta externa.
Importante: a consulta interna deverá retornar apenas uma coluna.Usamos como exemplo de uma subconsulta o banco de dados da livraria, apresentado inicialmente no nosso estudo orientado 1 (e mostrado abaixo):
| Código | Título | Preço | Lançamento | Assunto | Editora |
| 1 | Banco de Dados para Web | 31,20 | 10/01/1999 | B | 1 |
| 2 | Programando em Linguagem C | 30,00 | 01/10/1997 | P | 1 |
| 3 | Programando em Linguagem C++ | 111,50 | 01/11/1998 | P | 3 |
| 4 | Banco de Dados na Bioinformática | 48,00 | B | 2 | |
| 5 | Redes de Computadores | 42,00 | 01/09/1996 | R | 2 |
|
|
Exemplo de subconsulta não-relacionada
Exemplo 1: Obtenha os nomes das editoras que possuem livros já lançados
Subconsulta - Exemplo 1
mysql> select nome
-> from editora
-> where codigo in
-> (select editora from livro where lancamento is not null);
+-----------------------+
| nome |
+-----------------------+
| Mirandela Editora |
| Editora Ilhas Tijucas |
| Editora via-norte |
+-----------------------+
3 rows in set (0.00 sec)
Nessa consulta temos uma "consulta interna" que gera uma relação temporária de uma única coluna e que não é exibida. Ela é usada como dado para a consulta externa.
A consulta interna retorna os códigos de editoras que publicaram livros (lancamento is not null). A partir do resultado dessa consulta, a consulta externa irá buscar os dados.
A consulta interna sozinha retorna:
consulta interna
mysql> select editora from livro where lancamento is not null;
+---------+
| editora |
+---------+
| 1 |
| 1 |
| 3 |
| 2 |
+---------+
4 rows in set (0.00 sec)
Exemplo 2: Quais os assuntos que não tiveram livros lançados?
Subconsulta - Exemplo 2
mysql> select descricao
-> from assunto
-> where sigla not in
-> (select assunto from livro where lancamento is not null);
+-----------------------+
| descricao |
+-----------------------+
| Sistemas Operacionais |
+-----------------------+
1 row in set (0.00 sec)
Nesse exemplo a consulta interna gera uma lista de assuntos dos livros que já foram lançados. A consulta externa procura na tabela assuntos quais assuntos NÃO CONSTAM na lista gerada pela consulta interna.
Explicação
Nesses dois exemplos a consulta interna foi independente da consulta externa. Por isso a chamamos de subconsulta não-correlacionada
Comentário
Podemos usar subconsultas em oeprações de atualização e exclusão. Por exemplo, podemos fazer:
Exemplo: exclusão com subconsulta
Exclua as editoras que não publicaram livros:
delete from editora
where codigo not in
(select editora from livro)
Subconsultas Correlacionadas
No caso da subconsulta correlacionada existe uma dependência direta entre as consultas externa e interna.
Na subconsulta correlacionada utiliza-se o predicado EXISTS. Lembre-se que predicado IN permite testar se valores de uma coluna constam em uma listagem de valores. Já o predicado EXISTS testa se uma condição é verdadeira ou falsa.
Sintaxe Subconsulta Correlacionada
SELECT col1, col2,...colN
FROM NOME_TABELA TAB_EXTERNA
WHERE [NOT] EXISTS (select COLX from NOME_TABELA2 TAB_INTERNA
WHERE TAB_EXTERNA.COL_A = TAB_INTERNA.COL_A)
WHERE TAB_EXTERNA.COL_A = TAB_INTERNA.COL_A
Esse tipo de teste é possível nas subconsultas. Aliás é um dos motivos de termos subconsultas.
Essa subconsulta começa ser executada pela consulta mais externa. Então para cada linha de NOME_TABELA, a subconsulta será executada, substituindo-se o valor de TAB_EXTERNA.COL_A por seu valor na linha em questão.
Se a consulta interna retornar algum valor (poderá retornar uma ou mais linhas que farão parte de um relação temporária) a cláusula EXISTS será verdadeira e a linha recuperada na consulta mais externa fará parte do resultado final. Caso contrário, a consulta mais externa realiza o teste para a próxima linha de TAB_EXTERNA.COL_A.
Note que na utilização do predicado EXISTS, não é posicionada nenhuma coluna a esquerda, pois ele não compara valores mas sim faz teste de uma condição booleana. Assim a coluna posicionada na cláusula SELECT da subconsulta não influenciará o resultado do comando
Exemplo de subconsulta correlacionada
Exemplo 3: Quais os nomes das editoras que possuem livros já lançados
(repare que usamos essa mesma consulta com uma subconsulta não-correlacionadas, no exemplo 1).Subconsulta Correlacionada- Exemplo 3
mysql> select nome
-> from editora ed
-> where exists
-> (select editora from livro where lancamento is not null and ed.codigo = editora);
+-----------------------+
| nome |
+-----------------------+
| Mirandela Editora |
| Editora Ilhas Tijucas |
| Editora via-norte |
+-----------------------+
3 rows in set (0.00 sec)
Observação
Essa subconsulta pode ser realizada (vide exemplo 1 acima) com uma subconsulta não-correlacionada ou usando junção:
select distinct nome from editora ed inner
join livro on ed.codigo=editora
where lancamento is not null;
Exemplo 4: Quais os assuntos que não tiveram livros lançados?
(Vide consulta semelhante no Exemplo 2 acima)Subconsulta - Exemplo 4
mysql> SELECT descricao
-> FROM assunto ASSU
-> WHERE NOT EXISTS
-> (select assunto from livro
-> where lancamento is not null
-> and ASSU.SIGLA = ASSUNTO);
+-----------------------+
| descricao |
+-----------------------+
| Sistemas Operacionais |
+-----------------------+
1 row in set (0.00 sec)
Atualização e Exclusão
Assim como no caso do predicado IN e da subconsulta não-correlacionada, podemos usar o predicado EXISTS em comandos de atualização e exclusão de dados.
Importante
Em geral consultas com JOIN são mais eficientes que uma subconsulta, portanto, se a subquery puder ser transformada em uma consulta com JOIN, é preferível usar essa última.