Oracle Insert all data from another table contain duplicates how to avoid - oracle

have two tables A and B both same structure except B has one addition extra column inserting as "null". I need to Retain all data from A in B when I insert like below query it is inserting duplicate values because of that getting "primary Key violation error" when I try to create the "CONSTRAINT PK_Details_A PRIMARY KEY" Please help on this to avoid duplicate values while inserting the records.
Thanks in advance.
Insert into tableB(
id, effectiveDate, endDate
,startDate, Type, salary
,baseSalary, Amount, Amount1
,currency, Percentage, Salary
,Notional
)
select id, effectiveDate, endDate
,startDate, Type, salary
,baseSalary, Amount, Amount1
,currency, Percentage, Salary,null
from tableA;
EDIT
Primary key definition for B copied from comment below:
ALTER TABLE B
ADD CONSTRAINT PK_B
PRIMARY KEY ( oid)
USING INDEX ( CREATE UNIQUE INDEX PK_B ON B ( oid )

Related

(Beginner) How to exclude null value from Oracle Inner Join Statement Result and How to show ONLY null data in any of the attributes

(Beginner)
Q1) How to exclude null value from Oracle Inner Join Statement Result. i.e. to display only that row which has all the values (i.e. no null data in any of the attribute)
Q2) How to show ONLY those record/s who has missing/null data in any of the attributes in any of the four table
Below is the dummy example in oracle sql
Created 4 Tables i.e.,
name , details , social , address
`create table name
(
id number,
firstname varchar2(20),
lastname varchar2(20)
);
create table details
(
id number,
dob_month varchar2(20),
dob_day varchar2(20),
dob_year varchar2(20)
);
create table social
(
id number,
ssn varchar2(20),
telephone number
);
create table address
(
id number,
address varchar2(20)
);
`
Now insert dummy data into the above tables
`insert into name values (1, 'Will' , 'Smith');
insert into name values (2, 'Barry' , 'White');
insert into name values (3, 'Tom' , 'Jones');
insert into name values (4, 'Rod' , 'Stewart');
insert into name values (5, 'Elvis' , 'Presley');
insert into details values (1,'May',31,null);
insert into details values (2,'August',22,1980);
insert into details values (3,'October',null,1973);
insert into details values (4,'January',30,1980);
insert into details values (5,'March',11,1980);
insert into social values (1,'123-45-6789',null);
insert into social values (2,'222-45-5555',789456123);
insert into social values (3,'333-45-7777',888888888);
insert into social values (4,null,693456741);
insert into social values (5,'999-45-1111',null);
insert into address values (null, null);
insert into address values (2, '12th street');
insert into address values (null, null);
insert into address values (4, '14th Avenue');
insert into address values (5, null);`
Q1 Pictorial Explanation
For Q1,
I tried with below oracle sql query (both returns the same result) but not able to figure out the exact query which will exclude null value from Oracle Inner Join Statement Result and display only that row which has all the values (i.e. not null)
`select name.id, firstname, lastname, dob_month, dob_year, ssn, telephone, address
from name, details, social, address
where name.id=details.id
and details.id=social.id
and social.id=address.id;
select name.id, firstname, lastname, dob_month, dob_year, ssn, telephone, address
from name join details on name.id=details.id
join social on details.id=social.id
join address on social.id=address.id;`
For Q2, I am looking for sample Query
i.e. How to show ONLY those record/s who has missing/null data in any of the attributes in any of the four table
For the first question, I think you are looking for this:
select name.id, firstname, lastname, dob_month, dob_year, ssn, telephone, address
from name
join details on name.id=details.id
join social on details.id=social.id
join address on social.id=address.id
where dob_year is not null
and dob_day is not null
and telephone is not null
and ssn is not null
and address is not null;
Or a bit shorter
...
where COALESCE(dob_year, dob_day, telephone, ssn, address) is not null;
For Q2 it would be this
select *
from address
where id is null
or address is null;
Some more notes:
It is a poor design to store date parts and then even localized strings. You should never do that. In your case it should be
create table details
(
id number,
dob_date DATE
);
Then next question, why do you create four tables? Maybe you learned at school about database normalization but you have taken too literally. Can a person have more than one SSN/telephone? If not, then add these columns to name table (and maybe rename it to person) instead of a separate table. The same question applies to table address.

could anyone help me to write a code to this question?

An HR system has an Employee table that holds a row for each employee within the company. Each record in the table has a employee id, employee name and manager column, that holds the id for the employee's manager. Write a trigger so that when an employee record is deleted, the record details need to be inserted into an table called Employee_archive along with the deleted date.
EMPLOYEE:
EMPID NUMBER PRIMARY KEY
EMPNAME VARCHAR2(25)
MANAGERID NUMBER
EMPLOYEE_ARCHIVE:
EMPID NUMBER PRIMARY KEY
EMPNAME VARCHAR2(25)
MANAGERID NUMBER
DELETED_DATE DATE
(Hint: Data is case sensitive. Use '/' to terminate the PLSQL block)
Seems to be pretty simple:
create or replace trigger trg_bd_emp
before delete on employee
for each row
begin
insert into employee_archive (empid, empname, managerid, deleted_date)
values (:old.empid, :old.empname, :old.managerid, sysdate);
end trg_bd_emp;
/
Though, what is that hint supposed to mean? What does letter case have to do with the problem?

Create table as select statement primary key in oracle

Is it possible to specify which is the primary key on creating table as select statement? My aim is to include the declaration of primary key on the create table not modifying the table after the creation.
CREATE TABLE suppliers
AS (SELECT company_id, address, city, state, zip
FROM companies
WHERE company_id < 5000);
Yes, it's possible. You would need to specify columns explicitly:
CREATE TABLE suppliers (
company_id primary key,
address,
city,
state,
zip
)
AS
SELECT company_id, address, city, state, zip
FROM companies
WHERE company_id < 5000;
Here is a demo
Note: in this case primary key constraint will be given a system-generated name. If you want it to have a custom name you'd have to execute alter table suppliers add constraint <<custom constraint name>> primary key(<<primary_key_column_name>>) after executing(without primary key specified) CREATE TABLE suppliers.. DDL statement.
Yes, it's possible.You can try referring below example.
create table student (rollno ,student_name,score , constraint pk_student primary key(rollno,student_name))
as
select empno,ename,sal
from emp;
You can create Suppliers table explicitly and if any column have primary key in companies table, then copy that structure from companies table.
Or
Create a same column defining primary key that you want and copy that column from companies table!

Creating a conditional index based on a column value

Table1
___________
User_ID
Location_ID
Type_ID
Level_ID
Levels
_________
1111 Manager
2222 Staff
There is an existing constraint on User_ID and Category_ID. I need to add a constraint to ensure that only one user
of level Manager can be added to a location for each type.
How do I go about creating a unique index on Location_ID, Type_ID and Level_ID where level_id=mypackage.get_level_id('Manager')?
I am trying something like that:
CREATE UNIQUE INDEX idx_mgr on Table1 (CASE WHEN Level_id=mypackage.get_level_id('Manager')
THEN (Location_ID,Type_ID)
ELSE NULL
END);
or
CREATE UNIQUE INDEX idx_mgr ON (DECODE(Level_ID,mypackage.get_level_id('Manager'),NULL);
How do I get something like this to work?
Defining a function index for the management level only (referencing teh constant directly - not via package) you get the required behaviour:
create unique index ix1 on table1
(case when level_id = 1111 then Location_ID end, case when level_id = 1111 then Type_ID end);
You can insert any number of stuff with the same location and type, but only one manager:
insert into table1(User_ID,Location_ID, Type_ID, Level_ID) values(1,1,1,2222);
insert into table1(User_ID,Location_ID, Type_ID, Level_ID) values(2,1,1,2222);
insert into table1(User_ID,Location_ID, Type_ID, Level_ID) values(3,1,1,1111);
insert into table1(User_ID,Location_ID, Type_ID, Level_ID) values(4,1,1,1111);
-- fails with ORA-00001: Unique Constraint violated

Procedure to remove duplicates in a table

Brief model overview:
I have a student and a course tables. As it's many to many relation there is also a junction table student_course (id_student, id_course), with unique constraint on both columns (composite).
The problem I want to solve:
On account of a mistake, there is no a unique constraint on the code column of the course table. It should as code column should uniquely identify a course. As a result there are two rows in the course table with the same value in the code column. I want to remove that duplicate, check that there is no other duplicates and add a unique constraint on the code column. Without loosing relations with student table.
My approach to solve the issue:
I have create a procedure that should do what I want.
CREATE OR REPLACE PROCEDURE REMOVE_COURSES
(
v_course_code IN VARCHAR2,
v_course_price IN VARCHAR2
)
AS
new_course_id NUMBER;
BEGIN
INSERT INTO course (CODE, PRICE) VALUES (v_course_code, v_course_price)
RETURNING ID INTO new_course_id;
FOR c_course_to_overwrite IN (SELECT *
FROM course
WHERE code = v_course_code AND id != new_course_id) LOOP
UPDATE student_course SET id_course = new_course_id WHERE id_course = c_course_to_overwrite.id;
DELETE FROM course WHERE id = c_course_to_overwrite.id;
END LOOP;
END REMOVE_COURSES;
/
Main problem I want to solve:
The procedure keeps giving me an error about unique constraint violation on student_course table. But I am really not sure how it's possible as I am using new_course_id, so there is no chance that in the junction table there are two rows with the same id_student, id_course. What do I need to fix ?
Miscellaneous:
I want to solve that issue using procedure only for learning purposes
EDITED:
CREATE TABLE student (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
name VARCHAR2(150) NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE student MODIFY ID
GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH LIMIT VALUE);
CREATE TABLE course (
id NUMBER GENERATED BY DEFAULT ON NULL AS IDENTITY,
code VARCHAR2(255) NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE course MODIFY ID
GENERATED BY DEFAULT ON NULL AS IDENTITY (START WITH LIMIT VALUE);
CREATE TABLE student_course (
id_student NUMBER NOT NULL,
id_course NUMBER NOT NULL,
PRIMARY KEY (id_student, id_course),
CONSTRAINT student_fk FOREIGN KEY (id_student) REFERENCES student (id),
CONSTRAINT course_fk FOREIGN KEY (id_course) REFERENCES course (id)
);
insert into student (name) values ('John');
INSERT INTO course (ID, CODE) VALUES (1, 'C_13');
INSERT INTO course (ID, CODE) VALUES (2, 'C_13');
commit;
INSERT INTO STUDENT_COURSE (ID_STUDENT, ID_COURSE) VALUES (1, 1);
INSERT INTO STUDENT_COURSE (ID_STUDENT, ID_COURSE) VALUES (1, 2);
commit;
CALL REMOVE_COURSES('C_13');
[23000][1] ORA-00001: unique constraint (SYS_C0014983) violated ORA-06512: near "REMOVE_COURSES", line 8
Rather than removing one of the duplicate codes, you're creating a third course with the same code, and trying to move all students on either of the old courses onto the new one. The error suggests you have students who are already enrolled on both of the old courses.
Your cursor loop query is:
SELECT *
FROM course
WHERE code = v_course_code AND id != new_course_id
That will find all junction records for both old versions of the code, and the update then sets all of those junction records to the same new ID.
If there are any students listed against both old IDs for the code - which would be allowed by your composite unique key - then they will both be updated to the same new ID.
So say the courses you're looking at are [updated for your example code]:
ID CODE
-- ----
1 C_13
2 C_13
and you have junction records for a student for both courses, like:
ID_STUDENT ID_COURSE
---------- ---------
1 1
1 2
You are creating a new course:
ID CODE
-- ----
3 C_13
Your cursor loop looks for code = 'ABC' and ID != 3, which finds IDs 1 and 2. So in the first iteration of the loop up update the rows with ID 1, so now you have:
ID_STUDENT ID_COURSE
---------- ---------
1 3
1 2
Then in the second iteration you try to update the rows with ID 2, which would attempt to produce:
ID_STUDENT ID_COURSE
---------- ---------
1 3
1 3
which would break the unique constraint - hence the error.
You probably don't want to create a new course at all, but either way, you need to remove duplicate records from student_course - that is, rows which will become duplicates when updated. Basically you need to find students with entries for both existing course IDs, and delete either of them. If you don't care which this would do it:
delete from student_course sc1
where id_course in (
select id
from course
where code = 'C_13'
)
and exists (
select null
from student_course sc2
join course c on c.id = sc.id_course
where sc2.id_student = sc1.id_student
and sc2.id_course > sc1.id_course
and c.code = 'C_13'
);
but there are other (probably better) ways.
You then have the choice of updating all remaining junction records for both old IDs to your new ID; or to consolidate on one of the old IDs and remove the other.
(Your question implies you want to solve the overall task yourself, so I'll refrain from trying to provide a complete solution - this just hopefully helps you understand and resolve your main problem...)

Resources