Comandos sql e exercicios avançados
-
Upload
joel-campos -
Category
Documents
-
view
487 -
download
2
description
Transcript of Comandos sql e exercicios avançados
Junção de Tabelas
A figura abaixo resume as operações de junção:
As operações de junção dividem-se em dois grupos: horizontais e verticais.
As horizontais actuam sobre linhas enquanto as verticais actuam
sobre colunas.
Junção horizontal
Utiliza-se uma junção horizontal quando a consulta SQL requer dados de duas
ou mais tabelas. Esta é a operação que na prática tira partido do conceito "base
de dados relacional" pois permite mostrar os dados que estão armazenados em
diferentes tabelas como se estivessem armazenados numa única, desde que
essas tabelas possuam um relacionamento entre si. A tabela resultado é
construída a partir de uma das tabelas originais, acrescentando colunas da
segunda tabela, o que corresponde a um crescimento horizontal.
A norma SQL99 define a sintaxe usada pelas cláusulas do comando SELECT
para fazer os diferentes tipos de junção. A base de dados Oracle suporta esta
sintaxe desde a versão 9.0. Nas versões anteriores à 9.0 era usada uma sintaxe
antiga, que no caso da junção externa possuia uma notação proprietária. Por
razões de compatibilidade com o passado a sintaxe antiga com as extensões
proprietárias contínua disponível. Neste manual os comandos serão dados
seguindo as duas abordagens: sintaxe antiga e SQL99.
Produto cartesiano
O produto cartesiano entre dois conjuntos é um terceiro conjunto constituído
por todos os elementos do primeiro combinados com todos os elementos do
segundo.
Os comandos abaixo geram o produto cartesiado entre as tabelas EMP e DEP:
Sintaxe antiga SQL99
SELECT emp.empno,
emp.ename,
emp.deptno,
dept.deptno,
dept.dname
FROM emp, dept;
SELECT emp.empno,
emp.ename,
emp.deptno,
dept.deptno,
dept.dname
FROM emp CROSS JOIN dept;
EMPNO ENAME DEPTNO DEPTNO
DNAME
---------------------- ---------- ---------------------- -------------
--------- --------------
7369 SMITH 20 10
ACCOUNTING
7499 ALLEN 30 10
ACCOUNTING
7521 WARD 30 10
ACCOUNTING
7566 JONES 20 10
ACCOUNTING
7654 MARTIN 30 10
ACCOUNTING
7698 BLAKE 30 10
ACCOUNTING
7782 CLARK 10 10
ACCOUNTING
7788 SCOTT 20 10
ACCOUNTING
7839 KING 10 10
ACCOUNTING
7844 TURNER 30 10
ACCOUNTING
7876 ADAMS 20 10
ACCOUNTING
7900 JAMES 30 10
ACCOUNTING
7902 FORD 20 10
ACCOUNTING
7934 MILLER 10 10
ACCOUNTING
7369 SMITH 20 20
RESEARCH
7499 ALLEN 30 20
RESEARCH
7521 WARD 30 20
RESEARCH
7566 JONES 20 20
RESEARCH
7654 MARTIN 30 20
RESEARCH
7698 BLAKE 30 20
RESEARCH
7782 CLARK 10 20
RESEARCH
7788 SCOTT 20 20
RESEARCH
7839 KING 10 20
RESEARCH
7844 TURNER 30 20
RESEARCH
7876 ADAMS 20 20
RESEARCH
7900 JAMES 30 20
RESEARCH
7902 FORD 20 20
RESEARCH
7934 MILLER 10 20
RESEARCH
7369 SMITH 20 30
SALES
7499 ALLEN 30 30
SALES
7521 WARD 30 30
SALES
7566 JONES 20 30
SALES
7654 MARTIN 30 30
SALES
7698 BLAKE 30 30
SALES
7782 CLARK 10 30
SALES
7788 SCOTT 20 30
SALES
7839 KING 10 30
SALES
7844 TURNER 30 30
SALES
7876 ADAMS 20 30
SALES
7900 JAMES 30 30
SALES
7902 FORD 20 30
SALES
7934 MILLER 10 30
SALES
7369 SMITH 20 40
OPERATIONS
7499 ALLEN 30 40
OPERATIONS
7521 WARD 30 40
OPERATIONS
7566 JONES 20 40
OPERATIONS
7654 MARTIN 30 40
OPERATIONS
7698 BLAKE 30 40
OPERATIONS
7782 CLARK 10 40
OPERATIONS
7788 SCOTT 20 40
OPERATIONS
7839 KING 10 40
OPERATIONS
7844 TURNER 30 40
OPERATIONS
7876 ADAMS 20 40
OPERATIONS
7900 JAMES 30 40
OPERATIONS
7902 FORD 20 40
OPERATIONS
7934 MILLER 10 40
OPERATIONS
56 rows selected
Na sintaxe proprietária o produto cartesiano é obtido quando se faz
referencia a mais que duas tabelas e não se coloca uma condição de
JOIN na cláusula WHERE;
Na sintaxe SQL99 o produto cartesiano é obtido usando a cláusula
CROSS JOIN;
A sintaxe SQL99 é menos susceptível a erros, pois é preciso usar
explicitamente a cláusula CROSS JOIN, enquanto que na sintaxe
proprietária, se houver esquecimento da cláusula de JOIN ou erro na
sua construção, sai um produto cartesiano;
O resultado do produto cartesiano raramente é útil, pois mostra
combinações de linhas que não têm relação entre si e por isso não são
úteis para o utilizador. A sua execução causa muito I/O na base de
dados;
Junção Interna
Sumário
A junção interna é uma operação de junção horizontal entre duas tabelas, que
usa uma comparação por igualdade entre a(s) coluna(s) comum(ns).
Normalmente a(s) coluna(s) comum(ns) é(são) Foreign Key numa tabela e
Primary Key ou Unique Key na outra. A junção interna pode ser vista como
um produto cartesiano filtrado, pois exige que as linhas da tabela da esquerda
tenham correspondente na tabela da direita, sendo o valor da coluna comum
igual. O diagrama apresentado a seguir mostra como funciona a junção interna
entre duas tabelas:
A junção interna é a operação mais importante nas bases de dados relacionais,
pelo que é suportada desde sempre. A norma SQL99 propos uma nova sintaxe
para esta operação, tendo disponibilizado várias cláusulas que serão analisadas
nos exemplos abaixo, onde também faremos a comparação com a sintaxe
antiga. Os temas abordados serão:
Cláusula ON
Cláusula USING
Cláusula NATURAL JOIN
Comparação entre ON, USING e NATURAL JOIN
Sinónimos para nomes de tabelas
Junção com mais de duas tabelas
A cláusula de junção e a cláusula de filtro
A junção feita com coluna(s) UNIQUE
Cláusula ON
As tabelas EMP e DEPT possuem uma relação entre si, implementada através
da coluna comum DEPTNO. Na tabela EMP sabemos qual o número do
departamento em que o empregado trabalha. Na tabela DEPT sabemos o
número, nome e localização desse departamento. Para juntar os dois conjuntos
efectuamos uma JUNÇÃO horizontaldas duas tabelas, usando uma igualdade
de valores na coluna comum, como ilustrado nos exemplos abaixo:
Sintaxe antiga SQL99
SELECT emp.empno, SELECT emp.empno,
emp.ename,
emp.deptno,
dept.deptno,
dept.dname,
dept.loc
FROM emp, dept
WHERE emp.deptno=dept.deptno;
emp.ename,
emp.deptno,
dept.deptno,
dept.dname,
dept.loc
FROM emp
INNER JOIN dept ON
(emp.deptno=dept.deptno);
EMPNO ENAME DEPTNO DEPTNO
DNAME LOC
---------------------- ---------- ---------------------- -------------
--------- -------------- -------------
7369 SMITH 20 20
RESEARCH DALLAS
7499 ALLEN 30 30
SALES CHICAGO
7521 WARD 30 30
SALES CHICAGO
7566 JONES 20 20
RESEARCH DALLAS
7654 MARTIN 30 30
SALES CHICAGO
7698 BLAKE 30 30
SALES CHICAGO
7782 CLARK 10 10
ACCOUNTING NEW YORK
7788 SCOTT 20 20
RESEARCH DALLAS
7839 KING 10 10
ACCOUNTING NEW YORK
7844 TURNER 30 30
SALES CHICAGO
7876 ADAMS 20 20
RESEARCH DALLAS
7900 JAMES 30 30
SALES CHICAGO
7902 FORD 20 20
RESEARCH DALLAS
7934 MILLER 10 10
ACCOUNTING NEW YORK
14 rows selected
Com esta operação o utilizador consegue visualizar o nome do
empregado, o nome do departamento em que trabalha e a sua
localização, ou seja, vê os dados de duas tabelas relacionadas como se
fossem uma única;
Esta junção pode ser interpretada como um produto cartesiano ao qual
foram eliminadas as linhas que não satisfazem a condição de junção;
O comentário anterior mostra como interpretar a junção em
comparação com o produto cartesiano, mas não revela a forma como o
motor da base de dados efectivamente resolve a operação. Esta
operação é tão importante que os construtores de motores relacionais
investem muitos recursos para optimizar o desempenho, o que resulta
na existência de vários meios para executar a junção, que dependem da
dimensão das tabelas envolvidas, da existência de índices e da
selectividade das colunas comuns. Produzir um produto cartesiano e
depois filtrar linhas é um meio muito dispendioso em termos de I/O e
processamento, pelo que os motores recorrem a outros caminhos, cuja
explicação mais detalhada está fora do âmbito deste curso;
As tabelas DEPT e EMP têm em comum a coluna DEPTNO pelo que
nos comandos houve necessidade de distinguir de qual das tabelas
queremos obter a coluna. Sempre que há ambiguidade nos nomes das
colunas o utilizador é obrigado a indicar o nome da tabela a que
pertence a coluna pretendida. Por exemploEMP.DEPTNO
e DEPT.DEPTNO;
A maioria das operações de junção são internas (INNER) pelo que a
palavra reservada INNER é facultativa;
Topo
Cláusula USING
A cláusula USING está disponível na sintaxe SQL99 e pode ser usada em vez
da cláusula ON sempre que a(s) coluna(s) usada(s) na junção tenha(m) o
mesmo nome em ambas as tabelas. Esta cláusula pode ser usada mesmo que
existam outras colunas com o mesmo nome em ambas as tabelas.
No caso das tabelas EMP e DEPT a junção pode ser feita com USING:
Sintaxe antiga SQL99
SELECT emp.empno,
emp.ename,
emp.deptno,
dept.deptno,
dept.dname,
dept.loc
FROM emp, dept
WHERE emp.deptno=dept.deptno;
SELECT emp.empno,
emp.ename,
deptno,
dept.dname,
dept.loc
FROM emp
INNER JOIN dept USING (deptno);
Esta cláusula facilita a escrita do query, mas requer a validação prévia
de que a(s) coluna(s) usada(s) na junção tem(êm) o mesmo nome em
ambas as tabelas;
A cláusula USING obriga a que a(s) coluna(s) usada(s) na junção
seja(m) referenciada(s) sem o nome da tabela a que pertence(m);
Topo
Cláusula NATURAL JOIN
A cláusula NATURAL JOIN está disponível na sintaxe SQL99 e pode ser
usada em vez da cláusula ON ou em vez da cláusula USING sempre que:
A(s) coluna(s) usada(s) na junção tenha(m) o mesmo nome em ambas
as tabelas;
A(s) coluna(s) usada(s) na junção é(são) a(s) única(s) com o mesmo
nome em ambas as tabelas;
No caso das tabelas EMP e DEPT a junção pode ser feita com NATURAL
JOIN:
Sintaxe antiga SQL99
SELECT emp.empno,
emp.ename,
emp.deptno,
dept.deptno,
dept.dname,
dept.loc
FROM emp, dept
WHERE emp.deptno=dept.deptno;
SELECT emp.empno,
emp.ename,
deptno,
dept.dname,
dept.loc
FROM emp
NATURAL JOIN dept;
Esta cláusula facilita a escrita do query pois o utilizador não tem que
referir qual(ais) a(s) coluna(s) que vai usar na junção;
Esta cláusula requer a validação prévia não só de que a(s) coluna(s)
usada(s) na junção tem(êm) o mesmo nome em ambas as tabelas mas
também que é(são) a(s) única(s) coluna(s) comum(ns);
A cláusula NATURAL JOIN obriga a que a(s) coluna(s) usada(s) na
junção seja(m) referenciada(s) sem o nome da tabela a que pertence(m);
Topo
Comparação entre ON, USING e NATURAL JOIN
Consideremos as seguintes situações:
Sit
uaç
ão
Modelo entidade relacionamento Sintaxe
antiga ON
USIN
G
NAT
URA
L
JOI
N
1
SELECT *
FROM t1,
t2
WHERE
t1.t1_c1
=t2.t1_c
1;
SELECT *
FROM t1
INNER
JOIN t2
ON
(t1.t1_c
1=t2.t1_
c1);
SELECT
*
FROM
t1
INNER
JOIN
t2
USING
(t1_c1
);
SELE
CT *
FROM
t1
NATU
RAL
JOIN
t2;
2
SELECT *
FROM t3,
t4
WHERE
t3.t3_c1
=t4.t3_c
1
AND
t3.t3_c2
=t4.t3_c
2;
SELECT *
FROM t3
INNER
JOIN t4
ON
(t3.t3_c
1=t4.t3_
c1
AND
t3.t3_c2
=t4.t3_c
2);
SELECT
*
FROM
t3
INNER
JOIN
t4
USING
(t3_c1
,t3_c2
);
SELE
CT *
FROM
t3
NATU
RAL
JOIN
t4;
3
SELECT *
FROM t5,
t6
WHERE
t5.t5_c1
=t6.t6_c
2;
SELECT *
FROM t5
INNER
JOIN t6
ON
(t5.t5_c
1=t6.t6_
c2);
Não é
possív
el
Não
é
possí
vel
4
SELECT *
FROM t7,
t8
WHERE
t7.t7_c1
=t8.t7_c
1;
SELECT *
FROM t7
INNER
JOIN t8
ON
(t7.t7_c
1=t8.t7_
c1);
SELECT
*
FROM
t7
INNER
JOIN
t8
USING
(t7_c1
);
Não
é
possí
vel
Topo
Sinónimos para nomes de tabelas
O nome da tabela pode ser substituído por um sinónimo, como mostram os
exemplos abaixo:
Sintaxe antiga SQL99
SELECT e.empno,
e.ename,
e.deptno,
d.deptno,
d.dname,
d.loc
FROM emp e, dept d
WHERE e.deptno=d.deptno;
SELECT e.empno,
e.ename,
e.deptno,
d.deptno,
d.dname,
d.loc
FROM emp e
INNER JOIN dept d ON
(e.deptno=d.deptno);
A utilização de sinónimos para os nomes das tabelas apresenta as
seguintes vantagens:
Ajuda a distinguir as colunas que têm o mesmo nome nas duas tabelas.
O mesmo fim pode ser atingido usando o nome da tabela;
O query é mais rapidamente interpretado pela base de dados, pois esta
não tem duvidas de onde tem que ir buscar as colunas, pelo que poupa
processamento. Este fim também pode ser atingido recorrendo ao nome
da tabela;
Permite efectuar a junção de uma tabela com ela própria;
Topo
Junção com mais de duas tabelas
A figura abaixo mostra as relações existentes entre as tabelas EMPLOYEES,
DEPARTMENTS e LOCATIONS, pertencentes ao conjunto HR:
Este relacionamento possibilita a junção entre as 3 tabelas exemplificada pelos
comandos abaixo:
Sintaxe antiga ON USING NATURA
L JOIN
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name,
l.city,
l.state_province
FROM employees e,
departments d,
locations l
WHERE
e.department_id=d.dep
artment_id
AND
d.location_id=l.locat
ion_id;
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name,
l.city,
l.state_province
FROM employees e
INNER JOIN departments
d ON
(e.department_id=d.depa
rtment_id)
INNER JOIN locations l
ON
(d.location_id=l.locati
on_id);
SELECT
e.first_name
,
e.last_name,
department_i
d,
d.department
_name,
l.city,
l.state_prov
ince
FROM
employees e
INNER JOIN
departments
d USING
(department_
id)
INNER JOIN
locations l
USING
(location_id
);
Não é
possível
porque a
coluna
MANAGE
R_ID é
comúm a
Employees
e a
Departmen
ts e nao é
usada na
cláusula de
junção
deste
relacionam
ento
Na maior parte das situações é válido o seguinte principio: se há n
tabelas temos que usar n-1 condições de junção. Esta regra não é válida
quando existe mais que uma relação entre duas tabelas, como no nosso
exemplo, casos onde se deve aplicar o princípio abaixo;
Cada relacionamento entre duas tabelas exige uma condição de junção.
Neste exemplo consideramos o único relacionamento entre
LOCATIONS e DEPARTMENTS e nos vários relacionamentos
existentes entre EMPLOYEES e DEPARTMENTS consideramos
apenas EMP_DEPT_FK;
A condição de junção deve incluir todas as colunas usadas na junção;
Topo
A cláusula de junção e a cláusula de filtro
O facto de efectuarmos uma junção entre duas tabelas não impede que se faça
um filtro das linhas. O exemplo abaixo mostra como:
Sintaxe antiga ON USING NATURA
L JOIN
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name
FROM employees e,
departments d
WHERE
e.department_id=d.depa
rtment_id
AND e.first_name like
'Jam%';
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name
FROM employees e
INNER JOIN departments
d ON
(e.department_id=d.depa
rtment_id)
WHERE e.first_name like
'Jam%';
SELECT
e.first_name
,
e.last_name,
department_i
d,
d.department
_name
FROM
employees e
INNER JOIN
departments
d USING
(department_
id)
WHERE
e.first_name
like '%me%';
Não é
possível
porque a
coluna
MANAGE
R_ID é
comúm a
Employees
e a
Department
s e nao é
usada na
cláusula de
junção
deste
relacionam
ento
Na sintaxe antiga as condições de junção e de filtro misturam-se, sendo
necessária uma leitura mais atenta para as distinguir;
Na sintaxe SQL99 há uma separação clara entre condições de junção e
de filtro;
Topo
A junção feita com colunas UNIQUE
As boas práticas recomendam que a junção entre duas tabelas seja feita entre a
chave primária (PK - Primary Key) de uma e a chave estrangeira (FK -
Foreign Key) da outra tabela. O motor relacional do Oracle permite que a
chave primária seja substituída por uma chave alternativa. Por exemplo, em
vez do número de empregado poderíamos usar o NIF (Número de
Identificação Fiscal), desde que este seja único para cada empregado e tenha
um valor não nulo. Para isto a base de dados requer a existência de um índice
com a propriedade UNIQUE ou que seja definida a restrição UNIQUE sobre
a(s) coluna(s) envolvida(s).
Junção externa
O diagrama entidade relacionamento a seguir apresentado mostra os
relacionamentos existentes entre as tabelas EMPLOYEES e
DEPARTMENTS. Considerando apenas o relacionamento "Trabalha Em"
verificamos que um empregado pode não ter um departamento atribuído,
assim como um departamento pode não ter empregados atribuídos. Os
empregados que não têm departamento e os departamentos que não têm
empregado não aparecem no resultado de uma junção interna, mas aparecem
na junção externa. A junção externa é uma extensão da junção interna.
Junção externa à esquerda
Junção externa à direita
Junção externa FULL (à esquerda e à direita)
Junção externa à esquerda
A junção externa à esquerda estende o resultado da junção interna, pois
mostra todas as linhas que são devolvidas pela junção interna e acrescenta as
linhas da tabela da esquerda que não têm correspondência na tabela da direita.
A junção envolve sempre duas tabelas, sendo a da esquerda a que primeiro
aparece no comando. O diagrama apresentado a seguir mostra como funciona
este tipo de junção:
Os comandos apresentados a seguir mostram como fazer a junção externa à
esquerda entre as tabelas EMPLOYEES e DEPARTMENTS. Esta operação
vai mostrar as linhas obtidas pela junção interna, acrescida dos empregados
que não têm um departamento atribuído, o que é possível porque a coluna
DEPARTMENT_ID em EMPLOYEES suporta valores nulos:
Sintaxe proprietária ON USING
NATUR
AL
JOIN
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name
FROM employees e,
departments d
WHERE
e.department_id=d.depa
rtment_id (+);
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name
FROM employees e
LEFT OUTER JOIN
departments d ON
(e.department_id=d.depart
ment_id);
SELECT
e.first_name
,
e.last_name,
department_i
d,
d.department
_name
FROM
employees e
LEFT OUTER
JOIN
departments
d USING
(department_
id);
Não
aplicável
Topo
Junção externa à direita
A junção externa à direita funciona da mesma forma que a junção externa à
esquerda, mas mostra as linhas da tabela da direita que não têm
correspondência com linhas da tabela da esquerda. Este resultado pode ser
obtido por uma junção à esquerda trocando a ordem das colunas. O diagrama
apresentado a seguir descreve o funcionamento deste tipo de junção:
Os comandos apresentados a seguir mostram como fazer a junção externa à
direita entre as tabelas EMPLOYEES e DEPARTMENTS. Esta operação vai
mostrar as linhas obtidas pela junção interna, acrescida dos departamentos que
não têm um empregado atribuído:
Sintaxe
proprietária ON USING
NATURA
L JOIN
SELECT
SELECT
e.first_name,
SELECT
Não
e.first_name,
e.last_name,
d.department_i
d,
d.department_n
ame
FROM employees
e, departments
d
WHERE
e.department_i
d (+)
=d.department_
id;
e.last_name,
d.department_id,
d.department_name
FROM employees e
RIGHT OUTER JOIN departments
d ON
(e.department_id=d.department
_id);
e.first_name,
e.last_name,
department_id,
d.department_n
ame
FROM employees
e
RIGHT OUTER
JOIN
departments d
USING
(department_id
);
aplicável
Topo
Junção externa FULL (à esquerda e à direita)
A junção externa FULL mostra a soma das junções externas à esquerda e à
direita, como exemplificado no próximo diagrama:
Os comandos apresentados a seguir mostram como fazer a junção externa
FULL entre as tabelas EMPLOYEES e DEPARTMENTS:
Sintaxe
proprietária ON USING
NATURA
L JOIN
SELECT
e.first_name,
e.last_name,
d.department_i
d,
d.department_n
ame
FROM employees
SELECT
e.first_name,
e.last_name,
d.department_id,
d.department_name
FROM employees e
FULL OUTER JOIN departments d
ON
(e.department_id=d.department
_id);
SELECT
e.first_name,
e.last_name,
department_id,
d.department_n
ame
FROM employees
e
Não
aplicável
e, departments
d
WHERE
e.department_i
d
=d.department_
id (+)
UNION
SELECT
e.first_name,
e.last_name,
d.department_i
d,
d.department_n
ame
FROM employees
e, departments
d
WHERE
e.department_i
d (+)
=d.department_
id;
FULL OUTER
JOIN
departments d
USING
(department_id
);
A sintaxe proprietária não permite a junção externa em simultâneo à
esquerda e à direita, pelo que recorremos ao operador UNION que faz a
junção vertical dos dois conjuntos resultado;
O recurso ao operador UNION na sintaxe proprietária força a execução
de 2 queries para resolver o problema, ao contrário dos exemplos com
sintaxe SQL99 que resolvem com um único query;
Junção Vertical - Operadores sobre
conjuntos
O SQL disponibiliza três operadores que permitem a partir de dois conjuntos
produzir um terceiro. Estes operadores actuam sobre as colunas das tabelas de
origem, produzindo uma Junção Vertical:
UNIÃO
INTERSECÇÃO
DIFERENÇA
Estes operadores permitem obter um único conjunto resultado a partir de dois
conjuntos iniciais. São úteis na junção de diferentes consultas que se refiram a
tabelas diferentes mas que tenham colunas com o mesmo tipo de dados. A sua
utilizaçãoo segue as seguintes regras:
1. As duas instruções SELECT têm que seleccionar o mesmo número de
colunas;
2. As colunas correspondentes têm que ser do mesmo tipo de dados;
3. As linhas duplicadas são eliminadas pelo operador UNION. Se usarmos
UNION ALL os duplicados não são eliminados, o que poupa uma
operação de SORT;
4. Os nomes de coluna da primeira consulta aparecem no resultado;
5. A cláusula ORDER BY aparece no fim da instrução. Se as colunas
correspondentes dos diferentes SELECT's tiverem nomes diferentes, a
referêcia à(s) coluna(s) deverá ser feita por número de posição;
6. As instruções SELECT são executadas de cima para baixo;
7. Se forem utilizados vários operadores de conjunto é possivel
usar parentesis para definir prioridades de execução;
UNIÃO (UNION)
O operador UNION permite obter a reunião de dois conjuntos:
O comando abaixo apresenta os nomes e salários dos empregados das tabelas
EMP e EMPLOYEES. São duas consultas unidas numa única.
select ename, sal
from emp
UNION
select first_name, salary
from employees;
O comando UNION elimina automaticamente as linhas repetidas. Se
pretendermos que estas apareçam teremos que utilizar UNION ALL:
select job
from emp
UNION
select job_id
from employees;
JOB
----------
AC_ACCOUNT
AC_MGR
AD_ASST
AD_PRES
AD_VP
ANALYST
CLERK
FI_ACCOUNT
FI_MGR
HR_REP
IT_PROG
MANAGER
MK_MAN
MK_REP
PRESIDENT
PR_REP
PU_CLERK
PU_MAN
SALESMAN
SA_MAN
SA_REP
SH_CLERK
ST_CLERK
ST_MAN
24 rows selected
select job
from emp
UNION ALL
select job_id
from employees;
JOB
----------
CLERK
SALESMAN
SALESMAN
MANAGER
SALESMAN
MANAGER
MANAGER
ANALYST
PRESIDENT
SALESMAN
CLERK
CLERK
ANALYST
CLERK
AC_ACCOUNT
AC_MGR
AD_ASST
AD_PRES
AD_VP
AD_VP
FI_ACCOUNT
FI_ACCOUNT
FI_ACCOUNT
FI_ACCOUNT
FI_ACCOUNT
FI_MGR
HR_REP
IT_PROG
IT_PROG
IT_PROG
IT_PROG
IT_PROG
MK_MAN
MK_REP
PR_REP
PU_CLERK
PU_CLERK
PU_CLERK
PU_CLERK
PU_CLERK
PU_MAN
SA_MAN
SA_MAN
SA_MAN
SA_MAN
SA_MAN
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SA_REP
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
SH_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_CLERK
ST_MAN
ST_MAN
ST_MAN
ST_MAN
ST_MAN
121 rows selected
O operador UNION ALL não respeita a teoria de conjuntos, pois
permite a repetição de elementos. Foi criado por uma questão de
desempenho, já que evita ao motor de base de daos as operações
ordenação e filtro. Deve ser usado quando não faça difrença trabalhar
com elementos repetidos;
Topo
INTERSECÇÃO (INTERSECT)
O operador INTERSECT permite obter a intersecção entre dois conjuntos:
O comando abaixo permite listar os salários que existem em EMP e em
EMPLOYEES:
select sal
from emp
INTERSECT
select salary
from employees;
SAL
----------------------
3000
1 rows selected
Topo
DIFERENÇA (MINUS)
O operador MINUS permite obter a diferença entre dois conjuntos:
O comando abaixo permite listar os salários que estão em EMP e não estão em
EMPLOYEES:
select sal
from emp
MINUS
select salary
from employees;
SAL
----------------------
800
950
1100
1250
1300
1500
1600
2450
2850
2975
5000
11 rows selected
Exercícios sobre junção de tabelas
1. Liste todos os empregados e respectivos nomes de departamento, por
ordem do nome de departamento;
2. Liste o nome, número e nome de departamento de todos os
empregados;
3. Liste o nome, departamento e localidade do departamento dos
empregados cujo salário mensal seja superior a 1500;
4. Produza uma lista que mostre o nível salarial (GRADE) de cada
empregado;
5. Produza uma lista dos empregados com nível salarial 3;
6. Mostre todos os empregados de Dallas (Dept Loc);
7. Liste nome, função, salário, nível (GRADE) e nome de departamento
para todos os empregados, excepto empregados de escritório (CLERK).
Ordene por salário apresentando primeiro o mais elevado;
8. Liste o nome, função, salário anual, número de departamento, nome de
departamento e nível salarial (grade) para os empregados que ganham
mais de 36000 por ano (14 vezes o salário mais a comissão) ou que
sejam empregados de escritório (CLERK);
9. Liste todos os departamentos que não têm empregados;
10. Liste o nome e número de empregado juntamente com o nome e
número do seu manager;
11. Modifique a solução da questão 10 de forma a visualizar KING que não
tem manager;
12. Encontre o departamento que contratou funcionários na primeira
metade de 1981 e na primeira metade de 1982;
13. Encontre todos os empregados que entraram para a empresa antes do
seu manager;
14. Encontre um outro método de consulta para a questãoa 9 utilizando o
operador MINUS.
Soluções dos exercícios sobre junção de
tabelas
15.
16. 1.
17. Solução usando a sintaxe tradicional: 18. select e.ename, e.deptno, d.dname
19. from emp e, dept d
20. where e.deptno=d.deptno
21. order by d.dname;
22. Solução usando a sintaxe SQL99: 23. select e.ename, e.deptno, d.dname
24. from emp e
25. inner join dept d on (e.deptno=d.deptno)
26. order by d.dname;
27.
28. 2.
29. Solução usando a sintaxe tradicional: 30. select e.ename, d.deptno, d.dname
31. from emp e, dept d
32. where e.deptno=d.deptno;
33. Solução usando a sintaxe SQL99: 34. select e.ename, d.deptno, d.dname
35. from emp e
36. inner join dept d on (e.deptno=d.deptno);
37.
38. 3.
39. Solução usando a sintaxe tradicional: 40. select e.ename,d.dname,d.loc
41. from emp e, dept d
42. where e.deptno = d.deptno
43. and sal > 1500;
44. Solução usando a sintaxe SQL99: 45. select e.ename,d.dname,d.loc
46. from emp e
47. inner join dept d on (e.deptno = d.deptno)
48. where sal > 1500;
49.
50. 4.
51. Solução usando a sintaxe tradicional: 52. select ename, job, sal, grade
53. from emp, salgrade
54. where sal between salgrade.losal and salgrade.hisal;
55. Solução usando a sintaxe SQL99: 56. select ename, job, sal, grade
57. from emp
58. inner join salgrade on (sal between salgrade.losal and
salgrade.hisal);
59.
60. 5.
61. Solução usando a sintaxe tradicional: 62. select ename, job, sal, grade
63. from emp, salgrade
64. where sal between salgrade.losal and salgrade.hisal
65. and grade = 3;
66. Solução usando a sintaxe SQL99: 67. select ename, job, sal, grade
68. from emp
69. inner join salgrade on (sal between salgrade.losal and
salgrade.hisal)
70. where grade = 3;
71.
72. 6.
73. Solução usando a sintaxe tradicional: 74. select emp.ename, emp.sal, dept.loc
75. from emp, dept
76. where emp.deptno=dept.deptno
77. and dept.loc = 'DALLAS';
78. Solução usando a sintaxe SQL99: 79. select emp.ename, emp.sal, dept.loc
80. from emp
81. inner join dept on (emp.deptno=dept.deptno)
82. where dept.loc = 'DALLAS';
83.
84. 7.
85. Solução usando a sintaxe tradicional: 86. select e.ename, e.job, e.sal, s.grade, d.dname
87. from emp e, salgrade s, dept d
88. where e.sal between s.losal and s.hisal
89. and e.deptno=d.deptno
90. and e.job !='CLERCK'
91. order by e.sal desc;
92. Solução usando a sintaxe SQL99: 93. select e.ename, e.job, e.sal, s.grade, d.dname
94. from emp e
95. inner join salgrade s on (e.sal between s.losal and s.hisal)
96. inner join dept d on (e.deptno=d.deptno)
97. where e.job != 'CLERCK'
98. order by e.sal desc;
99.
100. 8.
101. Solução usando a sintaxe tradicional: 102. select e.ename, e.job, e.sal*14+nvl(e.comm,0), d.deptno,
d.dname, s.grade
103. from emp e, salgrade s, dept d 104. where e.sal between s.losal 105. and s.hisal and e.deptno=d.deptno 106. and (e.sal*14+nvl(e.comm,0) > 36000 or e.job = 'CLERK');
107. Solução usando a sintaxe SQL99: 108. select e.ename, e.job, e.sal, s.grade, d.dname 109. from emp e 110. inner join salgrade s on (e.sal between s.losal and s.hisal) 111. inner join dept d on (e.deptno=d.deptno) 112. where e.job != 'CLERCK' 113. order by e.sal desc;
114.
115. 9.
116. Solução usando a sintaxe tradicional. O operador (+) coloca-se
sempre do lado fraco, isto é, do lado onde pode haver uma linha NULL: 117. select d.deptno, d.dname 118. from emp e, dept d 119. where e.deptno (+) = d.deptno 120. and e.ename is null;
121. Solução usando a sintaxe SQL99: 122. select d.deptno, d.dname 123. from emp e 124. right outer join dept d on (e.deptno = d.deptno) 125. where e.ename is null;
126.
127. 10.
128. Solução usando a sintaxe tradicional: 129. select e.empno as empregado_numero, e.ename as empregrado_nome, 130. m.empno as manager_numero, m.ename as manager_nome 131. from emp e, emp m 132. where e.mgr = m.empno;
133. Solução usando a sintaxe SQL99: 134. select e.empno as empregado_numero, e.ename as empregrado_nome, 135. m.empno as manager_numero, m.ename as manager_nome 136. from emp e 137. inner join emp m on (e.mgr = m.empno)
138.
139. 11.
140. Solução usando a sintaxe tradicional. O operador (+) coloca-se
sempre do lado fraco, isto é, do lado onde pode haver uma linha NULL. 141. select e.ename,e.empno,e.mgr,m.ename,m.empno 142. from emp e, emp m 143. where e.mgr=m.empno (+);
144. Solução usando a sintaxe SQL99: 145. select e.ename,e.empno,e.mgr,m.ename,m.empno 146. from emp e 147. left outer join emp m on (e.mgr=m.empno (+));
148.
149. 12.
150. Solução usando a sintaxe tradicional: 151. select e.deptno, d.dname 152. from emp e, dept d 153. where e.deptno=d.deptno 154. and e.hiredate between to_date('1981-01-01','YYYY-MM-DD') and
to_date('1981-06-30','YYYY-MM-DD')
155. intersect 156. select e.deptno, d.dname 157. from emp e, dept d 158. where e.deptno=d.deptno 159. and hiredate between to_date('1982-01-01','YYYY-MM-DD') and
to_date('1982-06-30','YYYY-MM-DD');
160. Usando sintaxe SQL99 161. select e.deptno, d.dname 162. from emp e 163. inner join dept d on (e.deptno=d.deptno) 164. where e.hiredate between to_date('1981-01-01','YYYY-MM-DD') and
to_date('1981-06-30','YYYY-MM-DD')
165. intersect 166. select e.deptno, d.dname 167. from emp e 168. inner join dept d on (e.deptno=d.deptno) 169. where hiredate between to_date('1982-01-01','YYYY-MM-DD') and
to_date('1982-06-30','YYYY-MM-DD');
170.
171. 13.
172. Solução usando a sintaxe tradicional: 173. select e.ename as empregado_nome, e.hiredate as empregado_data, 174. m.ename as manager_nome, m.hiredate as manager_data 175. where e.mgr=m.empno 176. and e.hiredate > m.hiredate;
177. Usando sintaxe SQL99 178. select e.ename as empregado_nome, e.hiredate as empregado_data, 179. m.ename as manager_nome, m.hiredate as manager_data 180. from emp e 181. inner join emp m on (e.mgr=m.empno) 182. and e.hiredate > m.hiredate;
183.
184. 14.
185. Retirar à lista dos departamentos aqueles que têm empregados.
186. Solução usando a sintaxe tradicional:
187. select deptno, dname 188. from dept 189. minus 190. select e.deptno, d.dname 191. from emp e, dept d 192. where e.deptno=d.deptno;
193. Usando sintaxe SQL99 194. select deptno, dname 195. from dept 196. minus 197. select e.deptno, d.dname 198. from emp e 199. inner join dept d on (e.deptno=d.deptno);
Subconsultas simples e correlacionadas
Uma subconsulta é uma instrução SELECT que está encadeada dentro de
outra instrução SELECT. A consulta interior é designada por selecção interna
e é executada em primeiro lugar, sendo o seu resultado utilizado para
completar a consulta principal ou externa. A utilização de subconsultas
permite construir comandos potentes a partir de comandos mais simples.
Na construção de subconsultas devem ser seguidas as seguintes linhas de
orientação:
A consulta interna deverá ser colocada entre parentisis e terá que estar
no lado direito da condição;
Desde a versão 8.1.7 do motor Oracle que as subconsultas podem ter
uma cláusula ORDER BY;
As subconsultas podem devolver uma ou mais linhas, uma ou mais
colunas. Se devolverem várias colunas então terão que estar pela
mesma ordem que as colunas que apareçam na cláusula de condição da
consulta externa (ou principal). O tipo de dados e o número de colunas
têm também que corresponder;
As subconsultas podem utilizar operadores lógicos, operadores de SQL,
operadores ANY e ALL e operadores de conjunto;
As subconsultas podem ser utilizadas em instruções de SELECT,
UPDATE, DELETE, INSERT e CREATE TABLE;
Existem dois tipos de subconsultas:
Simples
Correlacionadas
Subconsulta simples
Suponha que pretende encontrar o(s) empregado(s) que ganha(m) o salário
mais baixo na empresa, desconhecendo a quantia em causa. O problema pode
resolver-se em dois passos:
Encontrar o salário mais baixo;
Encontrar o(s) empregado(s) que ganha(m) o salário mais baixo;
Para o primeiro passo usamos a consulta abaixo:
select min(sal)
from emp;
MIN(SAL)
----------------------
800
1 rows selected
Para o segundo passo usamos a consulta abaixo:
select ename, job, sal
from emp
where sal = 800;
ENAME JOB SAL
---------- --------- ----------------------
SMITH CLERK 800
1 rows selected
Os dois queries podem ser juntos num só, usando uma subconsulta:
select ename, job, sal
from emp
where sal = (select min(sal)
from emp);
ENAME JOB SAL
---------- --------- ----------------------
SMITH CLERK 800
1 rows selected
A consulta interior é executada em primeiro lugar produzindo um resultado
(800). O bloco externo é depois executado, utilizando o valor devolvido pela
consulta interna para completar a sua condição de pesquisa.
O exemplo abaixo procura todos os empregados que executam a mesma
função que BLAKE:
select ename,job
from emp
where job = (select job
from emp
where ename = 'BLAKE');
EENAME JOB
---------- ---------
JONES MANAGER
BLAKE MANAGER
CLARK MANAGER
3 rows selected
Na consulta anterior o programador corre um risco: a consulta interna
pesquisa por nome, que não é uma coluna UNIQUE e portanto não há
garantias de que devolva apenas um valor. Se devolver mais que um
valor a consulta toda dá um erro, por causa da comparação feita com =;
Para resolver este problema podemos recorrer ao operador ANY, que
será visto mais à frente;
Topo
Subconsultas correlacionadas
Uma subconsulta correlacionada é executada de forma diferente da
subconsulta simples. Nestas consultas o subquery precisa de um dado que vem
do query principal, pelo que o SELECT interno é executado tantas vezes
quantas as linhas que são processadas no query principal.
A lista abaixo contem os passos necessários para executar uma consulta
correlacionada:
Obter uma linha candidata a partir da consulta externa;
Executar a consulta interna utilizando o valor da linha candidata;
Utilizar o valor ou valores resultantes da consulta interna para
qualificar ou desqualificar a linha candidata;
Repetir para a próxima linha até que não haja mais linhas candidatas;
A consulta abaixo pretende encontrar os empregados que ganham um salário
superior ao salário médio do respectivo departamento:
select e1.empno, e1.ename, e1.sal, e1.deptno
from emp e1
where e1.sal > (select avg(e2.sal)
from emp e2
where e2.deptno = e1.deptno);
EMPNO ENAME SAL DEPTNO
---------------------- ---------- ---------------------- -------------
---------
7499 ALLEN 1600 30
7566 JONES 2975 20
7698 BLAKE 2850 30
7788 SCOTT 3000 20
7839 KING 5000 10
7902 FORD 3000 20
6 rows selected
Para identificar que se trata de uma subconsulta correlacionada é
preciso reparar na utilização de uma coluna da tabela do SELECT
externo na cláusula WHERE do SELECT interno;
O pseudónimo de tabela é utilizado para evitar ambiguidade nos nomes
das colunas, pois tanto a consulta interna como a externa usam a
mesma tabela;
Subconsulta que devolve várias linhas -
operadores do SQL
Os exemplos de subconsulta que vimos até agora devolvem apenas uma linha.
Mas uma subconsulta pode devolver várias linhas, o que obriga a consulta
externa a ter cuidados especiais e a recorrer aos operadores do SQL:
IN
ANY (SOME)
ALL
EXISTS
IN
Quando a subconsulta devolve várias linhas o operador IN pode ser usado
para validar se uma linha da consulta externa está presente no conjunto criado
pela subconsulta. Devolve TRUE se o(s) valor(es) usado(s) na consulta
externa está(ão) incluído(s) no conjunto devolvido pela consulta interna. Este
operador pode ser negado com NOT.
Suponha que pretende determinar os empregados que ganham o salário mais
baixo em cada função, usando a tabela EMPLOYEES. A consulta abaixo tenta
responder a esta pergunta, mas sem sucesso.
select first_name,salary,job_id
from employees
where salary in (select min(salary)
from employees
group by job_id);
FIRST_NAME SALARY JOB_ID
-------------------- ---------------------- ----------
Nandita 4200 SH_CLERK
Diana 4200 IT_PROG
Shelley 12000 AC_MGR
Alberto 12000 SA_MAN
Nancy 12000 FI_MGR
William 8300 AC_ACCOUNT
Kevin 5800 ST_MAN
Ellen 11000 SA_REP
Gerald 11000 SA_MAN
Den 11000 PU_MAN
Jennifer 4400 AD_ASST
Lex 17000 AD_VP
Neena 17000 AD_VP
Randall 2500 SH_CLERK
Martha 2500 SH_CLERK
Peter 2500 ST_CLERK
Joshua 2500 ST_CLERK
James 2500 ST_CLERK
Karen 2500 PU_CLERK
Luis 6900 FI_ACCOUNT
Clara 10500 SA_REP
Eleni 10500 SA_MAN
Michael 13000 MK_MAN
Hermann 10000 PR_REP
Harrison 10000 SA_REP
Janette 10000 SA_REP
Peter 10000 SA_REP
Steven 24000 AD_PRES
Sundita 6100 SA_REP
Pat 6000 MK_REP
Bruce 6000 IT_PROG
TJ 2100 ST_CLERK
Susan 6500 HR_REP
Shanta 6500 ST_MAN
34 rows selected
O resultado obtido não está correcto pois a consulta nãogarante que o
salário mínimo encontrado na subconsulta se refere ao departamento
para o qual trabalha o empregado da consulta externa;
O salário mínimo da função SA_MAN é 10500. O empregado Alberto,
com a função SA_MAN ganha 12000, que é acima do mínimo, mas
aparece no resultado da consulta. Isto porque o seu salário é igual ao
mínimo da função FI_MGR;
A forma de associar a função ao salário mínimo é devolver e comparar o par
de valores, como no exemplo abaixo:
select first_name,salary,job_id
from employees
where (job_id,salary) in (select job_id,min(salary)
from employees
group by job_id);
FIRST_NAME SALARY JOB_ID
-------------------- ---------------------- ----------
Diana 4200 IT_PROG
Shelley 12000 AC_MGR
William 8300 AC_ACCOUNT
Kevin 5800 ST_MAN
Den 11000 PU_MAN
Jennifer 4400 AD_ASST
Neena 17000 AD_VP
Lex 17000 AD_VP
Martha 2500 SH_CLERK
Randall 2500 SH_CLERK
Luis 6900 FI_ACCOUNT
Nancy 12000 FI_MGR
Karen 2500 PU_CLERK
Eleni 10500 SA_MAN
Michael 13000 MK_MAN
Hermann 10000 PR_REP
Steven 24000 AD_PRES
Sundita 6100 SA_REP
Pat 6000 MK_REP
TJ 2100 ST_CLERK
Susan 6500 HR_REP
21 rows selected
Topo
ANY (SOME)
O operador ANY (e o seu sinónimo SOME) permite a uma consulta externa
fazer comparações usando < ou > com os elementos de um conjunto
devolvido pela subconsulta. Este operador devolve TRUE se uma das linhas
do conjunto satisfaz a condição, ou seja, devolve FALSE se nenhuma satisfaz
a condição. Este operador pode ser negado com NOT.
A consulta abaixo devolve os empregados que ganham mais que algum
empregado do departamento 30. Isto é o mesmo que afirmar que procuramos
os que ganham mais que o salário mínimo do departamento 30.
select ename, sal, job, deptno
from emp
where sal > ANY (select distinct sal
from emp
where deptno=30);
ENAME SAL JOB DEPTNO
---------- ---------------------- --------- ----------------------
KING 5000 PRESIDENT 10
FORD 3000 ANALYST 20
SCOTT 3000 ANALYST 20
JONES 2975 MANAGER 20
BLAKE 2850 MANAGER 30
CLARK 2450 MANAGER 10
ALLEN 1600 SALESMAN 30
TURNER 1500 SALESMAN 30
MILLER 1300 CLERK 10
WARD 1250 SALESMAN 30
MARTIN 1250 SALESMAN 30
ADAMS 1100 CLERK 20
12 rows selected
A comparação '= ANY' pode ser usada, mas é equivalente a IN;
Ao utilizar ANY é frequente recorrer à cláusula DISTINCT, para evitar
linhas repetidas e assim tornar a avaliação da expressão lógica mais
eficiente;
Topo
ALL
O operador ALL permite a uma consulta externa fazer comparações usando <
ou > com os elementos de um conjunto devolvido pela subconsulta. Este
operador devolve TRUE se todas as linhas do conjunto satisfazem a condição,
ou seja, devolve FALSE se alguma linha não a satisfaz. Este operador pode
ser negado com NOT.
A consulta abaixo devolve os empregados que ganham mais que todos os
empregados do departamento 30. Isto é o mesmo que afirmar que procuramos
os que ganham mais que o salário máximo do departamento 30.
select ename, sal, job, deptno
from emp
where sal > ALL (select distinct sal
from emp
where deptno=30);
ENAME SAL JOB DEPTNO
---------- ---------------------- --------- ----------------------
JONES 2975 MANAGER 20
SCOTT 3000 ANALYST 20
KING 5000 PRESIDENT 10
FORD 3000 ANALYST 20
4 rows selected
Topo
EXISTS
O operador EXISTS permite à consulta externa verificar se a consulta interna
devolveu alguma linha. Não se preocupa com o valor das linhas, mas sim com
a cardinalidade do conjunto. Devolve TRUE se a cardinalidade for superior a
0 (zero) e FALSE caso seja igual a 0 (zero). Este operador pode ser negado
com NOT.
O exemplo abaixo procura os empregados que tenham pelo menos um
subordinado:
select m.empno,m.ename,m.job,m.deptno
from emp m
where exists (select e.empno
from emp e
where e.mgr=m.empno)
EMPNO ENAME JOB DEPTNO
---------------------- ---------- --------- ----------------------
7902 FORD ANALYST 20
7698 BLAKE MANAGER 30
7839 KING PRESIDENT 10
7566 JONES MANAGER 20
7788 SCOTT ANALYST 20
7782 CLARK MANAGER 10
6 rows selected
Temos uma subconsulta correlacionada, onde o SELECT externo
selecciona os managers (m - tabela manager) enquanto o SELECT
interno selecciona os empregados desse manager (e - tabela
empregado);
O exemplo abaixo procura todos os departamentos que não possuem
empregados:
select d.deptno, d.dname
from dept d
where not exists (select deptno
from emp e
where e.deptno=d.deptno);
DEPTNO DNAME
---------------------- --------------
40 OPERATIONS
1 rows selected
Recorremos uma subconsulta correlacionada. A conculta externa
percorre todos os departamentos. A consulta interna valida se o
departamento tem empregados.
O query interno necessita devolver um valor que não tem que ser a coluna que
está em causa. O exemplo anterior pode ser substituído por este:
select d.deptno, d.dname
from dept d
where not exists (select 1
from emp e
where e.deptno=d.deptno);
DEPTNO DNAME
---------------------- --------------
40 OPERATIONS
1 rows selected
Uma consulta ao dicionário de dados mostra que o relacionamento entre as
tabelas EMP e DEPT não está assegurado por uma restrição definida no motor
da base de dados. Isto significa que é possível que exista um empregado que
trabalhe num departamento que não esteja definido na tabela DEPT. A
consulta abaixo pesquisa isso:
select e.empno, e.ename, e.deptno
from emp e
where not exists (select deptno
from dept
where dept.deptno=e.deptno);
EMPNO ENAME DEPTNO
---------------------- ---------- ----------------------
0 rows selected
Subconsulta e cláusulas da instrução
SELECT
Uma subconsulta pode ser colocada em vários pontos da instrução SELECT:
WHERE
HAVING
FROM
SELECT
Subconsulta na cláusula WHERE
Nos exemplos apresentados até aqui a subconsulta aparece na cláusula
WHERE.
O exemplo abaixo procura todos os empregados que executam a mesma
função que BLAKE (subconsulta simples):
select ename,job
from emp
where job = (select job
from emp
where ename = 'BLAKE');
EENAME JOB
---------- ---------
JONES MANAGER
BLAKE MANAGER
CLARK MANAGER
3 rows selected
A consulta abaixo procura os empregados que ganham um salário superior ao
salário médio do respectivo departamento (subconsulta correlacionada):
select e1.empno, e1.ename, e1.sal, e1.deptno
from emp e1
where e1.sal > (select avg(e2.sal)
from emp e2
where e2.deptno = e1.deptno);
EMPNO ENAME SAL DEPTNO
---------------------- ---------- ---------------------- -------------
---------
7499 ALLEN 1600 30
7566 JONES 2975 20
7698 BLAKE 2850 30
7788 SCOTT 3000 20
7839 KING 5000 10
7902 FORD 3000 20
6 rows selected
Topo
Subconsulta na cláusula HAVING
Uma subconsulta pode ser colocada na cláusula HAVING.
O exemplo abaixo determina os departamentos cujo salário médio é superior
ao do departamento 30:
select deptno, avg(sal)
from emp
group by deptno
having avg(sal) > (select avg(sal)
from emp
where deptno=30);
DEPTNO AVG(SAL)
---------------------- ----------------------
20 2175
10 2916,666666666666666666666666666666666667
2 rows selected
A consulta interna determina o salário médio do departamento 30;
A consulta externa determina os salários médios de todos os
departamentos mas só mostra os que têm valor superior ao devolvido
pela subconsulta;
O exemplo abaixo determina a função com o salário médio mais elevado:
select job, avg(sal)
from emp
group by job
having avg(sal) = (select max(avg(sal))
from emp
group by job);
JOB AVG(SAL)
--------- ----------------------
PRESIDENT 5000
1 rows selected
A consulta interna começa por determinar o salário médio de cada
função, indo depois determinar o maior salário de entre as médias;
A consulta externa determina o nome da função e respectivo salário
médio, só mostrando aqueles que igualam o valor devolvido pela
subconsulta;
Topo
Subconsulta na cláusula FROM
Uma subconsulta pode ser colocada na cláusula FROM, o que é o mesmo que
referir uma view (vista) ou uma tabela virtual.
O exemplo abaixo determina os 5 empregados que têm o salário mais elevado:
select *
from (select ename, sal
from emp
order by sal desc)
where rownum <=5;
ENAME SAL
---------- ----------------------
KING 5000
SCOTT 3000
FORD 3000
JONES 2975
BLAKE 2850
5 rows selected
A subconsulta lista os salários por ordem decrescente, criando uma
tabela virtual;
A consulta externa lista a tabela virtual gerada anteriormente
considerando apenas as 5 primeiras linhas;
A consulta abaixo lista os salários máximos da tabela EMP e EMPLOYEES
usando apenas um query e mostrando os resultados numa linha única:
select
e1.c1,
e2.c1
from
(select max(sal) c1 from emp) e1 ,
(select max(salary) c1 from employees) e2;
C1 C1
---------------------- ----------------------
5000 24000
1 rows selected
Cada consulta interna devolve um valor que é considerado uma tabela
virtual. Cada tabela virtual recebe um nome (e1 e e2);
O valor devolvido em cada consulta interna é colocado numa coluna
com o nome c1;
A consulta externa produz o produto cartesiano entre as tabelas virtuais.
Cada uma tem uma linha, pelo que o resultado tem cardinalidade 1;
Topo
Subconsulta na cláusula SELECT
As subconsultas podem ser colocadas na cláusula SELECT.
O exemplo abaixo pretende listar os salários máximos da tabela EMP e
EMPLOYEES usando apenas um query e mostrando os resultados numa linha
única:
select
(select max(sal) from emp),
(select max(salary) from employees)
from
dual;
(SELECTMAX(SAL)FROMEMP) (SELECTMAX(SALARY)FROMEMPLOYEES)
----------------------- --------------------------------
5000 24000
1 rows selected
O exemplo abaixo considera apenas os empregados do departamento 20 que
executam a função 'CLERK'. Pretende mostrar o salário de cada um e
compará-lo com a média da função e a média do departamento.
select
ename,
sal,
job,
(select round(avg(sal)) from emp where job='CLERK') "Avg_Sal_Job",
deptno,
(select round(avg(sal)) from emp where deptno=20) "Avg_Sal_Deptno"
from emp
where job='CLERK'
and deptno=20;
ENAME SAL JOB Avg_Sal_Job
DEPTNO Avg_Sal_Deptno
---------- ---------------------- --------- ---------------------- ---
------------------- ----------------------
SMITH 800 CLERK 1038 20
2175
ADAMS 1100 CLERK 1038 20
2175
2 rows selected
A primeira subconsulta determina a média de salários para a função
enquanto a segunda determina a média do departamento;
A consulta exterior usa os valores anteriores no meio dos valores de
cada linha da tabela que satisfaz a condição de filtro;
Estas subconsultas são simples (não correlacionadas);
Vamos generalizar o exemplo anterior para todos os empregados da empresa,
o que nos obriga a considerar todas as funções e todos os departamentos.
Vamos recorrer a subconsultas correlacionadas.
select
e1.ename,
e1.sal,
e1.job,
(select round(avg(e2.sal)) from emp e2 where e2.job=e1.job)
"Avg_Sal_Job",
e1.deptno,
(select round(avg(e3.sal)) from emp e3 where e3.deptno=e1.deptno)
"Avg_Sal_Deptno"
from emp e1;
ENAME SAL JOB Avg_Sal_Job
DEPTNO Avg_Sal_Deptno
---------- ---------------------- --------- ---------------------- ---
------------------- ----------------------
SMITH 800 CLERK 1038 20
2175
ALLEN 1600 SALESMAN 1400 30
1567
WARD 1250 SALESMAN 1400 30
1567
JONES 2975 MANAGER 2758 20
2175
MARTIN 1250 SALESMAN 1400 30
1567
BLAKE 2850 MANAGER 2758 30
1567
CLARK 2450 MANAGER 2758 10
2917
SCOTT 3000 ANALYST 3000 20
2175
KING 5000 PRESIDENT 5000 10
2917
TURNER 1500 SALESMAN 1400 30
1567
ADAMS 1100 CLERK 1038 20
2175
JAMES 950 CLERK 1038 30
1567
FORD 3000 ANALYST 3000 20
2175
MILLER 1300 CLERK 1038 10
2917
14 rows selected
Repare como os sinónimos do nome de tabela são usados para
correlacionar as consultas e eliminar a ambiguidade na referência ao
nome das colunas;
Subconsulta e encadeamento múltiplo
Uma subconsulta pode receber outra, pelo que as subconsultas podem ser
encadeadas umas dentro das outras até um limite de 255 níveis (Oracle
SGBDR versão 8.0).
O exemplo abaixo determina o nome, função e data de admissão dos
empregados cujo salário é superior ao salário mais elevado do departamento
'SALES':
select ename, job, hiredate, sal
from emp
where sal > (select max(sal)
from emp
where deptno = (select deptno
from dept
where dname = 'SALES'));
ENAME JOB HIREDATE SAL
---------- --------- ------------------------- ----------------------
JONES MANAGER 81.04.02 2975
SCOTT ANALYST 82.12.09 3000
KING PRESIDENT 81.11.17 5000
FORD ANALYST 81.12.03 3000
4 rows selected
A subconsulta que será feita em primeiro lugar é a que está mais abaixo
e à direita e vai determinar o número do departamento que tem o nome
'SALES';
Em seguida vamos determinar a média de salários desse departamento;
Por último vamos determinar quais os empregados que ganham mais
que essa média;
Exercícios sobre subconsultas
1. Encontre os empregados que ganham o salário mais alto em cada tipo
de função (JOB).
2. Encontre os empregados que ganham o salário mais baixo em cada
função. Visualize o resultado por ordem crescente de salário.
3. Encontre os empregados mais recentes em cada departamento. Ordene
por data de admissão.
4. Encontre o nome, salário e número de departamento dos empregados
que ganham um salário maior que a média do respectivo departamento.
Ordene por número de departamento.
5. Liste todos os departamentos que não possuem empregados. Utilize
uma subconsulta.
6. Determine qual o departamento com o MAIOR encargo anual de
remunerações (14 vezes o salário mais a comissão).
7. Em que ano entraram mais pessoas para a empresa? Visualize o ano e
número de empregados.
8. Modifique a questão 4 para apresentar também o valor do salário médio
para o departamento.
9. Escreva uma consulta para visualizar um '*' ao lado da linha do
empregado mais recente. Visualize ENAME, HIREDATE e a coluna
(maxdate) com o '*'.
10. Quem são os 3 empregados mais bem pagos da companhia ?
Soluções dos exercícios sobre
subconsultas
11.
12. 1. 13. select job,ename,sal
14. from emp
15. where (sal,job) in (select max(sal),job
16. from emp
17. group by job);
18. 2. 19. select job,ename,sal
20. from emp
21. where (sal,job) in (select min(sal),job
22. from emp
23. group by job)
24. order by sal;
25. 3. 26. select ename,hiredate,deptno
27. from emp
28. where (hiredate,deptno) in (select max(hiredate),deptno
29. from emp
30. group by deptno)
31. order by hiredate;
32. 4. 33. select e.ename, e.sal, e.deptno
34. from emp e
35. where e.sal > (select avg(e2.sal)
36. from emp e2
37. where e2.deptno= e.deptno)
38. order by e.deptno;
39. 5. 40. select d.deptno, d.dname
41. from dept d
42. where not exists (select e.empno
43. from emp e
44. where e.deptno = d.deptno);
45. 6. 46. define anual = sal*14+nvl(comm,0);
47.
48. select deptno, sum(&anual)
49. from emp
50. group by deptno
51. having sum(&anual)= (select max(sum(&anual))
52. from emp
53. group by deptno);
54. 7. 55. select to_char(hiredate,'YYYY'), count(empno)
56. from emp
57. group by to_char(hiredate,('YYYY'))
58. having count(empno) = (select max(count(empno))
59. from emp
60. group by to_char(hiredate,'YYYY'));
61. 8. 62. select e.ename, e.sal, e.deptno, avg(a.sal)
63. from emp e, emp a
64. where e.deptno=a.deptno
65. and e.sal > (select avg(sal)
66. from emp
67. where deptno=e.deptno)
68. group by e.ename, e.sal, e.deptno;
69. Outra solução poderá ser a apresentada a seguir, que usa um subquery
na clausula SELECT: 70. select e.ename, e.sal, e.deptno, (select avg(e2.sal)
71. from emp e2
72. where e2.deptno= e.deptno)
73. from emp e
74. where e.sal > (select avg(e2.sal)
75. from emp e2
76. where e2.deptno= e.deptno)
77. order by e.deptno;
78. 9. 79. select ename, hiredate, '*'
80. from emp
81. where hiredate = (select max(hiredate) from emp)
82. union
83. select ename, hiredate, ' '
84. from emp
85. where hiredate <> (select max(hiredate) from emp);
86. 10. 87. select *
88. from (select *
89. from emp
90. order by sal desc)
91. where rownum <= 3
UPDATE
O comando UPDATE permite alterar linhas numa tabela. Como todos os
outros comandos do conjunto DML faz sempre parte de uma transacção.
Neste módulo vamos ver:
UPDATE
SELECT FOR UPDATE
Pseudo coluna ORA_ROWSCN
UPDATE
Uma instrução UPDATE permite alterar:
Uma coluna de uma linha da tabela;
Várias colunas de uma linha;
Uma coluna em várias linhas;
Várias colunas em várias linhas;
Para obter o que foi descrito acima usamos:
A cláusula SET para escolher a(s) coluna(s);
A cláusula WHERE para escolher a(s) linha(s);
O exemplo abaixo será analisado no módulo de criação de tabelas. Ele permite
criar uma tabela a partir do resultado de um comando SELECT. As restrições
existentes nas tabelas originais não são recriadas na nova tabela:
drop table EMP_SALS;
create table EMP_SALS (emp_name, salary, grade) as (
select e.ename, e.sal, s.grade
from emp e, salgrade s
where e.sal between s.losal and s.hisal
);
Error starting at line 1 in command:
drop table EMP_SALS
Error report:
SQL Error: ORA-00942: table or view does not exist
create table succeeded.
Se a tabela EMP_SALS não existir o comando DROP TABLE dá o
erro listado acima;
O comando abaixo altera o salário do empregado cujo nome é 'MILLER'. Se
existirem vários empregados com esse nome, todos são alterados.
update EMP_SALS
set salary = 3000
where EMP_NAME = 'MILLER';
1 rows updated
Como se pode ver no comando que cria a tabela EMP_SALS, a coluna
GRADE vem da tabela SALGRADE e representa o "nível" do salário. O
salário tem nível 1 se estiver entre 700 e 1200, tem nível 2 se estiver entre
1201 e 1400 e assim sucessivamente. No comando executado no exemplo
anterior a coluna GRADE pode ficar inconsistente após a actualização do
valor de salário.
No comando abaixo todos os empregados cujo nome começa por M recebem
um incremento salarial de 1000 e recorremos a uma subconsulta para
actualizar a coluna GRADE:
update EMP_SALS e
set e.salary = e.salary + 1000,
e.grade = ( select s.grade
from salgrade s
where e.salary between s.losal and s.hisal
)
where e.emp_name like 'M%';
2 rows updated
Neste UPDATE são actualizadas duas colunas e duas linhas;
A actualização da coluna GRADE recorre a uma subconsulta
correlacionada: o valor de SALARY do comando externo é usado para
pesquisar SALGRADE e devolver o valor de GRADE adequado para a
actualização;
Se a cláusula WHERE for omitida todas as linhas da tabela serão
alteradas.
A base de dados coloca um LOCK (bloqueio) sobre todas as linhas alteradas
pelo comando UPDATE. Este LOCK impede que outras sessões da base de
dados alterem estas linhas enquanto a transacção actual não terminar.
A existência de LOCKS pode gerar tempos de espera na base de dados pelo
que deve ser usada com muita cautela. O tempo em que o LOCK está activo
deve ser minimizado.
Vistas
Uma vista é uma a instrução SELECT que recebe um nome e pode ser
consultada como se fosse uma tabela. Na realidade não contem dados, pois
usa os da tabela que lhe dá suporte. As vistas permitem definir um nível de
abstracção, um nível superior de segurança ou, de uma forma mais genérica,
um ponto de vista. Uma vista pode mostrar uma parte de uma tabela, a soma
de duas tabelas ou qualquer outro conjunto de dados que se consiga obter com
uma instrução SELECT.
Neste módulo vamos ver os seguintes exemplos de vistas:
Com parte de uma tabela
Com JOIN
Com UNION entre duas tabelas
Ver o código da VIEW
Com parte de uma tabela
Vamos criar uma vista (VIEW) que faz uma selecção vertical e horizontal
sobre uma tabela:
create or replace view employee_v1 as
select
first_name,
last_name,
job_id,
salary,
commission
from
employee
where
department_id in (23,30);
Esta VIEW pode ser consultada com o seguinte comando:
select * from employee_v1;
Se dermos GRANT SELECT desta VIEW a outro utilizador, este só verá as
linhas e colunas por ela filtradas, pelo que esta técnica é frequentemente usada
para mostrar um subconjunto da tabela original.
Topo
Com JOIN
Vamos criar uma VIEW que faz a contagem de pessoas em cada
departamento. Como queremos mostrar o nome do departamento temos que
fazer um JOIN com a tabela DEPARTMENT:
create or replace view DEPT_COUNT_V1 (dept, count) as
select d.name, count(*)
from employee e
inner join department d on (d.department_id=e.department_id)
group by d.name;
No primeiro exemplo as colunas da VIEW foram definidas com o mesmo
nome das colunas da tabela original. Pelo contrário, neste exemplo o comando
que cria a VIEW define o nome das colunas. Para visualizar os dados da
VIEW fazemos:
select * from DEPT_COUNT_V1;
Topo
Com UNION entre duas tabelas
Vamos construir uma VIEW que faz a união vertical de dois conjuntos:
create or replace view salary_month_v1 as
select empno,
ename,
sal
from emp
union
select employee_id,
first_name || ' ' || last_name,
salary
from employee;
Para visualizar os dados da VIEW:
select * from salary_month_v1 where sal >= 3000;
Neste exemplo o query que consulta a VIEW leva uma cláusula WHERE, que
funciona como um filtro adicional ao query que define a vista.
Topo
Ver o código da VIEW
O código de uma VIEW pode ser consultado com um query a USER_VIEWS,
ALL_VIEWS ou DBA_VIEW. A primeira mostra os objectos do tipo VIEW
que o próprio utilizador criou (o utilizador que tem a sessão aberta). A
segunda mostra todos os objectos do tipo VIEW aos quais o utilizador actual
tem acesso de leitura, onde se inclui as VIEWS que lhe pertencem e aquelas
que embora pertençam a outros utilizadores, estes deram privilégios de leitura
ao utilizador actual. A terceira requer um privilégio especial e mostra todas as
VIEWS definidas dentro da base de dados.
select * from user_views;
select * from all_views;
select * from dba_views; /*requer privilégios especiais*/
A cláusula GROUP BY
A cláusula GROUP BY é usada para agrupar (ou agregar) as linhas da tabela
segundo um critério escolhido pelo utilizador, podendo depois ser aplicada
uma função de grupo a cada um dos grupos. Usando GROUP BY não é
possível seleccionar linhas individuais.
O exemplo abaixo determina o salário médio de cada função (JOB):
select job, avg(sal)
from emp
group by job;
JOB AVG(SAL)
--------- ----------------------
CLERK 1037,5
SALESMAN 1400
PRESIDENT 5000
MANAGER 2758,333333333333333333333333333333333333
ANALYST 3000
5 rows selected
É possível contar o número de linhas que cada grupo contém. Por exemplo,
quantas pessoas há em cada função?
select job, count(*)
from emp
group by job;
JOB COUNT(*)
--------- ----------------------
CLERK 4
SALESMAN 4
PRESIDENT 1
MANAGER 3
ANALYST 2
5 rows selected
As duas consultas anteriores podem ser fundidas. Nesse caso pretendemos
saber qual o salário médio de cada função e quantas pessoas nela trabalham:
select job, avg(sal), count(*)
from emp
group by job;
JOB AVG(SAL) COUNT(*)
--------- ----------------------------------------- ------------------
----
CLERK 1037,5 4
SALESMAN 1400 4
PRESIDENT 5000 1
MANAGER 2758,333333333333333333333333333333333333 3
ANALYST 3000 2
5 rows selected
Utilizando a cláusula WHERE podem-se excluir linhas antes de as dividir em
grupos. Por exemplo apresentar o salário médio de cada função (job)
excluindo os MANAGER:
select job, avg(sal), count(*)
from emp
where job != 'MANAGER'
group by job;
JOB AVG(SAL) COUNT(*)
--------- ---------------------- ----------------------
CLERK 1037,5 4
SALESMAN 1400 4
PRESIDENT 5000 1
ANALYST 3000 2
4 rows selected
Topo
A cláusula HAVING
A cláusula WHERE é utilizada no "modo de linha" para filtrar linhas
(restrição horizontal). A cláusula HAVING tem funções semelhantes no
"modo de grupo": serve para filtrar grupos quando o query possui um GROUP
BY.
Neste ponto veremos:
Como utilizar a cláusula HAVING?
Considerações sobre desempenho entre WHERE e HAVING;
Como utilizar a cláusula HAVING?
O exemplo abaixo determina o salário médio de todos os departamentos que
possuem mais de três pessoas:
select deptno, avg(sal), count(*)
from emp
group by deptno
having count(*) > 3;
DEPTNO AVG(SAL)
COUNT(*)
---------------------- ----------------------------------------- -----
-----------------
30 1566,666666666666666666666666666666666667 6
20 2175 5
2 rows selected
O exemplo abaixo determina as funções cujo salário mais alto é igual ou
superior a 3000:
select job,max(sal)
from emp
group by job
having max(sal) >= 3000;
JOB MAX(SAL)
--------- ----------------------
PRESIDENT 5000
ANALYST 3000
2 rows selected
A execução de uma consulta com WHERE, GROUP BY e HAVING segue os
passos abaixo:
1. WHERE - para filtrar as linhas individuais (não pode conter funções de
grupo);
2. GROUP BY - para agrupar as linhas seleccionadas no passo anterior;
3. HAVING - para excluir os grupos não requeridos;
A cláusula WHERE não pode incluir funções de grupo, pois a sua missão é
filtrar linhas e não grupos. Durante a sua execução os grupos ainda não estão
formados, pelo que as funções de grupo não podem ser calculadas.
O exemplo abaixo pretende determinar os departamentos cujo salário médio é
superior a 2000:
select deptno,avg(sal)
from emp
where avg(sal) > 2000
group by deptno;
where avg(sal) > 2000
*
ERROR at line 3:
ORA-00934: group function is not allowed here
A mensagem de erro mostra o principio referido anteriormente: a cláusula
WHERE não pode receber funções de grupo. A forma de resolver este
problema é usando a cláusula HAVING:
select deptno,avg(sal)
from emp
group by deptno
having avg(sal)>2000;
DEPTNO AVG(SAL)
---------------------- -----------------------------------------
20 2175
10 2916,666666666666666666666666666666666667
2 rows selected
Topo
Considerações sobre desempenho entre WHERE e HAVING
Algumas consultas com grupos tanto podem ser resolvidas recorrendo a uma
cláusula WHERE como a uma cláusula HAVING. Considere que pretende
determinar o salário médio de cada função (JOB) excluíndo os 'MANAGER'.
A solução abaixo filtra as funções usando uma cláusula WHERE:
select job,avg(sal)
from emp
where job !='MANAGER'
group by job;
JOB AVG(SAL)
--------- ----------------------
CLERK 1037,5
SALESMAN 1400
PRESIDENT 5000
ANALYST 3000
4 rows selected
O mesmo resultado pode ser obtido recorrendo a um filtro de grupos, usando
HAVING:
select job,avg(sal)
from emp
group by job
having job != 'MANAGER';
JOB AVG(SAL)
--------- ----------------------
CLERK 1037,5
SALESMAN 1400
PRESIDENT 5000
ANALYST 3000
4 rows selected
A cláusula WHERE eliminou todos os elementos que iriam formar o conjunto
MANAGER, e por isso este não foi formado. Embora ambos queries tenham
resolvido o problema (foram eficazes), as duas consultas não são igualmente
eficientes.
A primeira consulta segue o seguinte plano de execução:
1. Identificar todas as linhas da tabela excluíndo as que têm função
MANAGER;
2. Ordenar as linhas por JOB;
3. Criar os conjuntos por JOB (agrupar);
4. Determinar a média de cada conjunto;
A segunda consulta segue este plano de execução:
1. Identificar todas as linhas da tabela;
2. Ordenar as linhas por JOB;
3. Criar os conjuntos por JOB (agrupar);
4. Determinar a média de cada conjunto;
5. Eliminar o conjunto 'MANAGER';
Comparando os dois planos de execução verificamos que no primeiro as
linhas são filtradas no inicio, o que significa que as operações de ordenação e
agrupamento são feitas sobre menos linhas. No segundo plano os grupos são
formados tendo em conta todas as linhas, sendo depois eliminado um dos
grupos. Quando as tabelas têem grande dimensão esta diferença é
significativa, tornando a primeira consulta mais eficiente pelos seguintes
motivos:
1. Tem menos linhas para ordenar;
2. Tem menos contas para fazer, já que há menos linhas e menos grupos;
3. Não deita fora trabalho já feito;
Exercícios sobre funções de grupo
1. Encontre o salário mais baixo de todos os empregados.
2. Encontre o salário mais baixo, mais alto e médio de todos os
empregados.
3. Determine o salário mais alto e mais baixo de cada tipo de função.
4. Determine quantos empregados tem a função MANAGER.
5. Determine o salário médio e a remuneração total média (14 vezes o
salário mais a comissão) para cada tipo de função. Não se esqueça que
os vendedores ganham comissão.
6. Determine a diferença entre o salário mais alto e mais baixo
7. Encontre todos os departamentos que têm mais de três empregados.
8. Verifique se todos os números de empregado são únicos.
9. Liste o salário mais baixo dentro dos empregados de cada manager
(MGR). Exclua os grupos em que o salário mais baixo é inferior a
1000. Ordene o resultado pelo salário.
Soluções dos exercícios sobre funções
de grupo
10.
11. 1. 12. select min(sal) from emp;
13.
14. 2. 15. select min(sal), max(sal), avg(sal) from emp;
16.
17. 3. 18. select job, max(sal), min(sal) from emp group by job;
19.
20. 4. 21. select count(*) from emp where job='MANAGER';
22.
23. 5. 24. select job, avg(sal), avg(sal*14+nvl(comm,0))
25. from emp
26. group by job;
27.
28. 6. 29. select max(sal)-min(sal) from emp;
30.
31. 7. 32. select deptno, count(*)
33. from emp
34. group by deptno
35. having count(*) > 3;
36.
37. 8. 38. select empno
39. from emp
40. group by empno
41. having count(*) > 1;
42.
43. 9. 44. select mgr, min(sal)
45. from emp
46. group by mgr
47. having min(sal)>=1000
48. order by min(sal);