Merge statement - oracle

I am looking into merge statements, but I can not figure out the syntax.
Let's say I have these tables
CREATE TABLE employee (
employee_id NUMBER(5),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
dept_no NUMBER(2),
salary NUMBER(10));
INSERT INTO employee VALUES (1, 'Dan', 'Morgan', 10, 100000);
INSERT INTO employee VALUES (2, 'Helen', 'Lofstrom', 20, 100000);
INSERT INTO employee VALUES (3, 'Akiko', 'Toyota', 20, 50000);
INSERT INTO employee VALUES (4, 'Jackie', 'Stough', 20, 40000);
INSERT INTO employee VALUES (5, 'Richard', 'Foote', 20, 70000);
INSERT INTO employee VALUES (6, 'Joe', 'Johnson', 20, 30000);
INSERT INTO employee VALUES (7, 'Clark', 'Urling', 20, 90000);
CREATE TABLE bonuses (
employee_id NUMBER, bonus NUMBER DEFAULT 100);
INSERT INTO bonuses (employee_id) VALUES (1);
INSERT INTO bonuses (employee_id) VALUES (2);
INSERT INTO bonuses (employee_id) VALUES (4);
INSERT INTO bonuses (employee_id) VALUES (6);
INSERT INTO bonuses (employee_id) VALUES (7);
COMMIT;
and just for the sake of an example I want to update all entries of bonuses with 200 * employee_id. Here is my statement. What's wrong with it?
merge into bonuses b
using
(select employee_id id, 200 bonus from employees) test
on (test.id = b.employee_id)
when matched then update set
b.bonus = test.bonus * test.employee_id
Thanks!
P.S. See also my sqlfiddle here: http://sqlfiddle.com/#!4/ff425/14

merge into bonuses b
using
(select employee_id id, 200 bonus from employee) test
on (test.id = b.employee_id)
when matched then update set
b.bonus = test.bonus * test.id;
Two minor mistakes:
1) employee instead of employees
2) test.id instead of test.employee_id

Related

SQL: ORA-02291: integrity constraint violated - parent key not found

I am creating this code SQL code and I keep getting the same error from every line of the insert statements after the errors begin here statement. the error is, ORA-02291: integrity constraint violated - parent key not found. I think it has something to do with the employee section constraint EMPSUPERVRFK but, that is the only constraint that the error message would lead to.
-- keep these two commands at the top of every sql file
set echo on
set linesize 120
delete from Employee;
commit;
-- insert only managers first with their dno is null
INSERT INTO Employee VALUES
('James','E','Borg',888665555,'10-NOV-1937','450 Stone, Houston, TX','M',55000,null,null);
INSERT INTO Employee VALUES
('Franklin','T','Wong',333445555, to_date('1955-12-08', 'YYYY-MM-DD'), '638 Voss, Houston, TX','M',40000,888665555,null);
INSERT INTO Employee VALUES
('Jennifer','J','Zelaya',987654321,'20-JUN-1941','291 Berry, Bellaire, TX','F',43000,888665555,null);
delete from Department;
commit;
insert into Department values ('Research',5,333445555,'22-MAY-1988');
insert into Department values ('Headquarters',1,888665555,'19-JUN-1981');
insert into Department values ('Administration',1,888665555,'01-JAN-1995');
-- now, update employee.dno for managers
UPDATE Employee SET dno = 1 WHERE ssn = 888665555;
UPDATE Employee SET dno = 5 WHERE ssn = 333445555;
-- need to update the rest of managers
-- insert the rest of non-manager employees, supervisors first
--errors begin here
delete from Employee;
commit;
INSERT INTO Employee VALUES ('John','B','Smith',123456789,'09-JAN-1965','731 Fondren, Houston, TX','M',30000,333445555,5);
insert into Employee values ('Alica','J','Zelya',999887777,'19-JAN-1968','3321 Castle, Spring, TX','F',25000,987654321,4);
insert into Employee values ('Ramesh','K','Narayan',666884444,'15-SEP-1962', '975 Fire Oak, Humnle, TX','M',38000,333445555,5);
insert into Employee values ('Joyce','A','English',453453453,'31-JUL-1972','5631 Rice, Houston, TX','F',25000,333445555,5);
insert into Employee values ('Ahmad','V','Jabbar',987987987,'29-MAR-1969','980 Dallas, Houston, TC','M',25000,987654321,4);
--Project
delete from PROJECT;
commit;
insert into PROJECT values ('ProductY',2,'Sugarland',5);
insert into PROJECT values ('ProductZ',3,'Houston',5);
insert into PROJECT values ('Computerication',10,'Stafford',4);
insert into PROJECT values ('Reorganization',20,'Houston',1);
insert into PROJECT values ('Newbenefits',30,'Stafford',4);
--dept_Locations
delete from DEPT_LOCATIONS;
commit;
insert into DEPT_LOCATIONS values (1, 'Houston');
insert into DEPT_LOCATIONS values (4,'Stafford');
insert into DEPT_LOCATIONS values (5,'Bellaire');
insert into DEPT_LOCATIONS values (5,'Sugarland');
insert into DEPT_LOCATIONS values (5,'Houston');
--works_on 16
delete from WORKS_ON;
commit;
insert into WORKS_ON values (123456789,1,32.5);
insert into WORKS_ON values (123456789,2,7.5);
insert into WORKS_ON values (666884444,3,40.0);
insert into WORKS_ON values (453453453,1,20.0);
insert into WORKS_ON values (453453453,2,20.0);
insert into WORKS_ON values (333445555,2,10.0);
insert into WORKS_ON values (333445555,3,10.0);
insert into WORKS_ON values (333445555,10,10.0);
insert into WORKS_ON values (333445555,20,10.0);
insert into WORKS_ON values (999887777,30,30.0);
insert into WORKS_ON values (999887777,10,10.0);
insert into WORKS_ON values (987987987,10,35.0);
insert into WORKS_ON values (987987987,30,5.0);
insert into WORKS_ON values (987654321,30,20.0);
insert into WORKS_ON values (987654321,20,15.0);
insert into WORKS_ON values (888665555,20,null);
--dependent 7
delete from DEPENDENT;
commit;
insert into DEPENDENT values (333445555,'Alice','F','05-APR-1986','Daughter');
insert into DEPENDENT values (333445555,'Theodore','M','25-OCT-1983','Son');
insert into DEPENDENT values (333445555,'Joy','F', '03-MAY-1958','Spouse');
insert into DEPENDENT values (987654321,'Abner','M', '28-FEB-1942','Spouse');
insert into DEPENDENT values (123456789,'Michael','M','04-JAN-1988','Son');
insert into DEPENDENT values (123456789,'Alice','F','30-DEC-1988','Daughter');
insert into DEPENDENT values (123456789,'Elizabeth','F', '05-MAY-1967','Spouse');
-----------------------------------------------------------------------------------
set echo on
set linesize 120
drop table Employee cascade constraints;
commit;
create table Employee
(
fname varchar2(15),
minit varchar2(1), -- can be char
lname varchar2(15),
ssn number,
bdate date,
address varchar2(50),
sex varchar2(1) CHECK(Sex = 'M' or Sex = 'F'),
salary number CHECK(20000 <= salary AND 100000 >= salary),
superssn number,
dno number DEFAULT 0,
constraint EMPPK
primary key(ssn),
constraint EMPSUPERVRFK
foreign key(superssn) references Employee(ssn)
ON DELETE SET NULL
);
drop table Department cascade constraints;
commit;
create table Department
(
dname varchar2(15),-- NOT NULL,
dnumber number,
mgrssn number,
mgrstartdate date,
constraint DEPTPK
primary key(dnumber),
constraint DEPTMGRFK
foreign key(mgrssn) references Employee(ssn)
ON DELETE SET NULL
);
alter table Employee add
constraint EMPDEPTFK foreign key(dno) references Department(dnumber)
ON DELETE SET NULL;
drop table DEPT_LOCATIONS;
create table DEPT_LOCATIONS
(
Dnumber number,
Dlocation varchar2(15),
constraint PK_DnoDloc primary key(Dnumber,Dlocation)
);
COMMIT;
drop table PROJECT;
create table PROJECT
(
Pname varchar2(15),
Ponumber number primary key,
Plocation varchar2 (15),
Dnum number,
foreign key (Dnum) references Department(dnumber)
);
Commit;
drop table DEPENDENT;
create table DEPENDENT
(
Essn number,
Dependent_name varchar2(15),
Sex Char,
Bdate Date,
Relationship varchar2(15),
foreign key(Essn) references Employee(ssn) --
ON DELETE SET NULL,
constraint PK_essn
primary key(Essn,Dependent_name)
);
COMMIT;
drop table WORKS_ON;
create table WORKS_ON
(
Essn number,
Pno number,
Hours number,
foreign key(Essn) references Employee(ssn)--
ON DELETE SET NULL,
foreign key(Pno) references PROJECT(Ponumber)
ON DELETE SET NULL,
constraint PK_SSN
primary key(Essn, Pno)
);
commit;
----------------------------------------------------------------
-- keep these two commands at the top of every sql file
set echo on
set linesize 120
-- test queries, not to be submitted
select count(*) from employee;
select count(*) as DEPT_COUNT from department;
-- comment out the above queries for your homework
-- a the first name, last name of employees who work in department 5.
select fname, lname from employee where dno = 5;
-- b the first name, last name of every employee and name of his/her department
select E.fname as FIRST_NAME, E.lname LAST_NAME, D.dname DEPARTMENT_NAME
from employee E, department D
where E.dno = D.dnumber;
--c The first name, last name of employees who works at the 'Research' department
select e.fname , e.lname , Dname
from employee e inner join department d on e.dno=d.dname
where d.name ='Research';
--d. The first name, last name of employee who is the manager of the 'Research' department
select e.fname , e.lname , Dname
from employee e inner join department d on e.dno=d.dname
where d.name ='Research' and e.super_ssn=d.mgr_ssn;
--e. The first name, last name of employees who works on the 'Computerization' project.
select e.fname,e.lname
from employee e inner join department d on e.dno=d.dnumber inner join project p on d.dnumber=p.dnum
where p.pname="Computerization";
this happens because you are inserting values to table that depends on other table that is still empty, you should insert on that table first before this one
for example, suppose you have employee table, and department table, in which every employee must be assigned to a department, so when you input employee Bob to department IT, it would result in error, since there is no IT yet in department table. so you need to input IT on department table, then you can input Bob to employee table
or, you can disable integrity check when importing sql, but this setting is different for each DB engine, so I can't give you an example

Hierarchical Queries inside Join

I'm facing one annoying problema and I would like some help.
This is the situation.
CREATE TABLE tree_hierarchy (
id NUMBER (20)
,parent_id NUMBER (20)
);
CREATE TABLE tree_information (
id NUMBER (20)
,some_text VARCHAR(20)
,tree_id NUMBER (20)
);
INSERT INTO tree_hierarchy (id, parent_id) VALUES (2, null);
INSERT INTO tree_hierarchy (id, parent_id) VALUES (4, 2);
INSERT INTO tree_hierarchy (id, parent_id) VALUES (9, 4);
INSERT INTO tree_hierarchy (id, parent_id) VALUES (20, null);
INSERT INTO tree_hierarchy (id, parent_id) VALUES (40, 20);
INSERT INTO tree_hierarchy (id, parent_id) VALUES (90, 40);
INSERT INTO tree_information (id, some_text, tree_id) VALUES (10,'Some teste', 2);
INSERT INTO tree_information (id, some_text, tree_id) VALUES (11,'Other tree', 20);
And i would like to do something like this.
SELECT hier.*
FROM tree_information Ti
JOIN (
SELECT
id,
parent_id
FROM tree_hierarchy th
where connect_by_isleaf = 1
START WITH th.id = ti.tree_id
CONNECT BY PRIOR th.id = th.parent_id
) hier on 1=1;
but ti.tree_id is not visible inside the select.
If I change the start with condition for
START WITH th.parent_id is null
Will stay wrong.
Someone has idea how to solve this situation ?
I would appreciate if you provide expected result explicitly.
My best guess is:
SELECT hier.*, ti.*
FROM tree_information Ti
JOIN (
SELECT
id,
parent_id,
connect_by_root th.id as tree_id
FROM tree_hierarchy th
where connect_by_isleaf = 1
START WITH th.id in ( select tii.tree_id from tree_information Tii)
CONNECT BY PRIOR th.id = th.parent_id
) hier on ti.tree_id = hier.tree_id;
ID PARENT_ID TREE_ID ID SOME_TEXT TREE_ID
9 4 2 10 Some teste 2
90 40 20 11 Other tree 20

How to bind horizontal values of a table to a vertical values of another table in oracle database

i have 2 tables .
The columns start with attributes are change based on department. the description of attributes are here
My requirement is to get the values of each attributes with its primary key based on the department as table bellow.
Honestly i am stuck on this problem in my program. I have no permission to change the tables and there is no common unique key column.i would appreciate if anyone could provide me a suggestion.
with a as (
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a),
e as (
select employeeId, department, attribute1, 1 rn from employees union all
select employeeId, department, attribute2, 2 rn from employees union all
select employeeId, department, attribute3, 3 rn from employees
)
select e.employeeId, a.attributeid, e.department, a.attribute, a.meaning,
e.attribute1 as value
from e join a on a.department=e.department and a.rn=e.rn
order by e.employeeId, a.attributeid
Test data and output:
create table employees (employeeID number(3), name varchar2(10), department varchar2(5), age number(3), attribute1 varchar2(10), attribute2 varchar2(10), attribute3 varchar2(10));
insert into employees values (1, 'john', 'IT', 22, 'attr1val1', 'attr2val2', null);
insert into employees values (2, 'jane', 'HR', 32, 'attr1val3', 'attr2val4', 'attr3val5');
insert into employees values (3, 'joe', 'HR', 23, 'attr1val6', 'attr2val7', 'attr3val8');
insert into employees values (4, 'jack', 'IT', 45, 'attr1val9', 'attr2val10', null);
create table attributes (attributeID number(3), department varchar2(10), attribute varchar2(10), meaning varchar2(10));
insert into attributes values (1, 'IT', 'attribute1', 'laptoptype');
insert into attributes values (2, 'IT', 'attribute2', 'networkloc');
insert into attributes values (3, 'HR', 'attribute1', 'location');
insert into attributes values (4, 'HR', 'attribute2', 'position');
insert into attributes values (5, 'HR', 'attribute3', 'allocation');
EMPLOYEEID ATTRIBUTEID DEPARTMENT ATTRIBUTE MEANING VALUE
---------- ----------- ---------- ---------- ---------- ----------
1 1 IT attribute1 laptoptype attr1val1
1 2 IT attribute2 networkloc attr2val2
2 3 HR attribute1 location attr1val3
2 4 HR attribute2 position attr2val4
2 5 HR attribute3 allocation attr3val5
3 3 HR attribute1 location attr1val6
3 4 HR attribute2 position attr2val7
3 5 HR attribute3 allocation attr3val8
4 1 IT attribute1 laptoptype attr1val9
4 2 IT attribute2 networkloc attr2val10
Edit: Explanation
In answer I used with
clause just to divide solution into readable steps. You can move them into from clause of main query if it is
more comfortable for you. Anyway: subquery a reads data from table attributes and adds number for rows,
so for each department they are allways numbered from 1. I used row_number() for that. Subquery e unions (all) required attributes and numbers
them accordingly. Numbers generated in both subqueries are then used in main join: a.department=e.department and a.rn=e.rn.
Alternative 1 - if you are using Oracle 11g you could use the unpivot. See what is generated by subquery, and how it is joined with attributes table:
with e as (
select employeeId, name, department, attribute, value from employees
unpivot (value for attribute in ("ATTRIBUTE1", "ATTRIBUTE2", "ATTRIBUTE3"))
)
select e.employeeId, a.attributeid, e.department, a.attribute,
a.meaning, e.value
from e join attributes a on a.department=e.department
and lower(a.attribute)=lower(e.attribute)
order by e.employeeId, a.attributeid;
Alternative 2 - with hierarchical subquery generator (subquery r), realised by connect by which simple creates numbers from 1, 2, 3 which are next joined with employees and proper attribute
is attached as value in case clause. Rest is made in similiar way like in original answer.
with a as (
select a.*, row_number() over (partition by department order by attributeID) rn
from attributes a),
r as (select level rn from dual connect by level<=3),
e as (
select employeeId, department, rn,
case when r.rn = 1 then attribute1
when r.rn = 2 then attribute2
when r.rn = 3 then attribute3
end value
from employees cross join r
)
select e.employeeId, a.attributeid, e.department, a.attribute,
a.meaning, e.value
from e join a on a.department=e.department and a.rn=e.rn
order by e.employeeId, a.attributeid
All three versions gave me the same output. I also tested first option on similiar table with 100k rows and get output in few seconds (for 5 attributes). Please test all solutions and try to understand them. If you can use unpivot version I would prefer this.
Sorry for delayed explanation and any language mistakes.
The WITH clause was added with Oracle 9.2 and should do the trick. For the other attributes just add more sub queries where the filter is att.attribute = 'attribute2' or 'Attribute3'...
WITH e AS
(SELECT emp.employee_ID, emp.department, emp.attribute1
FROM employee emp),
a AS (SELECT att.attribute_id, att.attribute, att.meaning
FROM attribute_TYPE att
WHERE att.attribute = 'attribute1')a
SELECT e.employeeid, att.attributeid, e.department, a.attribute,
a.meaning e.attribute1
FROM e JOIN a ON e.department = a.department

PL/SQL Displaying Results

I have difficulty writing a PL/SQL Statement to display the following output.
These are my tables:
Employee (E#, FName, LName,...)
SkillPossessed (E#, SName, Level) (Employee may possessed more than 1 skills)
I need to display the output as follow:
1 Mary Loo:Sewing,Dancing,Cooking
2 Peter Pan:Painting, Singing
...
How do I do it?
Thanks
No need for PL/SQL, just use LISTAGG.
create table employee (id number, fname varchar2(20), lname varchar2(20), primary key (id));
create table skillpossessed(employee_id number, sname varchar2(20), lvl number, constraint fk_employee_id foreign key(employee_id) references employee(id));
insert into employee values (1, 'Mary', 'Loo');
insert into employee values (2, 'Peter', 'Pan');
insert into skillpossessed values (1, 'Sewing', 1);
insert into skillpossessed values (1, 'Dancing', 2);
insert into skillpossessed values (1, 'Cooking', 5);
insert into skillpossessed values (2, 'Painting', 3);
insert into skillpossessed values (2, 'Singing', 1);
select e.id, e.fname, e.lname, listagg (s.sname, ',')
within group (order by s.sname) as skills
from employee e, skillpossessed s
where e.id = s.employee_id group by e.id, e.fname, e.lname;
ID FNAME LNAME SKILLS
---------- ------ ----- ----------------------
1 Mary Loo Cooking,Dancing,Sewing
2 Peter Pan Painting,Singing

Merge is not returning right data

I have 2 tables:
CREATE TABLE employee (
employee_id NUMBER(5),
first_name VARCHAR2(20),
last_name VARCHAR2(20),
dept_no NUMBER(2),
salary NUMBER(10));
Table employee has values:
(1, 'Dan', 'Morgan', 10, 100000);
(2, 'Helen', 'Lofstrom', 20, 100000);
(3, 'Akiko', 'Toyota', 20, 50000);
(4, 'Jackie', 'Stough', 20, 40000);
(5, 'Richard', 'Foote', 20, 70000);
(6, 'Joe', 'Johnson', 20, 30000);
(7, 'Clark', 'Urling', 20, 90000);
CREATE TABLE bonuses (
employee_id NUMBER, bonus NUMBER DEFAULT 100);
Table bonuses has values:
(1,100);
(2,100);
(4,100);
(6,100);
(7,100);
And I did merge based on bonuses table:
MERGE INTO bonuses b
USING (
SELECT employee_id, salary, dept_no
FROM employee
WHERE dept_no =20) e
ON (b.employee_id = e.employee_id)
WHEN MATCHED THEN
UPDATE SET b.bonus = e.salary * 0.1
DELETE WHERE (e.salary < 40000)
WHEN NOT MATCHED THEN
INSERT (b.employee_id, b.bonus)
VALUES (e.employee_id, e.salary * 0.05)
WHERE (e.salary > 40000);
And when I
select * from bonuses;
EMPLOYEE_ID BONUS
------------------
1 100
2 10000
3 2500
4 4000
5 3500
7 9000
My question is "where is my bonuses record for employee_id #6"?
Deleted by DELETE WHERE (e.salary < 40000) statement?.
And You should probably make one of you conditions to include equality.
After all someone salary may be just 40K just like Jackie's.

Resources