Banco de Dados

30 out, 2017

Entendendo as cláusulas Exists e Not Exists

Publicidade

Estas são cláusulas SQL ANSI, um padrão da linguagem SQL seguido pela maior parte dos SGBDs (sistema de gerenciamento de banco de dados). Essa especificação é relativa a uma padronização de nome de cláusulas. Isso significa que o mesmo nome pode ser usado tanto no SQL Server, quanto no PostgreSQL, MySQL e assim por diante. Algumas cláusulas que seguem o mesmo padrão, são o INSERT, UPDATE e DELETE, por exemplo.

Para entender como elas funcionam, veremos como elas funcionam na prática. Para isso, os scripts abaixo precisam ser executados para que os dois exemplos a seguir possam trazer os mesmos resultados mostrados neste artigo. Os scripts foram implementados para o SQL SERVER.

Após executar os scripts, vamos aos exemplos:

Primeiro exemplo

Vamos relacionar do banco, os alunos que fazem apenas o curso de SQL SERVER 2012.

SELECT P.nu_matricula, 
       P.no_pessoa, 
       C.nu_curso, 
       C.no_curso 
FROM   tb_pessoa P, 
       tb_aula A, 
       tb_conteudo_programatico CP, 
       tb_curso C 
WHERE  A.co_pessoa = P.co_seq_pessoa 
       AND A.co_conteudoprogramatico = CP.co_seq_conteudoprogramatico 
       AND CP.co_curso = C.co_seq_curso 
       AND NOT EXISTS (SELECT NULL 
                       FROM   tb_curso C2, 
                              tb_conteudo_programatico CP2, 
                              tb_aula A2 
                       WHERE  C2.nu_curso = 'JV01' 
                              AND CP2.co_curso = C2.co_seq_curso 
                              AND A2.co_conteudoprogramatico = 
                                  CP2.co_seq_conteudoprogramatico 
                              AND A2.co_pessoa = A.co_pessoa) 
GROUP  BY P.nu_matricula, 
          P.no_pessoa, 
          C.nu_curso, 
          C.no_curso 
ORDER  BY C.no_curso, 
          P.no_pessoa;

Com esta query, teremos o seguinte resultado:

Veja que aqui temos 6 alunos do curso de SQL SERVER 2012. Ao total, na nossa base são 9 alunos (faça um select em TB_AULA para conferir). No exemplo queremos que apenas os alunos que fazem SQL SERVER sejam mostrados.

A abordagem realizada para permitir isso foi a utilização da cláusula NOT EXISTS e a igualdade com CO_PESSOA. Ambos estão abreviados para destacarmos este artifício. O contrário de NOT EXISTS é a cláusula EXISTS. Veremos um exemplo de como ela funciona logo mais.

Para entendermos melhor o que o NOT EXISTS faz (e a mesma analogia servirá para EXISTS), vamos executar apenas o SELECT que está entre os parênteses. Faremos apenas pequenas adaptações, como substituir o NULL do select por A2.* e C2.* e retirar a última linha de igual com CO_PESSOA, uma vez que esta linha se trata de um JOIN com uma tabela que não está dentro do parênteses. Com A2.* e C2.*, veremos o que nos interessa que são as informações referentes aos alunos e do curso apenas:

SELECT * 
FROM   tb_curso C2, 
       tb_conteudo_programatico CP2, 
       tb_aula A2 
WHERE  C2.nu_curso = 'JV01' 
       AND CP2.co_curso = C2.co_seq_curso 
       AND A2.co_conteudoprogramatico = p2.co_seq_conteudoprogramatico; 

Repare no resultado:

Com isso, fica mais fácil entender que os alunos 9, 6 e 5 serão excluídos do resultado, mas para isso, não podemos esquecer do NOT EXISTS e da coluna CO_PESSOA. Apenas para conferir os nomes dos alunos e seu respectivo CO_SEQ_PESSOA:

SELECT * 
FROM   tb_pessoa 
WHERE  co_seq_pessoa IN ( 9, 6, 5 ); 

Resultado:

Dado este aprendizado, vamos partir para o segundo exemplo.

Segundo exemplo

Agora vamos mostrar o total dos alunos, apenas do curso de JAVA usando a cláusula EXISTS.

SELECT C.nu_curso, 
       C.no_curso, 
       Count(DISTINCT A.co_pessoa) total_alunos 
FROM   tb_pessoa P, 
       tb_aula A, 
       tb_conteudo_programatico CP, 
       tb_curso C 
WHERE  A.co_pessoa = P.co_seq_pessoa 
       AND A.co_conteudoprogramatico = P.co_seq_conteudoprogramatico 
       AND CP.co_curso = C.co_seq_curso 
       AND EXISTS (SELECT NULL 
                   FROM   tb_curso C2, 
                          tb_conteudo_programatico CP2, 
                          tb_aula A2 
                   WHERE  C2.nu_curso = 'JV01' 
                          AND CP2.co_curso = C2.co_seq_curso 
                          AND A2.co_conteudoprogramatico = 
                              p2.co_seq_conteudoprogramatico 
                          AND A2.co_pessoa = A.co_pessoa 
                          AND C2.co_seq_curso = C.co_seq_curso) 
GROUP  BY C.nu_curso, 
          C.no_curso 
ORDER  BY C.no_curso; 

Veja o resultado:

Conforme mencionado, estes scripts SQL podem ser usados tranquilamente em outros SGBDs, por se tratar de SQL ANSI. Evidentemente que, para mostrar estes mesmos resultados, você terá que ter tabelas e dados iguais.

Bons estudos.