Após o término do Capítulo:
Manipular dados utilizando sub-consultas.
Descrever as características de INSERTs em múltiplas tabelas.
Utilizar os tipos de INSERTs em múltiplas tabelas: ◦ INSERT Incondicional.
◦ INSERT Pivotante.
◦ ALL INSERT Condicional.
◦ FIRST INSERT Condicional.
Comando MERGE.
Rastrear as alterações de dados em um período.
É possível utilizar sub-consultas em DML para:
◦ Copiar dados de uma tabela para outra.
◦ Recuperar dados de uma view inline.
◦ Atualizar dados em uma tabela com base em valores de outra tabela.
◦ Remover linhas de uma tabela com base em linhas de outra tabela.
Copiando linhas de outras tabelas:
Inserts com sub-consulta como destino:
INSERT INTO sales_reps(id, name, salary, commission_pct)
SELECT employee_id, last_name, salary, commission_pct
FROM employees
WHERE job_id LIKE '%REP%';
INSERT INTO
(SELECT employee_id, last_name,
email, hire_date, job_id, salary,
department_id
FROM empl3
WHERE department_id = 50)
VALUES (99999, 'Taylor', 'DTAYLOR',
TO_DATE('07-JUN-99', 'DD-MON-RR'),
'ST_CLERK', 5000, 50);
Recuperando dados a partir de uma sub-consulta:
SELECT a.last_name, a.salary,
a.department_id, b.salavg
FROM employees a JOIN(SELECT department_id,
AVG(salary) salavg
FROM employees
GROUP BY department_id) b
ON a.department_id = b.department_id
AND a.salary > b.salavg;
…
Atualizando diversas colunas com sub-consultas:
UPDATE empl3
SET job_id = (SELECT job_id
FROM employees
WHERE employee_id = 205),
salary = (SELECT salary
FROM employees
WHERE employee_id = 168)
WHERE employee_id = 114;
Removendo linhas utilizando sub-consultas:
DELETE FROM empl3
WHERE department_id =
(SELECT department_id
FROM departments
WHERE department_name
LIKE '%Public%');
1 row deleted.
Utilizando o WITH CHECK OPTION: ◦ Proíbe a alteração de linhas que não fazem parte do
contexto da sub-consulta:
INSERT INTO (SELECT employee_id, last_name, email,
hire_date, job_id, salary
FROM empl3
WHERE department_id = 50
WITH CHECK OPTION)
VALUES (99998, 'Smith', 'JSMITH',
TO_DATE('07-JUN-99', 'DD-MON-RR'),
'ST_CLERK', 5000);
INSERT INTO
*
ERROR at line 1:
ORA-01402: view WITH CHECK OPTION where-clause violation
A palavra-chave DEFAULT pode ser usada explicitamente:
◦ Em comandos INSERT e UPDATE.
◦ Para permitir que o usuário controle onde e quando o valor default deve ser aplicado ao dado.
◦ Para atender ao padrão SQL:1999.
INSERT INTO deptm3
(department_id, department_name, manager_id)
VALUES (300, 'Engineering', DEFAULT);
UPDATE deptm3
SET manager_id = DEFAULT
WHERE department_id = 10;
INSERT ALL
INTO table_a VALUES(…,…,…)
INTO table_b VALUES(…,…,…)
INTO table_c VALUES(…,…,…)
SELECT …
FROM sourcetab
WHERE …;
Table_a
Table_b
Table_c
O comando INSERT...SELECT pode seu usado para inserir linhas em múltiplas tabelas em um único comando DML.
Inserts em Múltiplas Tabelas podem ser usados em Data Warehousing para transferir dados de uma ou mais tabelas para um conjunto de tabelas destino.
Tem aumento significativo de performance sobre:
◦ Múltiplos comandos INSERT...SELECT.
◦ Uma procedure para executar múltiplos inserts por meio de sintaxe IF...THEN.
Tipos de Inserts em Múltiplas Tabelas (Multitable):
◦ INSERT Incondicional
◦ ALL INSERT Condicional
◦ FISRT INSERT Condicional
◦ INSERT Pivotante
Sintaxe:
◦ conditional_insert_clause:
INSERT [ALL] [conditional_insert_clause]
[insert_into_clause values_clause] (subquery)
[ALL] [FIRST]
[WHEN condition THEN] [insert_into_clause values_clause]
[ELSE] [insert_into_clause values_clause]
Selecione o EMPLOYEE_ID, HIRE_DATE, SALARY e MANAGER_ID da tabela EMPLOYEES para os empregados cujos Ids sejam superiores a 200.
Insira esses valores nas tabelas SAL_HISTORY e MGR_HISTORY.
INSERT ALL
INTO sal_history VALUES(EMPID,HIREDATE,SAL)
INTO mgr_history VALUES(EMPID,MGR,SAL)
SELECT employee_id EMPID, hire_date HIREDATE,
salary SAL, manager_id MGR
FROM employees
WHERE employee_id > 200;
12 rows created.
Selecione o EMPLOYEE_ID, HIRE_DATE, SALARY e MANAGER_ID da tabela EMPLOYEES para os empregados cujos Ids sejam superiores a 200.
Se o salário for superior a $10,000, insira esses valores na tabela SAL_HISTORY.
Se o manager_id for superior a 200, insira esses valores na tabela MGR_HISTORY.
INSERT ALL
WHEN SAL > 10000 THEN
INTO sal_history VALUES(EMPID,HIREDATE,SAL)
WHEN MGR > 200 THEN
INTO mgr_history VALUES(EMPID,MGR,SAL)
SELECT employee_id EMPID,hire_date HIREDATE,
salary SAL, manager_id MGR
FROM employees
WHERE employee_id > 200;
4 rows created.
Selecione o DEPARTMENT_ID, SUM(SALARY) e MAX(HIRE_DATE) da tabela DEPARTMENTS.
Se a soma do salário for superior a $25,000, então insira o valor na tabela SPECIAL_SAL.
Se a primeira condição WHEN for verdadeira, então os WHEN subseqüentes nem são avaliados.
Para as linhas que não satisfizerem a primeira condição WHEN, insira as linhas nas tabelas HIREDATE_HISTORY_00 a HIREDATE_HISTORY_99, com base em sua HIRE_DATE.
Não satisfazendo a nenhuma condição, insira na tabela HIREDATE_HISTORY.
INSERT FIRST
WHEN SAL > 25000 THEN
INTO special_sal VALUES(DEPTID, SAL)
WHEN HIREDATE like ('%00%') THEN
INTO hiredate_history_00 VALUES(DEPTID,HIREDATE)
WHEN HIREDATE like ('%99%') THEN
INTO hiredate_history_99 VALUES(DEPTID, HIREDATE) ELSE
INTO hiredate_history VALUES(DEPTID, HIREDATE)
SELECT department_id DEPTID, SUM(salary) SAL,
MAX(hire_date) HIREDATE
FROM employees
GROUP BY department_id;
12 rows created.
Suponha que você receba um conjunto de registros de vendas de uma tabela não-relacional chamada SALES_SOURCE_DATA no seguinte formato: ◦ EMPLOYEE_ID, WEEK_ID, SALES_MON, SALES_TUE,
SALES_WED, SALES_THUR, SALES_FRI
Você quer armazenar esses registros na tabela SALES_INFO em formato relacional: ◦ EMPLOYEE_ID, WEEK, SALES
Para tanto, a utilização de um comando Insert Pivotante é bastante útil!
INSERT ALL
INTO sales_info VALUES (employee_id,week_id,sales_MON)
INTO sales_info VALUES (employee_id,week_id,sales_TUE)
INTO sales_info VALUES (employee_id,week_id,sales_WED)
INTO sales_info VALUES (employee_id,week_id,sales_THUR)
INTO sales_info VALUES (employee_id,week_id, sales_FRI)
SELECT EMPLOYEE_ID, week_id, sales_MON, sales_TUE,
sales_WED, sales_THUR,sales_FRI
FROM sales_source_data;
5 rows created.
É possível inserir ou atualizar registros em uma tabela condicionalmente por meio do comando MERGE.
Sintaxe:
MERGE INTO table_name table_alias
USING (table|view|sub_query) alias
ON (join condition)
WHEN MATCHED THEN
UPDATE SET
col1 = col_val1,
col2 = col2_val
WHEN NOT MATCHED THEN
INSERT (column_list)
VALUES (column_values);
Insira ou atualize linhas na tabela EMPL3 de acordo com a tabela EMPLOYEES.
MERGE INTO empl3 c
USING employees e
ON (c.employee_id = e.employee_id)
WHEN MATCHED THEN
UPDATE SET
c.first_name = e.first_name,
c.last_name = e.last_name,
...
c.department_id = e.department_id
WHEN NOT MATCHED THEN
INSERT VALUES(e.employee_id, e.first_name, e.last_name,
e.email, e.phone_number, e.hire_date, e.job_id,
e.salary, e.commission_pct, e.manager_id,
e.department_id);
MERGE INTO empl3 c
USING employees e
ON (c.employee_id = e.employee_id)
WHEN MATCHED THEN
UPDATE SET
...
WHEN NOT MATCHED THEN
INSERT VALUES...;
TRUNCATE TABLE empl3;
SELECT *
FROM empl3;
no rows selected
SELECT *
FROM empl3;
107 rows selected.
SELECT salary FROM employees3
WHERE employee_id = 107;
UPDATE employees3 SET salary = salary * 1.30
WHERE employee_id = 107;
COMMIT;
SELECT salary FROM employees3
VERSIONS BETWEEN SCN MINVALUE AND MAXVALUE
WHERE employee_id = 107;
1
2
3
SELECT versions_starttime "START_DATE",
versions_endtime "END_DATE",
salary
FROM employees
VERSIONS BETWEEN SCN MINVALUE
AND MAXVALUE
WHERE last_name = 'Lorentz';
A Cláusula VERSIONS BETWEEN:
Objetivos:
◦ Executar Inserts em Múltiplas Tabelas.
◦ Executar operações de MERGE.
◦ Rastrear versões de linhas de tebelas.
Crie a tabela SAL_HISTORY que possuirá o histórico salarial dos empregados:
DROP TABLE SAL_HISTORY;
CREATE table SAL_HISTORY
(EMPLOYEE_ID NUMBER(6),
HIRE_DATE DATE,
SALARY NUMBER(8,2));
Depois de criada, descreva sua estrutura e confirme.
Crie a tabela MGR_HISTORY que possuirá o histórico de gerentes e salários dos empregados:
DROP TABLE MGR_HISTORY;
CREATE table MGR_HISTORY
(EMPLOYEE_ID NUMBER(6),
MANAGER_ID NUMBER(6),
SALARY NUMBER(8,2));
Depois de criada, descreva sua estrutura e confirme.
Crie a tabela SPECIAL_SAL que possuirá o ID e salário dos empregados que possuem salários especiais:
DROP TABLE SPECIAL_SAL;
CREATE table SPECIAL_SAL
(EMPLOYEE_ID NUMBER(6),
SALARY NUMBER(8,2));
Depois de criada, descreva sua estrutura e confirme.
1. Escreva uma consulta que:
₋ Recupere o ID, Data de Contratação, Salário e ID do Gerente de todos os empregados cujos Ids sejam menor que 125.
₋ Se o salário for maior que $20.000, insira o ID do empregado e seu salário na tabela SPECIAL_SAL.
₋ Insira o ID do empregado, sua data de contratação e seu salário na tabela SAL_HISTORY.
₋ Insira o ID do empregado, o ID de seu gerente e seu salário na tabela MGR_HISTORY.
Liste os registros das 3 tabelas e analise os resultados.
1. Solução:
INSERT ALL
WHEN SAL > 20000 THEN
INTO special_sal VALUES (EMPID, SAL)
ELSE
INTO sal_history VALUES(EMPID, HIREDATE, SAL)
INTO mgr_history VALUES(EMPID, MGR, SAL)
SELECT employee_id EMPID, hire_date HIREDATE,
salary SAL, manager_id MGR
FROM employees
WHERE employee_id < 125;
Crie a tabela SALES_SOURCE_DATA com informações do ID do empregado e vendas dos dias da semana:
DROP TABLE SALES_SOURCE_DATA;
CREATE TABLE SALES_SOURCE_DATA
(employee_id NUMBER(6),
WEEK_ID NUMBER(2),
SALES_MON NUMBER(8,2),
SALES_TUE NUMBER(8,2),
SALES_WED NUMBER(8,2),
SALES_THUR NUMBER(8,2),
SALES_FRI NUMBER(8,2));
Depois de criada, descreva sua estrutura e confirme.
Insira na tabela SALES_SOURCE_DATA o seguinte registro:
INSERT INTO SALES_SOURCE_DATA
VALUES (178, 6, 1750, 2200, 1500, 1500, 3000);
commit;
Faça um select na tabela SALES_SOURCE_DATA e confirme que o registro foi inserido corretamente.
Crie a tabela SALES_INFO com a instrução a seguir:
DROP TABLE SALES_INFO;
CREATE TABLE SALES_INFO
(employee_id NUMBER(6),
WEEK NUMBER(2),
SALES NUMBER(8,2));
Descreva a estrutura da tabela e confirme.
2. Escreva uma consulta que:
₋ Recupere o ID do empregado, ID da semana e vendas para cada um dos dias da semana da tabela SALES_SOURCE_DATA.
₋ Crie uma transformação de tal modo que cada registro recuperado da SALES_SOURCE_DATA seja convertido em múltiplos registros na tabela SALES_INFO.
₋ Dica: Use Insert Pivotante!
Liste os registros das 2 tabelas e analise os resultados.
2. Solução:
INSERT ALL
INTO sales_info VALUES (employee_id, week_id, sales_MON)
INTO sales_info VALUES (employee_id, week_id, sales_TUE)
INTO sales_info VALUES (employee_id, week_id, sales_WED)
INTO sales_info VALUES (employee_id, week_id, sales_THUR)
INTO sales_info VALUES (employee_id, week_id, sales_FRI)
SELECT employee_id, week_id, sales_MON, sales_TUE, sales_WED, sales_THUR, sales_FRI
FROM sales_source_data;
Crie a tabela SALES_INFO com a instrução a seguir:
DROP TABLE SALES_INFO;
CREATE TABLE SALES_INFO
(employee_id NUMBER(6),
WEEK NUMBER(2),
SALES NUMBER(8,2));
Descreva a estrutura da tabela e confirme.
3. Você tem os dados antigos de empregados armazenados em um arquivo texto chamado emp.dat. Você deseja armazenar os nomes (primeiro e sobrenome) e e-mails dos empregados antigos e atuais em uma única tabela chamada EMP_DATA.
Para tanto, é preciso criar uma tabela externa usando o arquivo emp.dat como origem:
CREATE TABLE emp_data
(first_name VARCHAR2(20)
,last_name VARCHAR2(20)
, email VARCHAR2(45))
ORGANIZATION EXTERNAL
( TYPE oracle_loader
DEFAULT DIRECTORY emp_dir
ACCESS PARAMETERS
(RECORDS DELIMITED BY NEWLINE CHARACTERSET US7ASCII
NOBADFILE
NOLOGFILE
FIELDS
( first_name POSITION ( 1:20) CHAR
, last_name POSITION (22:41) CHAR
, email POSITION (43:72) CHAR ))
LOCATION ('emp.dat‘)) ;
Crie a tabela EMP_HIST com a instrução a seguir:
DROP TABLE emp_hist;
CREATE TABLE emp_hist AS
SELECT first_name, last_name, email
FROM employees;
Descreva a estrutura da tabela EMP_HIST e confirme.
3. Faça um MERGE dos dados da tabela EMP_DATA criada a partir do arquivo texto na tabela EMP_HIST criada a partir da tabela EMPLOYEES. Assuma que os dados na tabela EMP_DATA estejam atualizados. Assim, se um registro existir na EMP_HIST, apenas atualize o e-mail. Caso o registro ainda não exista em EMP_HIST, insira-o. Para saber se um registro existe ou não na tabela EMP_HIST, utilize o primeiro nome e sobrenome para comparar os registros.
Depois, liste os registros da tabela EMP_HIST e analise os resultados.
3. Solução:
MERGE INTO EMP_HIST f USING EMP_DATA h
ON (f.first_name = h.first_name
AND f.last_name = h.last_name)
WHEN MATCHED THEN
UPDATE SET f.email = h.email
WHEN NOT MATCHED THEN
INSERT ( f.first_name,
f.last_name,
f.email)
VALUES (h.first_name,
h.last_name,
h.email);
Crie a tabela EMP3 com a instrução a seguir:
DROP TABLE emp3;
CREATE TABLE emp3 AS
SELECT * FROM employees;
Descreva a estrutura da tabela EMP3 e confirme.
4. Na tabela EMP3, altere o departamento do empregado de sobrenome Kochhar para 60 e faça o commit. Então, altere novamente o departamento para 50 e faça o commit. Por fim, rastreie as alterações feitas ao empregado Kochhar utilizando a feature de ROW VERSIONS.
4. Solução:
update emp3 set department_id =60
where last_name ='Kochhar';
commit;
update emp3 set department_id =50
where last_name ='Kochhar';
commit;
select versions_starttime "START_DATE",
versions_endtime "END_DATE“, department_id
from emp3 versions between scn minvalue and maxvalue
where last_name ='Kochhar';