Sunteți pe pagina 1din 56

Juno de Tabelas

A figura abaixo resume as operaes de juno:

As operaes de juno dividem-se em dois grupos: horizontais e verticais. As horizontais actuam sobre linhas enquanto as verticais actuam sobre colunas. Juno horizontal Utiliza-se uma juno horizontal quando a consulta SQL requer dados de duas ou mais tabelas. Esta a operao que na prtica tira partido do conceito "base de dados relacional" pois permite mostrar os dados que esto armazenados em diferentes tabelas como se estivessem armazenados numa nica, desde que essas tabelas possuam um relacionamento entre si. A tabela resultado construda 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 clusulas do comando SELECT para fazer os diferentes tipos de juno. A base de dados Oracle suporta esta sintaxe desde a verso 9.0. Nas verses anteriores 9.0 era usada uma sintaxe antiga, que no caso da juno externa possuia uma notao proprietria. Por razes de compatibilidade com o passado a sintaxe antiga com as extenses

proprietrias contnua disponvel. Neste manual os comandos sero dados seguindo as duas abordagens: sintaxe antiga e SQL99.

Produto cartesiano

O produto cartesiano entre dois conjuntos um terceiro conjunto constitudo 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
SELECT emp.empno, emp.ename, emp.deptno, dept.deptno, dept.dname FROM emp, dept; EMPNO ENAME DNAME ---------------------- ------------------ -------------7369 SMITH ACCOUNTING 7499 ALLEN ACCOUNTING 7521 WARD ACCOUNTING 7566 JONES ACCOUNTING 7654 MARTIN ACCOUNTING 7698 BLAKE ACCOUNTING 7782 CLARK ACCOUNTING 7788 SCOTT ACCOUNTING 7839 KING ACCOUNTING 7844 TURNER ACCOUNTING 7876 ADAMS ACCOUNTING 7900 JAMES ACCOUNTING 7902 FORD ACCOUNTING 7934 MILLER ACCOUNTING 7369 SMITH RESEARCH

SQL99
SELECT emp.empno, emp.ename, emp.deptno, dept.deptno, dept.dname FROM emp CROSS JOIN dept; DEPTNO DEPTNO

---------------------- ------------20 30 30 20 30 30 10 20 10 30 20 30 20 10 20 10 10 10 10 10 10 10 10 10 10 10 10 10 10 20

7499 RESEARCH 7521 RESEARCH 7566 RESEARCH 7654 RESEARCH 7698 RESEARCH 7782 RESEARCH 7788 RESEARCH 7839 RESEARCH 7844 RESEARCH 7876 RESEARCH 7900 RESEARCH 7902 RESEARCH 7934 RESEARCH 7369 SALES 7499 SALES 7521 SALES 7566 SALES 7654 SALES 7698 SALES 7782 SALES 7788 SALES 7839 SALES 7844 SALES 7876 SALES 7900 SALES 7902 SALES 7934 SALES 7369 OPERATIONS 7499 OPERATIONS 7521 OPERATIONS 7566

ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER SMITH ALLEN WARD JONES MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER SMITH ALLEN WARD JONES

30 30 20 30 30 10 20 10 30 20 30 20 10 20 30 30 20 30 30 10 20 10 30 20 30 20 10 20 30 30 20

20 20 20 20 20 20 20 20 20 20 20 20 20 30 30 30 30 30 30 30 30 30 30 30 30 30 30 40 40 40 40

OPERATIONS 7654 OPERATIONS 7698 OPERATIONS 7782 OPERATIONS 7788 OPERATIONS 7839 OPERATIONS 7844 OPERATIONS 7876 OPERATIONS 7900 OPERATIONS 7902 OPERATIONS 7934 OPERATIONS 56 rows selected

MARTIN BLAKE CLARK SCOTT KING TURNER ADAMS JAMES FORD MILLER

30 30 10 20 10 30 20 30 20 10

40 40 40 40 40 40 40 40 40 40

Na sintaxe proprietria o produto cartesiano obtido quando se faz referencia a mais que duas tabelas e no se coloca uma condio de JOIN na clusula WHERE; Na sintaxe SQL99 o produto cartesiano obtido usando a clusula CROSS JOIN; A sintaxe SQL99 menos susceptvel a erros, pois preciso usar explicitamente a clusula CROSS JOIN, enquanto que na sintaxe proprietria, se houver esquecimento da clusula de JOIN ou erro na sua construo, sai um produto cartesiano; O resultado do produto cartesiano raramente til, pois mostra combinaes de linhas que no tm relao entre si e por isso no so teis para o utilizador. A sua execuo causa muito I/O na base de dados;

Juno Interna

Sumrio

A juno interna uma operao de juno horizontal entre duas tabelas, que usa uma comparao por igualdade entre a(s) coluna(s) comum(ns). Normalmente a(s) coluna(s) comum(ns) (so) Foreign Key numa tabela e Primary Key ou Unique Key na outra. A juno 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 juno interna entre duas tabelas:

A juno interna a operao mais importante nas bases de dados relacionais, pelo que suportada desde sempre. A norma SQL99 propos uma nova sintaxe para esta operao, tendo disponibilizado vrias clusulas que sero analisadas nos exemplos abaixo, onde tambm faremos a comparao com a sintaxe antiga. Os temas abordados sero:

Clusula ON Clusula USING Clusula NATURAL JOIN Comparao entre ON, USING e NATURAL JOIN Sinnimos para nomes de tabelas Juno com mais de duas tabelas A clusula de juno e a clusula de filtro A juno feita com coluna(s) UNIQUE

Clusula ON As tabelas EMP e DEPT possuem uma relao entre si, implementada atravs da coluna comum DEPTNO. Na tabela EMP sabemos qual o nmero do departamento em que o empregado trabalha. Na tabela DEPT sabemos o nmero, nome e localizao desse departamento. Para juntar os dois conjuntos efectuamos uma JUNO horizontaldas duas tabelas, usando uma igualdade de valores na coluna comum, como ilustrado nos exemplos abaixo:

Sintaxe antiga
SELECT emp.empno,

SQL99
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); DEPTNO ------------20 30 30 20 30 30 10 20 10 30 20 30 20 10

EMPNO ENAME DEPTNO DNAME LOC ---------------------- ---------- ------------------------------ -------------- ------------7369 SMITH 20 RESEARCH DALLAS 7499 ALLEN 30 SALES CHICAGO 7521 WARD 30 SALES CHICAGO 7566 JONES 20 RESEARCH DALLAS 7654 MARTIN 30 SALES CHICAGO 7698 BLAKE 30 SALES CHICAGO 7782 CLARK 10 ACCOUNTING NEW YORK 7788 SCOTT 20 RESEARCH DALLAS 7839 KING 10 ACCOUNTING NEW YORK 7844 TURNER 30 SALES CHICAGO 7876 ADAMS 20 RESEARCH DALLAS 7900 JAMES 30 SALES CHICAGO 7902 FORD 20 RESEARCH DALLAS 7934 MILLER 10 ACCOUNTING NEW YORK 14 rows selected

Com esta operao o utilizador consegue visualizar o nome do empregado, o nome do departamento em que trabalha e a sua localizao, ou seja, v os dados de duas tabelas relacionadas como se fossem uma nica; Esta juno pode ser interpretada como um produto cartesiano ao qual foram eliminadas as linhas que no satisfazem a condio de juno; O comentrio anterior mostra como interpretar a juno em comparao com o produto cartesiano, mas no revela a forma como o

motor da base de dados efectivamente resolve a operao. Esta operao to importante que os construtores de motores relacionais investem muitos recursos para optimizar o desempenho, o que resulta na existncia de vrios meios para executar a juno, que dependem da dimenso das tabelas envolvidas, da existncia 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 explicao mais detalhada est fora do mbito deste curso; As tabelas DEPT e EMP tm 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 operaes de juno so internas (INNER) pelo que a palavra reservada INNER facultativa;

Topo

Clusula USING A clusula USING est disponvel na sintaxe SQL99 e pode ser usada em vez da clusula ON sempre que a(s) coluna(s) usada(s) na juno tenha(m) o mesmo nome em ambas as tabelas. Esta clusula pode ser usada mesmo que existam outras colunas com o mesmo nome em ambas as tabelas. No caso das tabelas EMP e DEPT a juno pode ser feita com USING: Sintaxe antiga
SELECT emp.empno, emp.ename, emp.deptno, dept.deptno, dept.dname, dept.loc FROM emp, dept WHERE emp.deptno=dept.deptno;

SQL99
SELECT emp.empno, emp.ename, deptno, dept.dname, dept.loc FROM emp INNER JOIN dept USING (deptno);

Esta clusula facilita a escrita do query, mas requer a validao prvia de que a(s) coluna(s) usada(s) na juno tem(m) o mesmo nome em ambas as tabelas; A clusula USING obriga a que a(s) coluna(s) usada(s) na juno seja(m) referenciada(s) sem o nome da tabela a que pertence(m);

Topo

Clusula NATURAL JOIN A clusula NATURAL JOIN est disponvel na sintaxe SQL99 e pode ser usada em vez da clusula ON ou em vez da clusula USING sempre que:

A(s) coluna(s) usada(s) na juno tenha(m) o mesmo nome em ambas as tabelas; A(s) coluna(s) usada(s) na juno (so) a(s) nica(s) com o mesmo nome em ambas as tabelas;

No caso das tabelas EMP e DEPT a juno pode ser feita com NATURAL JOIN: Sintaxe antiga
SELECT emp.empno, emp.ename, emp.deptno, dept.deptno, dept.dname, dept.loc FROM emp, dept WHERE emp.deptno=dept.deptno;

SQL99
SELECT emp.empno, emp.ename, deptno, dept.dname, dept.loc FROM emp NATURAL JOIN dept;

Esta clusula facilita a escrita do query pois o utilizador no tem que referir qual(ais) a(s) coluna(s) que vai usar na juno; Esta clusula requer a validao prvia no s de que a(s) coluna(s) usada(s) na juno tem(m) o mesmo nome em ambas as tabelas mas tambm que (so) a(s) nica(s) coluna(s) comum(ns); A clusula NATURAL JOIN obriga a que a(s) coluna(s) usada(s) na juno seja(m) referenciada(s) sem o nome da tabela a que pertence(m);

Topo

Comparao entre ON, USING e NATURAL JOIN Consideremos as seguintes situaes: NAT URA USIN L G JOI N
SELECT * FROM t1 INNER JOIN t2 USING (t1_c1 ); SELECT * FROM t3 INNER JOIN t4 USING (t3_c1 ,t3_c2 ); SELE CT * FROM t1 NATU RAL JOIN t2;

Sit ua o

Modelo entidade relacionamento

Sintaxe antiga

ON

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 t3 INNER JOIN t4 ON (t3.t3_c 1=t4.t3_ c1 AND t3.t3_c2 =t4.t3_c 2); SELECT * FROM t5 INNER JOIN t6 ON (t5.t5_c 1=t6.t6_ c2);

SELECT * FROM t3, t4 WHERE t3.t3_c1 =t4.t3_c 1 AND t3.t3_c2 =t4.t3_c 2;

SELE CT * FROM t3 NATU RAL JOIN t4;

SELECT * FROM t5, t6 WHERE t5.t5_c1 =t6.t6_c 2;

No No possv poss el vel


SELECT * FROM t7 INNER JOIN t8 USING (t7_c1 );

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);

No poss vel

Topo

Sinnimos para nomes de tabelas O nome da tabela pode ser substitudo por um sinnimo, como mostram os exemplos abaixo: Sintaxe antiga
SELECT e.empno, e.ename, e.deptno, d.deptno, d.dname, d.loc FROM emp e, dept d WHERE e.deptno=d.deptno;

SQL99
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 utilizao de sinnimos para os nomes das tabelas apresenta as seguintes vantagens:


Ajuda a distinguir as colunas que tm 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 no tem duvidas de onde tem que ir buscar as colunas, pelo que poupa processamento. Este fim tambm pode ser atingido recorrendo ao nome da tabela; Permite efectuar a juno de uma tabela com ela prpria;

Topo

Juno com mais de duas tabelas A figura abaixo mostra as relaes existentes entre as tabelas EMPLOYEES, DEPARTMENTS e LOCATIONS, pertencentes ao conjunto HR:

Este relacionamento possibilita a juno entre as 3 tabelas exemplificada pelos comandos abaixo: Sintaxe antiga ON USING
SELECT e.first_name , e.last_name, 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); 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 );

NATURA L JOIN

No possvel porque a coluna MANAGE R_ID comm a Employees ea Departmen ts e nao usada na clusula de juno deste relacionam ento

Na maior parte das situaes vlido o seguinte principio: se h n tabelas temos que usar n-1 condies de juno. Esta regra no vlida quando existe mais que uma relao entre duas tabelas, como no nosso exemplo, casos onde se deve aplicar o princpio abaixo; Cada relacionamento entre duas tabelas exige uma condio de juno. Neste exemplo consideramos o nico relacionamento entre LOCATIONS e DEPARTMENTS e nos vrios relacionamentos existentes entre EMPLOYEES e DEPARTMENTS consideramos apenas EMP_DEPT_FK; A condio de juno deve incluir todas as colunas usadas na juno;

Topo

A clusula de juno e a clusula de filtro O facto de efectuarmos uma juno entre duas tabelas no impede que se faa um filtro das linhas. O exemplo abaixo mostra como: Sintaxe antiga ON USING
SELECT e.first_name , 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%'; 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%';

NATURA L JOIN No possvel porque a coluna MANAGE R_ID comm a Employees ea Department s e nao usada na clusula de juno deste relacionam ento

Na sintaxe antiga as condies de juno e de filtro misturam-se, sendo necessria uma leitura mais atenta para as distinguir; Na sintaxe SQL99 h uma separao clara entre condies de juno e de filtro;

Topo

A juno feita com colunas UNIQUE As boas prticas recomendam que a juno entre duas tabelas seja feita entre a chave primria (PK - Primary Key) de uma e a chave estrangeira (FK Foreign Key) da outra tabela. O motor relacional do Oracle permite que a chave primria seja substituda por uma chave alternativa. Por exemplo, em vez do nmero de empregado poderamos usar o NIF (Nmero de Identificao Fiscal), desde que este seja nico para cada empregado e tenha um valor no nulo. Para isto a base de dados requer a existncia de um ndice com a propriedade UNIQUE ou que seja definida a restrio UNIQUE sobre a(s) coluna(s) envolvida(s).

Juno 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 no ter um departamento atribudo, assim como um departamento pode no ter empregados atribudos. Os empregados que no tm departamento e os departamentos que no tm empregado no aparecem no resultado de uma juno interna, mas aparecem na juno externa. A juno externa uma extenso da juno interna.

Juno externa esquerda Juno externa direita Juno externa FULL ( esquerda e direita)

Juno externa esquerda A juno externa esquerda estende o resultado da juno interna, pois mostra todas as linhas que so devolvidas pela juno interna e acrescenta as linhas da tabela da esquerda que no tm correspondncia na tabela da direita. A juno 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 juno:

Os comandos apresentados a seguir mostram como fazer a juno externa esquerda entre as tabelas EMPLOYEES e DEPARTMENTS. Esta operao vai mostrar as linhas obtidas pela juno interna, acrescida dos empregados que no tm um departamento atribudo, o que possvel porque a coluna DEPARTMENT_ID em EMPLOYEES suporta valores nulos:

Sintaxe proprietria

ON

USING

NATUR AL JOIN

SELECT e.first_name , 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); e.last_name, department_i d, d.department _name FROM employees e LEFT OUTER JOIN departments d USING (department_ id);

No aplicvel

Topo

Juno externa direita A juno externa direita funciona da mesma forma que a juno externa esquerda, mas mostra as linhas da tabela da direita que no tm correspondncia com linhas da tabela da esquerda. Este resultado pode ser obtido por uma juno esquerda trocando a ordem das colunas. O diagrama apresentado a seguir descreve o funcionamento deste tipo de juno:

Os comandos apresentados a seguir mostram como fazer a juno externa direita entre as tabelas EMPLOYEES e DEPARTMENTS. Esta operao vai mostrar as linhas obtidas pela juno interna, acrescida dos departamentos que no tm um empregado atribudo:

Sintaxe proprietria
SELECT

ON
SELECT e.first_name,

USING
SELECT

NATURA L JOIN No

e.first_name,

e.last_name, d.department_id, e.last_name, d.department_name FROM employees e d.department_i RIGHT OUTER JOIN departments d, d ON (e.department_id=d.department d.department_n _id); ame FROM employees e, departments d WHERE e.department_i d (+) =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 );

aplicvel

Topo

Juno externa FULL ( esquerda e direita) A juno externa FULL mostra a soma das junes externas esquerda e direita, como exemplificado no prximo diagrama:

Os comandos apresentados a seguir mostram como fazer a juno externa FULL entre as tabelas EMPLOYEES e DEPARTMENTS:

Sintaxe proprietria
SELECT

ON

USING
SELECT e.first_name, e.last_name, department_id, d.department_n ame FROM employees e

NATURA L JOIN

SELECT e.first_name, e.first_name, e.last_name, e.last_name, d.department_id, d.department_name d.department_i FROM employees e FULL OUTER JOIN departments d d, ON d.department_n (e.department_id=d.department ame _id); FROM employees

No aplicvel

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 proprietria no permite a juno externa em simultneo esquerda e direita, pelo que recorremos ao operador UNION que faz a juno vertical dos dois conjuntos resultado; O recurso ao operador UNION na sintaxe proprietria fora a execuo de 2 queries para resolver o problema, ao contrrio dos exemplos com sintaxe SQL99 que resolvem com um nico query;

Juno Vertical - Operadores sobre conjuntos

O SQL disponibiliza trs operadores que permitem a partir de dois conjuntos produzir um terceiro. Estes operadores actuam sobre as colunas das tabelas de origem, produzindo uma Juno Vertical:

UNIO INTERSECO DIFERENA

Estes operadores permitem obter um nico conjunto resultado a partir de dois conjuntos iniciais. So teis na juno de diferentes consultas que se refiram a tabelas diferentes mas que tenham colunas com o mesmo tipo de dados. A sua utilizaoo segue as seguintes regras: 1. As duas instrues SELECT tm que seleccionar o mesmo nmero de colunas; 2. As colunas correspondentes tm que ser do mesmo tipo de dados; 3. As linhas duplicadas so eliminadas pelo operador UNION. Se usarmos UNION ALL os duplicados no so eliminados, o que poupa uma operao de SORT; 4. Os nomes de coluna da primeira consulta aparecem no resultado; 5. A clusula ORDER BY aparece no fim da instruo. Se as colunas correspondentes dos diferentes SELECT's tiverem nomes diferentes, a refercia (s) coluna(s) dever ser feita por nmero de posio; 6. As instrues SELECT so executadas de cima para baixo; 7. Se forem utilizados vrios operadores de conjunto possivel usar parentesis para definir prioridades de execuo;

UNIO (UNION)
O operador UNION permite obter a reunio de dois conjuntos:

O comando abaixo apresenta os nomes e salrios dos empregados das tabelas EMP e EMPLOYEES. So 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 apaream 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 no respeita a teoria de conjuntos, pois permite a repetio de elementos. Foi criado por uma questo de

desempenho, j que evita ao motor de base de daos as operaes ordenao e filtro. Deve ser usado quando no faa difrena trabalhar com elementos repetidos; Topo

INTERSECO (INTERSECT)
O operador INTERSECT permite obter a interseco entre dois conjuntos:

O comando abaixo permite listar os salrios que existem em EMP e em EMPLOYEES:


select sal from emp INTERSECT select salary from employees; SAL ---------------------3000 1 rows selected

Topo

DIFERENA (MINUS)
O operador MINUS permite obter a diferena entre dois conjuntos:

O comando abaixo permite listar os salrios que esto em EMP e no esto 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

Exerccios sobre juno de tabelas

1. Liste todos os empregados e respectivos nomes de departamento, por ordem do nome de departamento; 2. Liste o nome, nmero e nome de departamento de todos os empregados; 3. Liste o nome, departamento e localidade do departamento dos empregados cujo salrio mensal seja superior a 1500; 4. Produza uma lista que mostre o nvel salarial (GRADE) de cada empregado; 5. Produza uma lista dos empregados com nvel salarial 3; 6. Mostre todos os empregados de Dallas (Dept Loc); 7. Liste nome, funo, salrio, nvel (GRADE) e nome de departamento para todos os empregados, excepto empregados de escritrio (CLERK). Ordene por salrio apresentando primeiro o mais elevado;

8. Liste o nome, funo, salrio anual, nmero de departamento, nome de departamento e nvel salarial (grade) para os empregados que ganham mais de 36000 por ano (14 vezes o salrio mais a comisso) ou que sejam empregados de escritrio (CLERK); 9. Liste todos os departamentos que no tm empregados; 10. Liste o nome e nmero de empregado juntamente com o nome e nmero do seu manager; 11. Modifique a soluo da questo 10 de forma a visualizar KING que no tem manager; 12. Encontre o departamento que contratou funcionrios 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 mtodo de consulta para a questoa 9 utilizando o operador MINUS.

Solues dos exerccios sobre juno de tabelas


15.

16. 1.

17. Soluo usando a sintaxe tradicional:


18. 19. 20. 21. 23. 24. 25. 26. select e.ename, e.deptno, d.dname from emp e, dept d where e.deptno=d.deptno order by d.dname; select e.ename, e.deptno, d.dname from emp e inner join dept d on (e.deptno=d.deptno) order by d.dname;

22. Soluo usando a sintaxe SQL99:

27.
28. 2.

29. Soluo 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. Soluo 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. Soluo 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. Soluo usando a sintaxe SQL99:


45. 46. 47. 48. select e.ename,d.dname,d.loc from emp e inner join dept d on (e.deptno = d.deptno) where sal > 1500;

49.
50. 4.

51. Soluo usando a sintaxe tradicional:


52. select ename, job, sal, grade 53. from emp, salgrade 54. where sal between salgrade.losal and salgrade.hisal;

55. Soluo 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. Soluo usando a sintaxe tradicional:


62. 63. 64. 65. select ename, job, sal, grade from emp, salgrade where sal between salgrade.losal and salgrade.hisal and grade = 3;

66. Soluo 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. Soluo usando a sintaxe tradicional:


74. 75. 76. 77. 79. 80. 81. 82. select emp.ename, emp.sal, dept.loc from emp, dept where emp.deptno=dept.deptno and dept.loc = 'DALLAS'; select emp.ename, emp.sal, dept.loc from emp inner join dept on (emp.deptno=dept.deptno) where dept.loc = 'DALLAS';

78. Soluo usando a sintaxe SQL99:

83.
84. 7.

85. Soluo usando a sintaxe tradicional:


86. 87. 88. 89. 90. select e.ename, e.job, e.sal, s.grade, d.dname from emp e, salgrade s, dept d where e.sal between s.losal and s.hisal and e.deptno=d.deptno and e.job !='CLERCK'

91. order by e.sal desc;

92. Soluo usando a sintaxe SQL99:


93. 94. 95. 96. 97. 98. select e.ename, e.job, e.sal, s.grade, d.dname from emp e inner join salgrade s on (e.sal between s.losal and s.hisal) inner join dept d on (e.deptno=d.deptno) where e.job != 'CLERCK' order by e.sal desc;

99.
100. 8.

101.

Soluo 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.
108. 109. 110. 111. 112. 113.

Soluo usando a sintaxe SQL99:


select e.ename, e.job, e.sal, s.grade, d.dname from emp e inner join salgrade s on (e.sal between s.losal and s.hisal) inner join dept d on (e.deptno=d.deptno) where e.job != 'CLERCK' order by e.sal desc;

114.
115. 9.

116. Soluo usando a sintaxe tradicional. O operador (+) coloca-se sempre do lado fraco, isto , do lado onde pode haver uma linha NULL:
117. 118. 119. 120. select d.deptno, d.dname from emp e, dept d where e.deptno (+) = d.deptno and e.ename is null;

121.
122. 123. 124. 125.

Soluo usando a sintaxe SQL99:


select d.deptno, d.dname from emp e right outer join dept d on (e.deptno = d.deptno) where e.ename is null;

126.
127. 10.

128.

Soluo 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.

Soluo 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. Soluo 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.

Soluo 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.

Soluo 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.

Soluo 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.
178. 179. 180. 181. 182.

Usando sintaxe SQL99


select e.ename m.ename from emp e inner join emp and e.hiredate as empregado_nome, e.hiredate as empregado_data, as manager_nome, m.hiredate as manager_data m on (e.mgr=m.empno) > m.hiredate;

183.
184. 14.

185. 186.

Retirar lista dos departamentos aqueles que tm empregados. Soluo usando a sintaxe tradicional:

187. 188. 189. 190. 191. 192.

select deptno, dname from dept minus select e.deptno, d.dname from emp e, dept d where e.deptno=d.deptno;

193.
194. 195. 196. 197. 198. 199.

Usando sintaxe SQL99


select deptno, dname from dept minus select e.deptno, d.dname from emp e inner join dept d on (e.deptno=d.deptno);

Subconsultas simples e correlacionadas

Uma subconsulta uma instruo SELECT que est encadeada dentro de outra instruo SELECT. A consulta interior designada por seleco interna e executada em primeiro lugar, sendo o seu resultado utilizado para completar a consulta principal ou externa. A utilizao de subconsultas permite construir comandos potentes a partir de comandos mais simples. Na construo de subconsultas devem ser seguidas as seguintes linhas de orientao:

A consulta interna dever ser colocada entre parentisis e ter que estar no lado direito da condio; Desde a verso 8.1.7 do motor Oracle que as subconsultas podem ter uma clusula ORDER BY; As subconsultas podem devolver uma ou mais linhas, uma ou mais colunas. Se devolverem vrias colunas ento tero que estar pela mesma ordem que as colunas que apaream na clusula de condio da consulta externa (ou principal). O tipo de dados e o nmero de colunas tm tambm que corresponder; As subconsultas podem utilizar operadores lgicos, operadores de SQL, operadores ANY e ALL e operadores de conjunto; As subconsultas podem ser utilizadas em instrues 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 salrio mais baixo na empresa, desconhecendo a quantia em causa. O problema pode resolver-se em dois passos:

Encontrar o salrio mais baixo; Encontrar o(s) empregado(s) que ganha(m) o salrio 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 condio de pesquisa. O exemplo abaixo procura todos os empregados que executam a mesma funo que BLAKE:
select ename,job from emp

where job = (select job from emp where ename = 'BLAKE'); EENAME ---------JONES BLAKE CLARK JOB --------MANAGER MANAGER MANAGER

3 rows selected

Na consulta anterior o programador corre um risco: a consulta interna pesquisa por nome, que no uma coluna UNIQUE e portanto no h garantias de que devolva apenas um valor. Se devolver mais que um valor a consulta toda d um erro, por causa da comparao 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 so processadas no query principal. A lista abaixo contem os passos necessrios 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 prxima linha at que no haja mais linhas candidatas;

A consulta abaixo pretende encontrar os empregados que ganham um salrio superior ao salrio mdio 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 -----------------------------7499 7566 7698 7788 7839 7902 6 rows selected

ENAME SAL DEPTNO ---------- ---------------------- ------------ALLEN JONES BLAKE SCOTT KING FORD 1600 2975 2850 3000 5000 3000 30 20 30 20 10 20

Para identificar que se trata de uma subconsulta correlacionada preciso reparar na utilizao de uma coluna da tabela do SELECT externo na clusula WHERE do SELECT interno; O pseudnimo 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 vrias linhas operadores do SQL

Os exemplos de subconsulta que vimos at agora devolvem apenas uma linha. Mas uma subconsulta pode devolver vrias 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 vrias 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) includo(s) no conjunto devolvido pela consulta interna. Este operador pode ser negado com NOT.

Suponha que pretende determinar os empregados que ganham o salrio mais baixo em cada funo, 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 -------------------Nandita Diana Shelley Alberto Nancy William Kevin Ellen Gerald Den Jennifer Lex Neena Randall Martha Peter Joshua James Karen Luis Clara Eleni Michael Hermann Harrison Janette Peter Steven Sundita Pat Bruce TJ Susan Shanta 34 rows selected SALARY ---------------------4200 4200 12000 12000 12000 8300 5800 11000 11000 11000 4400 17000 17000 2500 2500 2500 2500 2500 2500 6900 10500 10500 13000 10000 10000 10000 10000 24000 6100 6000 6000 2100 6500 6500 JOB_ID ---------SH_CLERK IT_PROG AC_MGR SA_MAN FI_MGR AC_ACCOUNT ST_MAN SA_REP SA_MAN PU_MAN AD_ASST AD_VP AD_VP SH_CLERK SH_CLERK ST_CLERK ST_CLERK ST_CLERK PU_CLERK FI_ACCOUNT SA_REP SA_MAN MK_MAN PR_REP SA_REP SA_REP SA_REP AD_PRES SA_REP MK_REP IT_PROG ST_CLERK HR_REP ST_MAN

O resultado obtido no est correcto pois a consulta nogarante que o salrio mnimo encontrado na subconsulta se refere ao departamento para o qual trabalha o empregado da consulta externa;

O salrio mnimo da funo SA_MAN 10500. O empregado Alberto, com a funo SA_MAN ganha 12000, que acima do mnimo, mas aparece no resultado da consulta. Isto porque o seu salrio igual ao mnimo da funo FI_MGR;

A forma de associar a funo ao salrio mnimo 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 -------------------Diana Shelley William Kevin Den Jennifer Neena Lex Martha Randall Luis Nancy Karen Eleni Michael Hermann Steven Sundita Pat TJ Susan 21 rows selected SALARY ---------------------4200 12000 8300 5800 11000 4400 17000 17000 2500 2500 6900 12000 2500 10500 13000 10000 24000 6100 6000 2100 6500 JOB_ID ---------IT_PROG AC_MGR AC_ACCOUNT ST_MAN PU_MAN AD_ASST AD_VP AD_VP SH_CLERK SH_CLERK FI_ACCOUNT FI_MGR PU_CLERK SA_MAN MK_MAN PR_REP AD_PRES SA_REP MK_REP ST_CLERK HR_REP

Topo

ANY (SOME) O operador ANY (e o seu sinnimo SOME) permite a uma consulta externa fazer comparaes usando < ou > com os elementos de um conjunto devolvido pela subconsulta. Este operador devolve TRUE se uma das linhas do conjunto satisfaz a condio, ou seja, devolve FALSE se nenhuma satisfaz a condio. 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 salrio mnimo do departamento 30.
select ename, sal, job, deptno from emp where sal > ANY (select distinct sal from emp where deptno=30); ENAME ---------KING FORD SCOTT JONES BLAKE CLARK ALLEN TURNER MILLER WARD MARTIN ADAMS SAL ---------------------5000 3000 3000 2975 2850 2450 1600 1500 1300 1250 1250 1100 JOB --------PRESIDENT ANALYST ANALYST MANAGER MANAGER MANAGER SALESMAN SALESMAN CLERK SALESMAN SALESMAN CLERK DEPTNO ---------------------10 20 20 20 30 10 30 30 10 30 30 20

12 rows selected

A comparao '= ANY' pode ser usada, mas equivalente a IN; Ao utilizar ANY frequente recorrer clusula DISTINCT, para evitar linhas repetidas e assim tornar a avaliao da expresso lgica mais eficiente;

Topo

ALL O operador ALL permite a uma consulta externa fazer comparaes usando < ou > com os elementos de um conjunto devolvido pela subconsulta. Este operador devolve TRUE se todas as linhas do conjunto satisfazem a condio, ou seja, devolve FALSE se alguma linha no 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 salrio mximo do departamento 30.

select ename, sal, job, deptno from emp where sal > ALL (select distinct sal from emp where deptno=30); ENAME ---------JONES SCOTT KING FORD SAL ---------------------2975 3000 5000 3000 JOB --------MANAGER ANALYST PRESIDENT ANALYST DEPTNO ---------------------20 20 10 20

4 rows selected

Topo

EXISTS O operador EXISTS permite consulta externa verificar se a consulta interna devolveu alguma linha. No 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 ---------------------7902 7698 7839 7566 7788 7782 6 rows selected ENAME ---------FORD BLAKE KING JONES SCOTT CLARK JOB --------ANALYST MANAGER PRESIDENT MANAGER ANALYST MANAGER DEPTNO ---------------------20 30 10 20 20 10

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 no 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 no tem que ser a coluna que est em causa. O exemplo anterior pode ser substitudo 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 dicionrio de dados mostra que o relacionamento entre as tabelas EMP e DEPT no est assegurado por uma restrio definida no motor da base de dados. Isto significa que possvel que exista um empregado que trabalhe num departamento que no 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 clusulas da instruo SELECT

Uma subconsulta pode ser colocada em vrios pontos da instruo SELECT:


WHERE HAVING FROM SELECT

Subconsulta na clusula WHERE Nos exemplos apresentados at aqui a subconsulta aparece na clusula WHERE. O exemplo abaixo procura todos os empregados que executam a mesma funo que BLAKE (subconsulta simples):
select ename,job from emp where job = (select job from emp where ename = 'BLAKE'); EENAME ---------JONES BLAKE CLARK JOB --------MANAGER MANAGER MANAGER

3 rows selected

A consulta abaixo procura os empregados que ganham um salrio superior ao salrio mdio 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 -----------------------------7499 7566 7698 7788 ENAME SAL DEPTNO ---------- ---------------------- ------------ALLEN JONES BLAKE SCOTT 1600 2975 2850 3000 30 20 30 20

7839 7902 6 rows selected

KING FORD

5000 3000

10 20

Topo

Subconsulta na clusula HAVING Uma subconsulta pode ser colocada na clusula HAVING. O exemplo abaixo determina os departamentos cujo salrio mdio 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 ---------------------20 10 2 rows selected AVG(SAL) ---------------------2175 2916,666666666666666666666666666666666667

A consulta interna determina o salrio mdio do departamento 30; A consulta externa determina os salrios mdios de todos os departamentos mas s mostra os que tm valor superior ao devolvido pela subconsulta;

O exemplo abaixo determina a funo com o salrio mdio 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 comea por determinar o salrio mdio de cada funo, indo depois determinar o maior salrio de entre as mdias; A consulta externa determina o nome da funo e respectivo salrio mdio, s mostrando aqueles que igualam o valor devolvido pela subconsulta;

Topo

Subconsulta na clusula FROM Uma subconsulta pode ser colocada na clusula FROM, o que o mesmo que referir uma view (vista) ou uma tabela virtual. O exemplo abaixo determina os 5 empregados que tm o salrio mais elevado:
select * from (select ename, sal from emp order by sal desc) where rownum <=5; ENAME ---------KING SCOTT FORD JONES BLAKE SAL ---------------------5000 3000 3000 2975 2850

5 rows selected

A subconsulta lista os salrios 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 salrios mximos 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 clusula SELECT As subconsultas podem ser colocadas na clusula SELECT. O exemplo abaixo pretende listar os salrios mximos 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 funo 'CLERK'. Pretende mostrar o salrio de cada um e compar-lo com a mdia da funo e a mdia 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 DEPTNO Avg_Sal_Deptno ---------- ---------------------- --------------------------- ---------------------SMITH 800 CLERK 2175 ADAMS 1100 CLERK 2175 2 rows selected Avg_Sal_Job ---------------------- --1038 1038 20 20

A primeira subconsulta determina a mdia de salrios para a funo enquanto a segunda determina a mdia do departamento; A consulta exterior usa os valores anteriores no meio dos valores de cada linha da tabela que satisfaz a condio de filtro; Estas subconsultas so simples (no correlacionadas);

Vamos generalizar o exemplo anterior para todos os empregados da empresa, o que nos obriga a considerar todas as funes 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 DEPTNO Avg_Sal_Deptno ---------- ---------------------- --------------------------- ---------------------SMITH 800 CLERK 2175 ALLEN 1600 SALESMAN 1567 WARD 1250 SALESMAN 1567 JONES 2975 MANAGER 2175 MARTIN 1250 SALESMAN 1567 BLAKE 2850 MANAGER 1567 Avg_Sal_Job ---------------------- --1038 1400 1400 2758 1400 2758 20 30 30 20 30 30

CLARK 2917 SCOTT 2175 KING 2917 TURNER 1567 ADAMS 2175 JAMES 1567 FORD 2175 MILLER 2917

2450 3000 5000 1500 1100 950 3000 1300

MANAGER ANALYST

2758 3000

10 20 10 30 20 30 20 10

PRESIDENT 5000 SALESMAN CLERK CLERK ANALYST CLERK 1400 1038 1038 3000 1038

14 rows selected

Repare como os sinnimos do nome de tabela so usados para correlacionar as consultas e eliminar a ambiguidade na referncia ao nome das colunas;

Subconsulta e encadeamento mltiplo

Uma subconsulta pode receber outra, pelo que as subconsultas podem ser encadeadas umas dentro das outras at um limite de 255 nveis (Oracle SGBDR verso 8.0). O exemplo abaixo determina o nome, funo e data de admisso dos empregados cujo salrio superior ao salrio 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 ---------JONES SCOTT KING FORD JOB --------MANAGER ANALYST PRESIDENT ANALYST HIREDATE ------------------------81.04.02 82.12.09 81.11.17 81.12.03 SAL ---------------------2975 3000 5000 3000

4 rows selected

A subconsulta que ser feita em primeiro lugar a que est mais abaixo e direita e vai determinar o nmero do departamento que tem o nome 'SALES'; Em seguida vamos determinar a mdia de salrios desse departamento; Por ltimo vamos determinar quais os empregados que ganham mais que essa mdia;

Exerccios sobre subconsultas

1. Encontre os empregados que ganham o salrio mais alto em cada tipo de funo (JOB). 2. Encontre os empregados que ganham o salrio mais baixo em cada funo. Visualize o resultado por ordem crescente de salrio. 3. Encontre os empregados mais recentes em cada departamento. Ordene por data de admisso. 4. Encontre o nome, salrio e nmero de departamento dos empregados que ganham um salrio maior que a mdia do respectivo departamento. Ordene por nmero de departamento. 5. Liste todos os departamentos que no possuem empregados. Utilize uma subconsulta. 6. Determine qual o departamento com o MAIOR encargo anual de remuneraes (14 vezes o salrio mais a comisso). 7. Em que ano entraram mais pessoas para a empresa? Visualize o ano e nmero de empregados. 8. Modifique a questo 4 para apresentar tambm o valor do salrio mdio 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 so os 3 empregados mais bem pagos da companhia ?

Solues dos exerccios 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); select job,ename,sal from emp where (sal,job) in (select min(sal),job from emp group by job) order by sal; select ename,hiredate,deptno from emp where (hiredate,deptno) in (select max(hiredate),deptno from emp group by deptno) order by hiredate; select e.ename, e.sal, e.deptno from emp e where e.sal > (select avg(e2.sal) from emp e2 where e2.deptno= e.deptno) order by e.deptno;

18. 2.
19. 20. 21. 22. 23. 24. 26. 27. 28. 29. 30. 31. 33. 34. 35. 36. 37. 38.

25. 3.

32. 4.

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. 47. 48. 49. 50. 51. 52. 53. 55. 56. 57. 58. 59. 60. 62. 63. 64. 65. 66. 67. 68. define anual = sal*14+nvl(comm,0); select deptno, sum(&anual) from emp group by deptno having sum(&anual)= (select max(sum(&anual)) from emp group by deptno); select to_char(hiredate,'YYYY'), count(empno) from emp group by to_char(hiredate,('YYYY')) having count(empno) = (select max(count(empno)) from emp group by to_char(hiredate,'YYYY')); select e.ename, e.sal, e.deptno, avg(a.sal) from emp e, emp a where e.deptno=a.deptno and e.sal > (select avg(sal) from emp where deptno=e.deptno) group by e.ename, e.sal, e.deptno;

54. 7.

61. 8.

69. Outra soluo 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. 80. 81. 82. 83. 84. 85. select ename, hiredate, '*' from emp where hiredate = (select max(hiredate) from emp) union select ename, hiredate, ' ' from emp 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 transaco. Neste mdulo vamos ver:

UPDATE SELECT FOR UPDATE Pseudo coluna ORA_ROWSCN

UPDATE Uma instruo UPDATE permite alterar:


Uma coluna de uma linha da tabela; Vrias colunas de uma linha; Uma coluna em vrias linhas; Vrias colunas em vrias linhas;

Para obter o que foi descrito acima usamos:


A clusula SET para escolher a(s) coluna(s); A clusula WHERE para escolher a(s) linha(s);

O exemplo abaixo ser analisado no mdulo de criao de tabelas. Ele permite criar uma tabela a partir do resultado de um comando SELECT. As restries existentes nas tabelas originais no so 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 no existir o comando DROP TABLE d o erro listado acima;

O comando abaixo altera o salrio do empregado cujo nome 'MILLER'. Se existirem vrios empregados com esse nome, todos so 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 "nvel" do salrio. O salrio tem nvel 1 se estiver entre 700 e 1200, tem nvel 2 se estiver entre 1201 e 1400 e assim sucessivamente. No comando executado no exemplo anterior a coluna GRADE pode ficar inconsistente aps a actualizao do valor de salrio. No comando abaixo todos os empregados cujo nome comea 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 so actualizadas duas colunas e duas linhas; A actualizao 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 actualizao;

Se a clusula WHERE for omitida todas as linhas da tabela sero alteradas. A base de dados coloca um LOCK (bloqueio) sobre todas as linhas alteradas pelo comando UPDATE. Este LOCK impede que outras sesses da base de dados alterem estas linhas enquanto a transaco actual no terminar. A existncia 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 instruo SELECT que recebe um nome e pode ser consultada como se fosse uma tabela. Na realidade no contem dados, pois usa os da tabela que lhe d suporte. As vistas permitem definir um nvel de abstraco, um nvel superior de segurana ou, de uma forma mais genrica, 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 instruo SELECT. Neste mdulo vamos ver os seguintes exemplos de vistas:

Com parte de uma tabela Com JOIN Com UNION entre duas tabelas Ver o cdigo da VIEW

Com parte de uma tabela

Vamos criar uma vista (VIEW) que faz uma seleco 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 tcnica 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 contrrio, 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 unio 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 clusula WHERE, que funciona como um filtro adicional ao query que define a vista. Topo

Ver o cdigo da VIEW O cdigo 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 prprio utilizador criou (o utilizador que tem a sesso 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 pertenam a outros utilizadores, estes deram privilgios de leitura ao utilizador actual. A terceira requer um privilgio 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 privilgios especiais*/

A clusula GROUP BY

A clusula GROUP BY usada para agrupar (ou agregar) as linhas da tabela segundo um critrio escolhido pelo utilizador, podendo depois ser aplicada

uma funo de grupo a cada um dos grupos. Usando GROUP BY no possvel seleccionar linhas individuais. O exemplo abaixo determina o salrio mdio de cada funo (JOB):
select job, avg(sal) from emp group by job; JOB --------CLERK SALESMAN PRESIDENT MANAGER ANALYST AVG(SAL) ---------------------1037,5 1400 5000 2758,333333333333333333333333333333333333 3000

5 rows selected

possvel contar o nmero de linhas que cada grupo contm. Por exemplo, quantas pessoas h em cada funo?
select job, count(*) from emp group by job; JOB --------CLERK SALESMAN PRESIDENT MANAGER ANALYST COUNT(*) ---------------------4 4 1 3 2

5 rows selected

As duas consultas anteriores podem ser fundidas. Nesse caso pretendemos saber qual o salrio mdio de cada funo e quantas pessoas nela trabalham:
select job, avg(sal), count(*) from emp group by job; JOB -----------CLERK SALESMAN PRESIDENT MANAGER ANALYST AVG(SAL) COUNT(*) ----------------------------------------- -----------------1037,5 1400 5000 2758,333333333333333333333333333333333333 3000 4 4 1 3 2

5 rows selected

Utilizando a clusula WHERE podem-se excluir linhas antes de as dividir em grupos. Por exemplo apresentar o salrio mdio de cada funo (job) excluindo os MANAGER:
select job, avg(sal), count(*) from emp where job != 'MANAGER' group by job; JOB --------CLERK SALESMAN PRESIDENT ANALYST AVG(SAL) ---------------------1037,5 1400 5000 3000 COUNT(*) ---------------------4 4 1 2

4 rows selected

Topo

A clusula HAVING

A clusula WHERE utilizada no "modo de linha" para filtrar linhas (restrio horizontal). A clusula HAVING tem funes semelhantes no "modo de grupo": serve para filtrar grupos quando o query possui um GROUP BY. Neste ponto veremos:

Como utilizar a clusula HAVING? Consideraes sobre desempenho entre WHERE e HAVING;

Como utilizar a clusula HAVING? O exemplo abaixo determina o salrio mdio de todos os departamentos que possuem mais de trs pessoas:
select deptno, avg(sal), count(*)

from emp group by deptno having count(*) > 3; DEPTNO COUNT(*) -------------------------------------30 20 2 rows selected AVG(SAL) ----------------------------------------- ----1566,666666666666666666666666666666666667 6 2175 5

O exemplo abaixo determina as funes cujo salrio mais alto igual ou superior a 3000:
select job,max(sal) from emp group by job having max(sal) >= 3000; JOB --------PRESIDENT ANALYST MAX(SAL) ---------------------5000 3000

2 rows selected

A execuo de uma consulta com WHERE, GROUP BY e HAVING segue os passos abaixo: 1. WHERE - para filtrar as linhas individuais (no pode conter funes de grupo); 2. GROUP BY - para agrupar as linhas seleccionadas no passo anterior; 3. HAVING - para excluir os grupos no requeridos; A clusula WHERE no pode incluir funes de grupo, pois a sua misso filtrar linhas e no grupos. Durante a sua execuo os grupos ainda no esto formados, pelo que as funes de grupo no podem ser calculadas. O exemplo abaixo pretende determinar os departamentos cujo salrio mdio 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 clusula WHERE no pode receber funes de grupo. A forma de resolver este problema usando a clusula HAVING:
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000; DEPTNO ---------------------20 10 2 rows selected AVG(SAL) ----------------------------------------2175 2916,666666666666666666666666666666666667

Topo

Consideraes sobre desempenho entre WHERE e HAVING Algumas consultas com grupos tanto podem ser resolvidas recorrendo a uma clusula WHERE como a uma clusula HAVING. Considere que pretende determinar o salrio mdio de cada funo (JOB) exclundo os 'MANAGER'. A soluo abaixo filtra as funes usando uma clusula WHERE:
select job,avg(sal) from emp where job !='MANAGER' group by job; JOB --------CLERK SALESMAN PRESIDENT ANALYST AVG(SAL) ---------------------1037,5 1400 5000 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 --------CLERK SALESMAN PRESIDENT ANALYST AVG(SAL) ---------------------1037,5 1400 5000 3000

4 rows selected

A clusula WHERE eliminou todos os elementos que iriam formar o conjunto MANAGER, e por isso este no foi formado. Embora ambos queries tenham resolvido o problema (foram eficazes), as duas consultas no so igualmente eficientes. A primeira consulta segue o seguinte plano de execuo: 1. Identificar todas as linhas da tabela exclundo as que tm funo MANAGER; 2. Ordenar as linhas por JOB; 3. Criar os conjuntos por JOB (agrupar); 4. Determinar a mdia de cada conjunto; A segunda consulta segue este plano de execuo: 1. 2. 3. 4. 5. Identificar todas as linhas da tabela; Ordenar as linhas por JOB; Criar os conjuntos por JOB (agrupar); Determinar a mdia de cada conjunto; Eliminar o conjunto 'MANAGER';

Comparando os dois planos de execuo verificamos que no primeiro as linhas so filtradas no inicio, o que significa que as operaes de ordenao e agrupamento so feitas sobre menos linhas. No segundo plano os grupos so formados tendo em conta todas as linhas, sendo depois eliminado um dos grupos. Quando as tabelas tem grande dimenso esta diferena 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. No deita fora trabalho j feito;

Exerccios sobre funes de grupo

1. Encontre o salrio mais baixo de todos os empregados. 2. Encontre o salrio mais baixo, mais alto e mdio de todos os empregados. 3. Determine o salrio mais alto e mais baixo de cada tipo de funo. 4. Determine quantos empregados tem a funo MANAGER. 5. Determine o salrio mdio e a remunerao total mdia (14 vezes o salrio mais a comisso) para cada tipo de funo. No se esquea que os vendedores ganham comisso. 6. Determine a diferena entre o salrio mais alto e mais baixo 7. Encontre todos os departamentos que tm mais de trs empregados. 8. Verifique se todos os nmeros de empregado so nicos. 9. Liste o salrio mais baixo dentro dos empregados de cada manager (MGR). Exclua os grupos em que o salrio mais baixo inferior a 1000. Ordene o resultado pelo salrio.

Solues dos exerccios sobre funes 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. 33. 34. 35. select deptno, count(*) from emp group by deptno having count(*) > 3;

36.

37. 8.
38. 39. 40. 41. select empno from emp group by empno having count(*) > 1;

42.

43. 9.
44. 45. 46. 47. 48. select mgr, min(sal) from emp group by mgr having min(sal)>=1000 order by min(sal);

S-ar putea să vă placă și