UFABC –UAB TSI –
TECNOLOGIA EM SISTEMAS DE
INFORMAÇÃO
AULA 6B: SQL – PARTE 2
SUBCONSULTAS E AGREGAÇÕES
AGENDA
Agrupamento e Agregação de dados
Agrupando resultados de consultas
Somando dados
Contando registros
Média, máximo, mínimo
Subconsultas
Conceitos
Formas de utilização
Quando usar subconsultas?
Criando consultas mais complexas
AGRUPANDO DADOS
Cláusula GROUP BY
Agrupa os dados pelo campo selecionado
Recurso para definirmos totalizações (por exemplo)
Agrupamentos só são realizados após o conjunto de dados ser recuperado
Não pode ser usado antes de uma cláusula WHERE
AGRUPANDO DADOS
mysql> select idProj -> from projFunc -> group by idProj;
+--------+| idProj |+--------+| 1 || 2 |+--------+2 rows in set (0.00 sec)
mysql> select idProj -> from projFunc;
+--------+| idProj |+--------+| 1 || 1 || 2 || 2 || 2 || 2 |+--------+6 rows in set (0.00 sec)
AGREGANDO DADOS
A idéia de agregar é sumarizar alguma informação de um conjunto de registros
Somatórias
Máximos valores
Mínimos valores
Médias
Quantidade de valores
Retirar da responsabilidade da aplicação, uma vez que o SGBD já realiza isso
Algumas consultas necessitam desse tipo de informação como critérios para novas consultas
FUNÇÕES DE AGREGAÇÃO
Max(campo)
Retorna o maior valor do campo dentro de um conjunto
Min(campo)
Retorna o menor valor do campo dentro de um conjunto
Avg(campo)
Retorna o valor médio do campo
Sum(campo)
Retorna a somatória dos valores do campo
Count(campo)
Retorna a quantidade de registros de um campo
USANDO FUNÇÕES DE
AGREGAÇÃO
Contando quantos funcionários há na empresa
mysql> select count(*) from funcionario;+----------+| count(*) |+----------+| 8 |+----------+1 row in set (0.06 sec)
Contando quantos departamentos há na empresa
mysql> select count(*) from departamento;+----------+| count(*) |+----------+| 3 |+----------+1 row in set (0.03 sec)
USANDO AGREGAÇÃO E
AGRUPAMENTOS
Contando quantos funcionários há por projeto
mysql> select idProj, count(idFunc)-> from projFunc group by idProj;
+--------+---------------+| idProj | count(idFunc) |+--------+---------------+| 1 | 2 || 2 | 4 |+--------+---------------+2 rows in set (0.00 sec)
AGRUPANDO, JUNTANDO,
AGREGANDO...
Selecionando os nomes dos projetos que os funcionários trabalham
mysql> select p.descrP, pf.idProj, count(pf.idFunc)-> from projFunc pf inner join projeto p using (idProj)-> group by idProj;
+----------------+--------+------------------+| descrP | idProj | count(pf.idFunc) |+----------------+--------+------------------+| Folha de Pagto | 1 | 2 || Sist. Escolar | 2 | 4 |+----------------+--------+------------------+2 rows in set (0.13 sec)
FILTROS PARA DADOS
AGREGADOS
Cláusula HAVING
Diferença básica entre HAVING e WHERE
Where dados brutos (originados diretamente da tabela ou da view), sem nenhum tratamento
Having dados agregados (somatórias, maiores, menores, contadores)
FILTROS PARA DADOS
AGREGADOS
Filtrando os projetos que possuem mais de 2 funcionários alocados
mysql> select p.descrP, pf.idProj, count(pf.idFunc)-> from projFunc pf inner join projeto p using (idProj)-> group by idProj-> having count(pf.idFunc) > 2;
+---------------+--------+------------------+| descrP | idProj | count(pf.idFunc) |+---------------+--------+------------------+| Sist. Escolar | 2 | 4 |+---------------+--------+------------------+1 row in set (0.06 sec)
AGRUPAMENTOS
Por que utilizar agrupamentos?
Organizar a informação que se quer recuperar
Exemplos de agrupamentos
Totais de vendas por região geográfica
Encontrar vendedores que mais realizaram vendas em um determinado ano
Determinar freqüências de ocorrências de elementos
Número de contas abertas em cada filial de um banco
UM EXEMPLO MAIS
ELABORADO
Este exemplo é um exemplo existente no livro
“Aprendendo SQL – O´Rilley”
E também pode ser obtido pelo endereço
A idéia é que o modelo retrate uma instituição financeira (Banco), onde existem várias agências que oferecem produtos a clientes.
Produtos podem ser Poupança (SAV-savings), financiamentos (LOA –loans), depósitos (CHK–checks), entre outros
A idéia é apenas apresentá-lo para que vocês possam “ler” um modelo de dados já existente e entender também como as consultas foram geradas.
Este exemplo é bastante rico se levarmos em considerações operações de agregações e agrupamentos
UM EXEMPLO MAIS
ELABORADO – AS TABELAS
Account
Uma conta (produto) específico aberto para um cliente em particular
Branch
Uma agência bancária onde uma transação é realizada
Customer
Cliente do banco (pode ser pessoa física ou jurídica)
Business
Cliente pessoa jurídica
Individual
Cliente pessoa física
Department
Departamento do banco
Employee
Funcionário do banco
Officer
O Administrador da pessoa jurídica (pode ter várias)
Product
Um produto oferecido pelo banco (linha de crédito para PJ, hipoteca imobiliária, financiamento de carros)
Product_type
Tipo dos produtos oferecidos (financiamentos, conta bancária, seguros)
Transaction
Uma ocorrência em uma conta bancária
ENTENDENDO O EXEMPLO
Um cliente (customer) é uma entidade que pode ser especializada em duas outras
Pessoa física (individual)
Pessoa jurídica (business)
Todo cliente pessoa jurídica tem um ou mais gerente (que pode ser gerente de apenas 1 pessoa jurídica)
ENTENDENDO O EXEMPLO
Todo produto (product) oferecido pelo banco tem uma categoria (product_type) associado a ela
Além disso todo funcionário (employee) trabalha tem um departamento (department) associado a ele e é gerenciado por outro funcionário (auto-relacionamento)
Adicionalmente, um funcionário está alocado (trabalha) em uma agência
ENTENDENDO O EXEMPLO
O cliente tem uma ou várias contas (account) e toda conta está associada a um produto (product) e a uma agência (branch) onde a conta foi aberta
ENTENDENDO O EXEMPLO
Toda transação (transaction) está associada a uma conta (que pode ser crédito ou débito)
Toda transação também está associada à um empregado (que a efetiva) e a uma agência onde a transação terá efeito (um depósito pode ser feito em uma agência referenciando uma conta de outra agência)
AGRUPAMENTOS POR VÁRIAS
COLUNAS
GROUP BY pode ser utilizado para agrupar dados por várias colunas
Geração de totais e subtotais
No exemplo dos bancos
Caso simples: somar todos os saldos de contas existentes
Elaborando um pouco: somar todos os saldos por tipos de produtos (crédito para pequenas empresas, poupança, etc)
Elaborando mais ainda: somar todos os saldos por tipos de produtos e também por agência
AGRUPAMENTOS POR VÁRIAS
COLUNAS
mysql> select product_cd, open_branch_id, sum(avail_balance) as total -> from account;
+------------+----------------+-----------+| product_cd | open_branch_id | total |+------------+----------------+-----------+| CHK | 2 | 170754.46 |+------------+----------------+-----------+1 row in set (0.03 sec)
mysql> select product_cd, open_branch_id, sum(avail_balance) as total -> from account group by product_cd;
+------------+----------------+----------+| product_cd | open_branch_id | total |+------------+----------------+----------+| BUS | 4 | 9345.55 || CD | 2 | 19500.00 || CHK | 2 | 73008.01 || MM | 3 | 17045.14 || SAV | 2 | 1855.76 || SBL | 3 | 50000.00 |+------------+----------------+----------+6 rows in set (0.08 sec)
Caso 1: somando tudo
Caso 2: agrupando por tipos de produtos
AGRUPAMENTO POR VÁRIAS
COLUNAS
mysql> select product_cd, open_branch_id, sum(avail_balance) as total -> from account group by product_cd, open_branch_id;
+------------+----------------+----------+| product_cd | open_branch_id | total |+------------+----------------+----------+| BUS | 2 | 9345.55 || BUS | 4 | 0.00 || CD | 1 | 11500.00 || CD | 2 | 8000.00 || CHK | 1 | 782.16 || CHK | 2 | 3315.77 || CHK | 3 | 1057.75 || CHK | 4 | 67852.33 || MM | 1 | 14832.64 || MM | 3 | 2212.50 || SAV | 1 | 767.77 || SAV | 2 | 700.00 || SAV | 4 | 387.99 || SBL | 3 | 50000.00 |+------------+----------------+----------+14 rows in set (0.03 sec)
Caso 3: agrupando por produto e por agência em que foi aberto
GERANDO SUMÁRIOS
(ROLLUPS)
Um recurso bastante poderoso oferecido pelo SGBD é a geração automática de sumários (RollUps)
Facilita a recuperação ordenada de informações com as respectivas totalizações automaticamente
Utiliza-se um agrupamento, indicando a necessidade de gerar totalizações
Cláusula WITH ROLLUP adicionada na cláusula GROUP BY
GERANDO SUMÁRIOS
(ROLLUPS)
mysql> select product_cd, open_branch_id, sum(avail_balance) as total -> from account group by product_cd, open_branch_id WITH ROLLUP;
+------------+----------------+-----------+| product_cd | open_branch_id | total |+------------+----------------+-----------+| BUS | 2 | 9345.55 || BUS | 4 | 0.00 || BUS | NULL | 9345.55 || CD | 1 | 11500.00 || CD | 2 | 8000.00 || CD | NULL | 19500.00 || CHK | 1 | 782.16 || CHK | 2 | 3315.77 || CHK | 3 | 1057.75 || CHK | 4 | 67852.33 || CHK | NULL | 73008.01 || MM | 1 | 14832.64 || MM | 3 | 2212.50 || MM | NULL | 17045.14 || SAV | 1 | 767.77 || SAV | 2 | 700.00 || SAV | 4 | 387.99 || SAV | NULL | 1855.76 || SBL | 3 | 50000.00 || SBL | NULL | 50000.00 || NULL | NULL | 170754.46 |+------------+----------------+-----------+21 rows in set (0.01 sec)
Ao invés de deixar a responsabilidade da somatória por conta da aplicação, o SGBD já realiza isso para você. As linhas que contém NULL representam totalizações parciais ou geral
Totais parciais
Total geral
RESUMOS MAIS ELABORADOS
Alguns SGBDs implementam a opção WITH CUBE em suas opções de agrupamento
MySQL não suporta essa opção
WITH ROLLUP
Organiza totais pela ordem dos campos que foram especificados na consulta
Totaliza as agências por tipo de produtos
Totaliza os produtos
WITH CUBE
Totaliza todas as combinações existentes
Totalizaria também todas as agências (independente do tipo de produto)
SUBCONSULTAS
Basicamente uma subconsulta é uma consulta contida em outra instrução SQL
Tipos de resultados
Única linha com única coluna
Única linha e múltiplas colunas
Múltiplas linhas com única coluna
Múltiplas linhas e colunas
Dois tipos de consulta
Subconsultas não correlatas
Subconsultas correlatas
POR QUE SE USAR
SUBCONSULTAS?
Muitas vezes é possível obter o mesmo resultado de uma subconsulta através das cláusulas de filtros (WHERE) indicando igualdades
Mas quando não se souber os valores que devem ser combinados para se fazer o filtro?
Ou não se sabe a quantidade de valores que devem ser comparados para se obter os filtros
Ideal: usar subconsultas
Uma consulta retorna um conjunto de valores que serão combinados (conferidos) com os valores da consulta principal e, então, retornados aos usuários
SITUAÇÃO
Deseja-se, a partir de uma tabela existente, buscar todos os funcionários que são supervisores
mysql> select * from funcionario;+--------+--------------+-------------------+------+------------+---------+---------+| idFunc | nomeF | emailF | sexo | dataAd | idDepto | idSuper |+--------+--------------+-------------------+------+------------+---------+---------+| 1 | Isidro | [email protected] | M | 2010-01-01 | 1 | NULL || 2 | Sezefredo | [email protected] | M | 2010-01-01 | 1 | 1 || 3 | Adamastor | [email protected] | M | 2010-01-01 | 1 | 1 || 4 | Deosdedite | [email protected] | M | 2010-01-01 | 1 | 1 || 5 | Energarda | [email protected] | F | 2010-01-01 | 2 | 2 || 6 | Josicleide | [email protected] | F | 2010-01-01 | 2 | 2 || 7 | Nilsonclecio | [email protected] | M | 2010-01-01 | 3 | 6 || 8 | Roberval | [email protected] | M | 2010-01-01 | 3 | 6 || 9 | Cheirosa | [email protected] | F | 2010-04-30 | 2 | 1 || 10 | Caue | [email protected] | M | 2010-04-30 | 1 | 1 || 11 | Ermenegildo | [email protected] | M | 2010-05-03 | 7 | 1 |+--------+--------------+-------------------+------+------------+---------+---------+11 rows in set (0.01 sec)
COMO FAZER?
1a tentativa – fácil, porém limitada (usando filtros simples)
mysql> select nomeF from funcionario where
idFunc = 1 or idFunc = 2 or idFunc = 6;
+------------+
| nomeF |
+------------+
| Isidro |
| Sezefredo |
| Josicleide |
+------------+
3 rows in set (0.00 sec)
Poblema desta abordagem
Caso surja outro supervisor, a consulta deve ser refeita para incluir na cláusula WHERE o código do novo supervisor
Ou ainda, se o número de identificação do supervisor for alterado
COMO FAZER?
2a tentativa – Subconsultas
Como pensar em subconsultas?
Pense em INTERSECÇÃO, SUBTRAÇÃO de conjuntos ou SUBCONJUNTOS
Conjunto 1 – recuperar os códigos de funcionários e seus respectivos nomes
cujos códigos sejam coincidentes na coluna SUPERVISOR da tabela
COMO FAZER?
+---------+| idSuper |+---------+| NULL || 1 || 1 || 1 || 2 || 2 || 6 || 6 || 1 || 1 || 1 |+---------+
+--------+| idFunc |+--------+| 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10 || 11 |+--------+
AS CLÁUSULAS IN E NOT IN
Lembram da teoria dos conjuntos?
Idéia por trás das subconsultas
IN
Indica que os dados que fazem parte do filtro DEVEM fazer parte do conjunto obtido na subconsulta (intersecção com um subconjunto)
NOT IN
Indica que os dados que fazem parte do filtro NÃO DEVEM fazer parte do conjunto obtido na subconsulta (Subtração de conjuntos)
TRANSFORMANDO O RACIOCÍNIO EM
SQL
mysql> select nomeF from funcionario where
-> idFunc IN (select idSuper from funcionario);+------------+| nomeF |+------------+| Isidro || Sezefredo || Josicleide |+------------+3 rows in set (0.00 sec) Esta consulta retorna
um conjunto de ID de
supervisores dos
funcionários
TRANSFORMANDO O RACIOCÍNIO EM
SQL
mysql> select nomeF from funcionario where
-> idFunc IN (select idSuper from funcionario);+------------+| nomeF |+------------+| Isidro || Sezefredo || Josicleide |+------------+3 rows in set (0.00 sec)
O filtro indica todos os
IDs de funcionários
que fazem parte do
conjunto obtido na
subconsulta
ALGUMAS OBSERVAÇÕES
Existem casos em que elementos da query principal não combinam (match) com elementos do conjunto obtido na subconsulta
Operador IN indica que se houver algum elemento na subconsulta, a condição é satisfeita
O operador NOT IN indica que um elemento da query principal não deve ter nenhum correspondente na subconsulta
Todo o conjunto deve ser percorrido
MAIS OBSERVAÇÕES
Ao usar NOT IN, deve-se certificar que os valores retornados pela subconsulta não contenham valores NULL
O SBGD vai igualar o valor do lado esquerdo da expressão com cada valor da subconsulta
Ao igualar o valor com NULL, o resultado é “desconhecido” e, portanto a consulta não resultará no esperado
SITUAÇÃO
Recuperar todos os funcionários que não são supervisores – teoricamente a mesma instrução com uma restrição a mais na 2ª subconsulta
mysql> select nomeF from funcionario -> where idFunc not in (Select distinct idsuper from funcionario);
Empty set (0.00 sec)
mysql> select nomeF from funcionario -> where idFunc in(Select distinct idsuper from funcionario where idSuper is not null)
+--------------+| nomeF |+--------------+| Adamastor || Deosdedite || Energarda || Nilsonclecio || Roberval || Cheirosa || Caue || Ermenegildo |+--------------+8 rows in set (0.00 sec)
O simples fato de uma subconsultaretornar uma única linha com um campo NULL, já pode alterar o resultado de toda a consulta
OPERADOR ALL
Permite realizar operações com TODOS os elementos do subconjuntos
Dessa forma, algum tipo de operação complementar deve ser indicado
=, <>, >, >=, <, <=
OPERADOR ALL
O exemplo anterior também pode ser escrito da seguinte forma:
mysql> select nomeF from funcionario where idFunc <> ALL (Select distinct idsuper from funcionario where idSuper is not
null);
+--------------+| nomeF |+--------------+| Adamastor || Deosdedite || Energarda || Nilsonclecio || Roberval || Cheirosa || Caue || Ermenegildo |+--------------+8 rows in set (0.00 sec)
OPERADOR ANY
Da mesma forma que o ALL, o ANY também compara elementos da consulta inicial com os elementos da subconsulta
Operadores complementares também fazem-se necessários
Assim que, pelo menos 1 elemento da subconsulta satisfaz a condição, ele já faz parte do resultado
Observação
NOT IN <> ALL
IN = ANY
SUBCONSULTAS COM MAIS DE
UM CAMPO
Subconsultas podem retornar mais de um campo
A ordem de filtro dos campos que serão referenciados na subconsulta deverá ser exatamente a mesma dos campos retornados pela subconsulta
Muito cuidado com isso!!!
SUBCONSULTAS CORRELATAS
Subconsultas vistas até agora são ditas Não Correlatas
A subconsulta é executada independentemente
Inclusive é uma forma de depuração das informações obtidas
Subconsultas correlatas possuem elementos dependentes da instrução-contêiner
Ou seja, campos da consulta principal fazem parte do critério de filtro da subconsulta
COMO FUNCIONA UMA
SUBCONSULTA CORRELATA?
Ao invés de ser executada uma única vez, antes da execução da consulta-contêiner, a subconsulta correlata é executada para cada linha-candidata
Linhas que podem ser incluídas no resultado final
É a consulta que mais exige acessos ao disco.
Portanto de menor eficiência.
Seu uso deve ser muito bem planejado, pois, em geral é possível recuperar boa parte do que se pretende usando subconsultas não correlatas
Mesmo que tabelas diferentes façam parte da subconsulta correlata
Situação: no exemplo das contas bancárias, como recuperar os códigos dos clientes que possuem saldo entre $5000 e $10000?
SUBCONSULTAS CORRELATAS
1o passo – buscar as somatórias das contas de todos os clientes
Select sum(a.avail_balance) from account a
2o passo – buscar de um determinado cliente
Select sum(a.avail_balance) from account a
where a.cust_id = ???
Porém deve-se recuperar TODOS os clientes que tiverem conta e, finalmente filtrar o valor final pelo critério escolhido
SUBCONSULTAS CORRELATAS
mysql> select c.cust_id, c.cust_type_cd, c.city-> from customer c-> where (select sum(a.avail_balance)-> from account a-> where a.cust_id = c.cust_id)-> between 5000 and 10000;
+---------+--------------+------------+| cust_id | cust_type_cd | city |+---------+--------------+------------+| 4 | I | Waltham || 7 | I | Wilmington || 11 | B | Wilmington |+---------+--------------+------------+3 rows in set (0.09 sec)
A presença do campo
c.cust_id tanto na
consulta quanto na
subconsulta torna-a
correlata
OPERADOR EXISTS
Muito utilizado em consultas correlatas
Simplesmente retorna a quantidade de registros encontrados
0, 1 ou mais registros
O conteúdo dos dados recuperados não é importante
Verifica apenas se o resultado existe ou não
EXEMPLO
É possível recuperar o número da conta e o saldo disponível das contas que possuem transação no dia 03 de maio de 2010?
1o passo – recuperar as transações que possuem determinado código de conta
Se existir alguma transação para esta conta, mostra o número da conta e o saldo existente
Como fazer?
SUBCONSULTAS CORRELATAS
mysql> select a.account_id, a.product_cd, a.cust_id, a.avail_balance-> from account a-> where EXISTS-> (select 1 from-> transaction t-> where t.account_id = a.account_id-> and t.txn_date='2008-09-22');
Empty set (0.00 sec)
mysql> select a.account_id, a.product_cd, a.cust_id, a.avail_balance-> from account a-> where EXISTS-> (select 1 from-> transaction t-> where t.account_id = a.account_id-> and t.txn_date='2010-05-03');
+------------+------------+---------+---------------+| account_id | product_cd | cust_id | avail_balance |+------------+------------+---------+---------------+| 1 | CHK | 1 | 1057.75 |+------------+------------+---------+---------------+1 row in set (0.00 sec)
A subconsulta deve
retornar algo, não
importando os valores
“Select 1” indica que se houver alguma coisa, retorna
apenas um valor „1‟. Em geral, quando usa-se EXISTS,
usa-se „select 1‟ ou „select *‟ para indicar que existem
valores
Top Related