How to carry out deletions from 2 tables, at the same time in Oracle database? - oracle

Within my Oracle database I wish to delete rows from 2 different tables.
The issue is that, if I delete rows from KENNEL first, then the rows I want to delete in DOG table cannot be found to delete.
Below are my SQL statements to delete from the two tables.
DELETE FROM KENNEL WHERE COUNTRY_ID IS NULL;
DELETE FROM DOG WHERE ID IN (SELECT DOG_ID FROM KENNEL WHERE COUNTRY_ID IS NULL);
How can I fix this so that the 2 deletes happen at the same time, and ensure that rows from both the tables are removed?
Note: I cannot delete from DOG then KENNEL as KENNEL is the child record that must be deleted first.

I would do this set of deletes as something like:
-- delete rows from child table first
DELETE FROM KENNEL WHERE COUNTRY_ID IS NULL;
-- now delete any parent rows that don't have any child records
DELETE FROM DOG WHERE ID not exists (SELECT DOG_ID FROM KENNEL);
Doing it this way means that if not all the country_ids for a given dog_id in the kennel table were null, you wouldn't attempt to delete the parent record - it would error if you tried.

UPDATE DOG SET [some non-key field] = 'XXX' WHERE ID IN (SELECT DOG_ID FROM KENNEL WHERE COUNTRY_ID IS NULL);
DELETE FROM KENNEL WHERE COUNTRY_ID IS NULL;
DELETE FROM DOG WHERE [non-key field] = 'XXX';

Related

How can I move existing records from parent table to newly created child table with the help of triggers (Oracle)?

I want to create a trigger wherein the child table pulls all the exisiting records from parent table.
I have created child tables referencing the parent table primary key as foreign key in new table
CREATE OR REPLACE TRIGGER trigger name
AFTER INSERT ON table_name(parent_table)
FOR EACH ROW
BEGIN
insert statement for child table;
END;
Above trigger is created for records which will be inserting post to child table creation, I would like to push all old records (which were present prior to child table creation) to the new child table. Will triggers help in pulling all the old records ?
Obviously NO!!
The trigger will start inserting records to the child table from the parent table post creation of trigger. Records inserted into parent table prior to trigger creation need to be inserted manually.
If you want to pull all records before the creation of trigger into child table from parent table then you need to write one-time INSERT query as following:
INSERT INTO CHILD_TABLE
SELECT * FROM PARENT_TABLE P
WHERE NOT EXISTS (SELECT 1 FROM CHILD_TABLE C WHERE P.PK = C.FK);
-- OR --
INSERT INTO CHILD_TABLE
SELECT * FROM PARENT_TABLE P
WHERE P.PK IN
(SELECT PK FROM PARENT_TABLE
MINUS
SELECT FK FROM CHILD_TABLE
)
Cheers!!

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

oracle | delete duplicates records

I have identified some duplicates in my table:
-- DUPLICATES: ----
select PPLP_NAME,
START_TIME,
END_TIME,
count(*)
from PPLP_LOAD_GENSTAT
group by PPLP_NAME,
START_TIME,
END_TIME
having count(*) > 1
-- DUPLICATES: ----
How is it possible to delete them?
Even if you don't have the primary key, each record has a unique rowid associated.
By using the query below you delete only the records that don't have the maximum row id by self joining a table with the columns that cause duplication. This will make sure that you delete any duplicates.
DELETE FROM PPLP_LOAD_GENSTAT plg_outer
WHERE ROWID NOT IN(
select MAX(ROWID)
from PPLP_LOAD_GENSTAT plg_inner
WHERE plg_outer.pplp_name = plg_inner.pplg_name
AND plg_outer.start_time= plg_inner.start_time
AND plg_outer.end_time = plg_inner.end_time
);
I'd suggest something easier:
CREATE table NewTable as
SELECT DISTINCT pplp_name,start_time,end_time
FROM YourTable
Then delete your table, and rename the new table.
If you really want to delete records, you can find a few examples of how here.

Updating rows with same id and name in oracle database

i have a large data inside a table two employees have same name and same id in accident so i want to update one of the two employee so it becomes hard to me do you have any answer or solution
when i write this it updates the two rows
update EMPLOYEE
set id = 2 where Name='ahmed' and id=1
you can use ROWNUM
update EMPLOYEE
set id = 2 where Name='ahmed' and id=1 and ROWNUM = 1

Create after insert trigger which updates record by getting value from other Oracle 11g table

I have two tables
Parent(id, name, occupation)
Child(id, name, gender,parent_id, parent_name, parent_occupation)
Now to insert value in child i'll run chi query
insert into Child(id,name,gender,parent_id) values(10,'XYZ','Male',15);
So now my requirement is when this insert query is executed a trigger will run and get name and occupation from parent table for id 15 (parent_id of the Child record) and add it to the newly inserted row in fields parent_name and parent_occupation respectively.
I am using Oracle 11g as my database.
You want something akin to this (though you'll need to add code to handle the exception):
CREATE OR REPLACE
TRIGGER ai_child_tg
AFTER INSERT ON child
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
SELECT name,
occupation
INTO :NEW.parent_name,
:NEW.parent_occupation
FROM parent
WHERE id = :NEW.parent_id;
EXCEPTION
WHEN no_data_found
THEN
<handle_your_exception_>
END ai_child_tg;
However, if your CHILD table is really a relational child to your PARENT table and there is a FK relationship in place (via the CHILD.PARENT_ID column) then storing the PARENT_NAME and PARENT_OCCUPATION columns in the CHILD table is logically redundant.
I'd query why you have those two columns in the CHILD table at all.
Hope it helps...

Resources