Oracle Inserting a row in a table only if a match found in some other table - oracle

I have 3 tables in my database namely employees,students and Images
create table employees(id number primary key,name varchar2(100), address varchar2(100));
create table students(id number primary key,name varchar2(100),address varchar2(100));
create table Images (image_id number primary key,employee_id number,student_id number,image_name varchar2(100));
Insert into employees values (1,'asdfasd','asdfasdf');
Insert into employees values (2,'asdfasd','asdfasdf');
Insert into employees values (3,'asdfasd','asdfasdf');
Insert into employees values (4,'asdfasd','asdfasdf');
Insert into employees values (5,'asdfasd','asdfasdf');
Insert into students values (1,'asdfasd','asdfasdf');
Insert into students values (2,'asdfasd','asdfasdf');
Insert into students values (3,'asdfasd','asdfasdf');
Insert into students values (4,'asdfasd','asdfasdf');
Insert into students values (5,'asdfasd','asdfasdf');
Insert into students values (49,'asdfasd','asdfasdf');
Insert into Images(image_id,employee_id,image_name) values (1,5,'adsfasdfasdf');
Insert into Images(image_id,student_id,image_name) values (2,49,'asfasdfasdf');
Now, when Inserting a row into the Images table I should check whether the employee_id / Student_id is existed in the employees table/student table, If a match found then only I have to Insert else it should not.
I thought of adding two foreign keys on the images table as follows:
alter table images add constraint fk_employeeid foreign key(employee_id)
references employees(id);
alter table images add constraint fk_studentsid foreign key(student_id)
references students(id);
But, If I do so. It will not allow me to insert null values. How can I modify my design so that whenever I insert a row in images table either it should be an employee_id or an student_id.
If I created any confusion, here is the link for the sql fiddle,http://www.sqlfiddle.com/#!4/92d24/1/0

I thought of adding two foreign keys on the images table.
But, If I do so. It will not allow me to insert null values.
You are wrong when you say the foreign key constraint won't allow NULL values. It will definitely allow the NULL values.
Test case
Let's add the foreign key constraint on the IMAGES table for the employee_id and student_id.
ALTER TABLE images ADD CONSTRAINT fk_emp FOREIGN KEY(employee_id) REFERENCES employees(ID);
ALTER TABLE images ADD CONSTRAINT fk_stu FOREIGN KEY(student_id) REFERENCES students(ID);
Let's check the INSERT with NULL values:
SQL> INSERT INTO Images(image_id,employee_id,image_name) VALUES (1,5,'adsfasdfasdf');
1 row created.
SQL> INSERT INTO Images(image_id,student_id,image_name) VALUES (2,49,'asfasdfasdf');
1 row created.
SQL> INSERT INTO Images(image_id,employee_id,image_name) VALUES (3,null,'adsfasdfasdf');
1 row created.
SQL> INSERT INTO Images(image_id,student_id,image_name) VALUES (4,null,'asfasdfasdf');
1 row created.
SQL>
SQL> COMMIT;
Commit complete.
SQL>
SQL> SELECT * FROM images;
IMAGE_ID EMPLOYEE_ID STUDENT_ID IMAGE_NAME
---------- ----------- ---------- ---------------
1 5 adsfasdfasdf
2 49 asfasdfasdf
3 adsfasdfasdf
4 asfasdfasdf
SQL>
Let's check the foreign key constraint validation:
SQL> INSERT INTO Images(image_id,employee_id,image_name) VALUES (1,10,'adsfasdfasdf');
INSERT INTO Images(image_id,employee_id,image_name) VALUES (1,10,'adsfasdfasdf')
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.SYS_C0010739) violated
SQL> INSERT INTO Images(image_id,student_id,image_name) VALUES (2,20,'asfasdfasdf');
INSERT INTO Images(image_id,student_id,image_name) VALUES (2,20,'asfasdfasdf')
*
ERROR at line 1:
ORA-00001: unique constraint (LALIT.SYS_C0010739) violated
SQL>
So, everything works as per the design.

Add constraints to images like you did. Add one more constraint:
alter table images add constraint chk_nulls
check (
(employee_id is not null and student_id is null)
or (employee_id is null and student_id is not null)
);
This way you cannot insert both nulls nor both not nulls for employee_id and student_id. And foreign keys are also checked.
Test:
insert into images values (1, 1, null, 'not important'); -- OK
insert into images values (2, null, null, 'not important'); -- error
insert into images values (3, 1, 1, 'not important'); -- error
insert into images values (4, null, 1, 'not important'); -- OK

I would keep the foreign keys, that is the correct approach.
But instead of inserting NULL's, you should define an "unknown record" in your EMPLOYEES and STUDENTS tables (maybe with an id=-1, name='UNKNOWN'), and insert -1 into your IMAGES table.

I recommend you to change the primary key in table images, and have as PK three columns (image_id, employee_id and student_id).
Edit 1: Based on comment
I think you planned in a wrong way the problem. If the images are for both, employees and students, you should have two tables, images_employees and images_students, with respectively foreign keys employee_id and student_id and of course an id for the image.
But is there any sense to have a row like this?
id: 1 student_id: null image_name: 'something'
I don't think so... please explain more about the purpose of images table.

Related

How do I create a foreign key on two columns that are under the primary key constraint?

CREATE TABLE "RESEARCH_DEP"."RESEARCH_TV_COMPANY"
( "CID" NUMBER(38,0) NOT NULL ENABLE,
"SOURCE_ID" NUMBER(2,0),
CONSTRAINT "PK_RESEARCH_TV_COMPANY_1" PRIMARY KEY ("CID", "SOURCE_ID")
USING INDEX (CREATE UNIQUE INDEX "RESEARCH_DEP"."IDX_TV_COMPANY_CID_SOURCE_ID" ON "RESEARCH_DEP"."RESEARCH_TV_COMPANY" ("CID", "SOURCE_ID")
CREATE TABLE "RESEARCH_DEP"."RESEARCH_METRICS_PHARMA_AUD"
( "ID" NUMBER GENERATED ALWAYS AS IDENTITY MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE NOT NULL ENABLE,
"SOURCE_ID" NUMBER(2,0) NOT NULL ENABLE,
"MEDIA_COMPANY_ID" NUMBER(*,0) NOT NULL ENABLE
)
NEED
ALTER TABLE RESEARCH_DEP.RESEARCH_METRICS_PHARMA_AUD
ADD CONSTRAINT fk_METRICS_PHARMA_AUD_TV_COMPANY_ID
FOREIGN KEY (MEDIA_COMPANY_ID,SOURCE_ID) REFERENCES RESEARCH_DEP.RESEARCH_TV_COMPANY(CID,SOURCE_ID);
ORA-02298: parent keys not found
DO I NEED TO CREATE A COMPOSITION COLUMN: CID,SOURCE_ID?
OR
create sequence of values two column oracle CID,SOURCE_ID ?
Your code is more or less OK:
SQL> create table research_tv_company
2 (cid number,
3 source_id number,
4 --
5 constraint pk_rtc primary key (cid, source_id)
6 );
Table created.
SQL> create table research_metrics_pharma_aud
2 (id number,
3 source_id number,
4 media_company_id number
5 );
Table created.
SQL> alter table research_metrics_pharma_aud
2 add constraint fk_rmpa_rtc
3 foreign key (media_company_id, source_id)
4 references research_tv_company (cid, source_id);
Table altered.
SQL>
Note that I
removed double quotes
removed NOT NULL for primary key columns (they can't be NULL anyway)
don't have any indexes created so Oracle will - along with table creation - create a primary key constraint AND unique index to support it
as I'm on 11gXE and it doesn't support identity columns, I removed that
from the second table; I'd have to enforce it via a trigger. You don't have to do anything about it, just saying (so that you wouldn't wonder where did it go?)
Error you got:
ORA-02298: parent keys not found
means that there are combinations of (media_company_id, source_id) in the second table that do not exist as pairs of (cid, source_id) in the first table. To illustrate it:
Drop the foreign key constraint first (otherwise, I wouldn't be able to do that):
SQL> alter table research_metrics_pharma_aud drop constraint fk_rmpa_rtc;
Table altered.
Insert a row into the first (master) table:
SQL> insert into research_tv_company (cid, source_id) values (1, 1);
1 row created.
Insert two rows into the second (detail) table; the first combination is valid, the second is not as (2, 2) don't exist in research_tv_company:
SQL> insert into research_metrics_pharma_aud (id, source_id, media_company_id) values (1, 1, 1);
1 row created.
SQL> insert into research_metrics_pharma_aud (id, source_id, media_company_id) values (2, 2, 2);
1 row created.
SQL>
If we try to create a foreign key constraint:
SQL> alter table research_metrics_pharma_aud
2 add constraint fk_rmpa_rtc
3 foreign key (media_company_id, source_id)
4 references research_tv_company (cid, source_id);
add constraint fk_rmpa_rtc
*
ERROR at line 2:
ORA-02298: cannot validate (SCOTT.FK_RMPA_RTC) - parent keys not found
SQL>
See? The same error you got.
What can you do?
insert missing primary key values into the master table, or
delete detail rows that violate the constraint, or
create the constraint, but instruct Oracle not to check whether existing rows are valid or not:
SQL> alter table research_metrics_pharma_aud
2 add constraint fk_rmpa_rtc
3 foreign key (media_company_id, source_id)
4 references research_tv_company (cid, source_id)
5 enable novalidate;
Table altered.
SQL>
The enable novalidate means that foreign key constraint will be enabled for any new or modified rows, but existing rows won't be checked. If that option suits you, use it. However, I believe that one of the first two option is better, with the first one - adding missing primary keys - being the best.

How to insert different value in Oracle

Suppose I have a name column with UNIQUE Constraint on it and it has data ABC ,XYZ etc.And I want to insert more data.if the data are different then insert it.And take ABC as same as Abc,abc,abC etc.
if the word is present in the table and we want to insert same word with different case then it should throw an error that we cannot insert this data
You can use a unique function-based index to achieve this.
At the moment you have a unique constraint which is case-sensitive, e.g.:
create table your_table (name varchar2(30));
alter table your_table add constraint con_unique_name unique (name);
insert into your_table (name) values ('ABC');
insert into your_table (name) values ('XYZ');
commit;
That blocks an exact duplicate, but allows variations in case to be inserted:
insert into your_table (name) values ('ABC');
ORA-00001: unique constraint (STACK.CON_UNIQUE_NAME) violated
insert into your_table (name) values ('Abc');
1 row inserted.
insert into your_table (name) values ('abc');
1 row inserted.
rollback;
If you add a unique index that uses the upper-case version of the value (or lower-case; doesn't matter as long as it's consistent!) as well as, or instead of, your existing constraint then those would be blocked too:
create unique index idx_unique_name on your_table (upper(name));
insert into your_table (name) values ('ABC');
ORA-00001: unique constraint (STACK.CON_UNIQUE_NAME) violated
insert into your_table (name) values ('Abc');
ORA-00001: unique constraint (STACK.IDX_UNIQUE_NAME) violated
insert into your_table (name) values ('abc');
ORA-00001: unique constraint (STACK.IDX_UNIQUE_NAME) violated
Notice the reported constraint name is different for the first one - that is still hitting the original unique constraint, while the mixed-case ones are passing that constraint and then failing on the new index. If you dropped the original constraint then they would all fail on the new index.
You can do an insert-select, like
insert into yourtable(name)
select 'ABC'
from yourtable
group by ''
having count(*) > 0
where not exists (select 1 from yourtable yt where yt.name = yourtable.name);
(untested)
or you can wrap an if around the insert to see whether this name already exists.

Alter Table , adding a Foreign key constraint at a column ORA-02253

Hello there i am studying for the Oracle Certification of SQL Associate .
And trying to do some Examples .
I have an issue where i cannot find easily a reference on this .
create table employees
(employee_id number NOT NULL,
first_name varchar(20),
last_name varchar(30),
constraint employee_pk primary key (employee_id));
create table employee_notes
(employee_notes_id number,
employee_notes varchar(500),
constraint pk_employee_notes primary key (employee_notes_id));
create sequence employee_notes_seq start with 1 increment by 1
Now i want to add a new column at employee_notes table with a foreign key constraint .
I can't find out in syntax where is the problem .
****alter table employee_notes
add employee_id number
constraint fk_employee_notes foreign key (employee_id) references employees (employee_id);****
i get this error
ORA-02253: constraint specification not allowed her
I also tried to alter the table and add column and then the constraint but cannot
alter table employee_notes
add employee_id number;
--
alter table employee notes
add constraint fk_employee_notes foreign key (employee_id) references employees (employee_id);
ORA-02253: constraint specification not allowed here
I would like to know how i can do this
and why this syntax is wrong :)
You did something wrong because - it works OK:
SQL> CREATE TABLE employees
2 (
3 employee_id NUMBER NOT NULL,
4 first_name VARCHAR (20),
5 last_name VARCHAR (30),
6 CONSTRAINT employee_pk PRIMARY KEY (employee_id)
7 );
Table created.
SQL>
SQL> CREATE TABLE employee_notes
2 (
3 employee_notes_id NUMBER,
4 employee_notes VARCHAR (500),
5 CONSTRAINT pk_employee_notes PRIMARY KEY (employee_notes_id)
6 );
Table created.
SQL> ALTER TABLE employee_notes ADD employee_id NUMBER;
Table altered.
SQL> ALTER TABLE employee_notes ADD CONSTRAINT fk_employee_notes
2 FOREIGN KEY (employee_id)
3 REFERENCES employees (employee_id);
Table altered.
SQL>
When you use ALTER TABLE ... ADD in order to add a column and a constraint in one statement, do the following:
-- notice the () and the comma!
alter table employee_notes
add (
employee_id number
, constraint fk_employee_notes
foreign key (employee_id) references employees (employee_id)
) ;
That should do the trick. See dbfiddle. The syntax is similar to CREATE TABLE, where you'd also write all column names, data types etc in (), separated by commas.

Update trigger to ensure matching values in other table Oracle SQL Developer

I am trying to come up with a way to make sure that when a table is updated, that a certain condition is met. Can this be done in a trigger? I have made the following two tables, storeTable and employeeTable.
I need to make sure that when storeManager is updated in the storeTable, that the employee has a storeID that matches the store in which I am trying to update the storeManager. (employee cannot be manager of a store he does not work at)
In addition, I need to make sure that the employee exists in the employeeTable. I was thinking some sort of CASE statement would be best, but dont know how this could be enforced by a trigger.
I was thinking about morphing the "Foreign Key Trigger for Child Table" trigger example from https://docs.oracle.com/cd/B12037_01/appdev.101/b10795/adfns_tr.htm#1007172 but I could not figure out how to change this to fit my specific need. Any help is much appreciated.
For context, the current keys are:
storeTable:
storeID PRIMARY KEY
employeeTable:
empID PRIMARY KEY
storeID FOREIGN KEY REFERS TO storeTable.storeID
To me, it seems that constraints can do the job. You don't need triggers.
Here's how. First, create tables without any constraints. Then add them, both primary and foreign key ones which will be deferrable (otherwise you wouldn't be able to insert any rows as parent keys don't exist yet).
SQL> create table employee
2 (empid number,
3 fname varchar2(10),
4 storeid number
5 );
Table created.
SQL> create table store
2 (storeid number,
3 storename varchar2(20),
4 storemanager number
5 );
Table created.
SQL>
SQL> alter table employee add constraint pk_employee primary key (empid, storeid);
Table altered.
SQL> alter table store add constraint pk_store primary key (storeid);
Table altered.
SQL>
SQL> alter table store add constraint fk_store_emp foreign key (storemanager, storeid)
2 references employee (empid, storeid)
3 deferrable initially deferred;
Table altered.
SQL> alter table employee add constraint fk_emp_store foreign key (storeid)
2 references store (storeid)
3 deferrable initially deferred;
Table altered.
SQL>
Now let's add some data: initial insert into employee will be OK until I commit - then it'll fail because its store doesn't exist yet:
SQL> insert into employee values (1, 'John' , 1);
1 row created.
SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (SCOTT.FK_EMP_STORE) violated - parent key not
found
SQL>
But, if I don't commit and pay attention to what I'm entering (i.e. that referential integrity is maintained), it'll be OK:
SQL> insert into employee values (1, 'John' , 1);
1 row created.
SQL> insert into employee values (2, 'Matt' , 2);
1 row created.
SQL> insert into store values (1, 'Santa Clara', 1);
1 row created.
SQL> insert into store values (2, 'San Francisco', 2); --> note 2 as STOREID
1 row created.
SQL> commit;
Commit complete.
SQL> select * From employee;
EMPID FNAME STOREID
---------- ---------- ----------
1 John 1
2 Matt 2
SQL> select * From store;
STOREID STORENAME STOREMANAGER
---------- -------------------- ------------
1 Santa Clara 1
2 San Francisco 2
SQL>
See? So far so good.
Now I'll try to modify STORE table and set its manager to John who works in storeid = 1 which means that it should fail:
SQL> update store set storemanager = 1
2 where storeid = 2;
1 row updated.
SQL> commit;
commit
*
ERROR at line 1:
ORA-02091: transaction rolled back
ORA-02291: integrity constraint (SCOTT.FK_STORE_EMP) violated - parent key not
found
SQL>
As expected.
Let's now add emplyoee ID = 6, Jimmy, who works in storeid = 2 and set him to be manager in San Francisco (storeid = 2):
SQL> insert into employee values (6, 'Jimmy', 2);
1 row created.
SQL> update store set storemanager = 6
2 where storeid = 2;
1 row updated.
SQL> commit;
Commit complete.
SQL>
Yey! It works!
As you can see, no triggers needed.
Note that - if you want to drop any of those tables - you'll fail as they are referenced by each other:
SQL> drop table store;
drop table store
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
SQL> drop table employee;
drop table employee
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
SQL>
It means that you'd first have to drop foreign key constraints, then drop tables:
SQL> alter table employee drop constraint fk_emp_store;
Table altered.
SQL> alter table store drop constraint fk_store_emp;
Table altered.
SQL> drop table store;
Table dropped.
SQL> drop table employee;
Table dropped.
SQL>
That's all, I guess.

In oracle on delete set null is not working

I have created two tables:
Create Table Dept
(Department_id number Constraint Depart_id_pk Primary Key
,Department_name varchar2(20));
Create table Emp
(Emp_id number Constraint Empl_id_pk Primary Key
,First_name varchar2(10)
,salary number
,Department_id number
,Constraint depart_id_fk Foreign Key (department_id)
References Dept (Department_id) on delete set null);
Then I have inserted some records in dept and Emp table. But when I try to drop dept table, instead of setting null in Emp.department_id column it shows error like this:
SQL> Drop Table Dept;
Drop Table Dept
*
ERROR at line 1:
ORA-02449: unique/primary keys in table referenced by foreign keys
The foreign key's clause say "on delete set null". Delete is a DML operation, and had you attempted to delete rows from the dept table, the corresponding emp rows would have been updated with a null dept_id.
But this isn't the case - you tried to drop the entire table, a DDL operation. This isn't allowed, because you'd be leaving behind constraints on the emp table that reference a table that no longer exists. If you want to drop these constraints too, you can use a cascade constraints clause:
DROP TABLE dept CASCADE CONSTRAINTS

Resources