Enforce a foreign-key constraint to columns of same table - sql

How to enforce a constraint of foreign key on columns of same table in SQL while entering values in the following table:
employee:
empid number,
manager number (must be an existing employee)

Oracle call this a self-referential integrity constraint. The documentation is here for a description,
You create a self-referential constraint in the same manner you would a normal one:
alter table employees
add constraint employees_emp_man_fk
foreign key ( manager_no )
references employees ( emp_id )
on delete set null
;
I'm assuming that your manager_no is nullable. I've added set null here as a delete cascade would probably wipe out a significant amount of your table.
I can't think of a better way of doing this. Deleting a manager should not result in the deletion of all their employees so you have to set null and have a trigger on the table to alert you to anyone with no manager.
I always like this site, which is good for simple references. and don't forget to have an index on the FK as well or Tom will yell at you :-).
One can also utilise standard Oracle syntax to create a self-referential FK in the create table statement, which would look like the following.
create table employees
( emp_id number
, other_columns ...
, manager_no number
, constraint employees_pk
primary key (emp_id)
, constraint employees_man_emp_fk
foreign key ( manager_no )
references employees ( emp_id )
on delete set null
);
EDIT:
In answer to #popstack's comment below:
Whilst you can do this in one statement not being able to alter a table is a fairly ridiculous state of affairs. You should definitely analyze a table that you're going to be selecting from and you will still want an index on the foreign key ( and possibly more columns and / or more indexes ) otherwise whenever you use the foreign key you're going to do a full table scan. See my link to asktom above.
If you're unable to alter a table then you should, in descending order of importance.
Find out how you can.
Change your DB design as a FK should have an index and if you can't have one then FKs are probably not the way to go. Maybe have a table of managers and a table of employees?

SELF REFERENCES QUERY...
Alter table table_name ADD constraints constraints_name foreign key(column_name1,column_name2..) references table_name(column_name1,column_name2...) ON DELETE CASCADE;
EX- ALTER TABLE Employee ADD CONSTRAINTS Fr_key( mgr_no) references employee(Emp_no) ON DELETE CASCADE;

CREATE TABLE TABLE_NAME (
`empid_number` int ( 11) NOT NULL auto_increment,
`employee` varchar ( 100) NOT NULL ,
`manager_number` int ( 11) NOT NULL ,
PRIMARY KEY (`empid_number`),
CONSTRAINT `manager_references_employee`
FOREIGN KEY (`manager_number`) REFERENCES (`empid_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Hope it helps!

Related

Delete/Modify row in one table based on a condition - Oracle DBMS

I have a table structure like
create table EMPLOYE (
CodeEmploye varchar2(100) not null,
NAS varchar2(100),
CONSTRAINT employe_pk primary key (CodeEmploye)
);
create table SALAIRE (
CodeEmploye varchar2(100) not null,
Mois number not null,
CONSTRAINT salaire_pk primary key (CodeEmploye, Mois),
CONSTRAINT salaire_code_employe_fk FOREIGN KEY(CodeEmploye) REFERENCES EMPLOYE(CodeEmploye)
);
I want to add a constraint where I should not be allowed to modify/delete a row in EMPLOYE table if the same employee exist in SALAIRE table.
What is the best way to do that ?
As you have define the foreign key relationship between two tables by "CodeEmployee" column, what you want has been achieved.
A little bit extension is that if you add "ON DELETE CASCADE" following the fk declaration, once you delete any row form employee table, all the related records in the salary table will be deleted as well.
One of the best ways to do is by creating a foreign key constraint on the "CodeEmploye" column during CREATE TABLE or ALTER TABLE statements. In your case, it is already created (salaire_code_employe_fk) as part of your CREATE statement.
A foreign key constraint ensures that an employee row from the parent table (EMPLOYE) cannot be modified/deleted if the same employee exists in the child table (SALAIRE).
In this case, when you create the order_items table, you define a foreign key constraint with the DELETE CASCADE option as follows:
CREATE TABLE order_items
(
order_id NUMBER( 12, 0 ),
-- other columns
-- ...
CONSTRAINT fk_order_items_orders
FOREIGN KEY( order_id )
REFERENCES orders( order_id )
ON DELETE CASCADE
);
By doing this, whenever you delete a row from the orders table, for example:
DELETE
FROM
orders
WHERE
order_id = 1;
All the rows whose order id is 1 in the order_items table are also deleted automatically by the database system.

How can I create a foreign key with Index in one single create table statement? (Oracle)

I tried to create a new table (tableB) with a foreign key constraint to another table (tableA) and just wondering if I can create along with this all constraints and indexes needed. My goal would be to have a single create table statement with no need of an alter table… statement afterwards and no other create index… statement. Is this possible? Thanks for any hint in advance :)
create table tableA
(
id number
, constraint tableApk primary key (id)
);
create table tableB
(
id number
, constraint tableBfk foreign key (id) references tableA (id)
on delete cascade
using index (
create index tableBfkidx on tableB (id)
)
);
That isn't allowed. Per the documentation a using_index_clause can only be specified for unique or primary constraints.
Best of luck.

How to add a foreign key referring to itself in SQL Server 2008?

I have not seen any clear, concise examples of this anywhere online.
With an existing table, how do I add a foreign key which references this table? For example:
CREATE TABLE dbo.Projects(
ProjectsID INT IDENTITY(1,1) PRIMARY KEY,
Name varchar(50)
);
How would I write a command to add a foreign key which references the same table? Can I do this in a single SQL command?
I'll show you several equivalent ways of declaring such a foreign key constraint. (This answer is intentionally repetitive to help you recognise the simple patterns for declaring constraints.)
Example: This is what we would like to end up with:
Case 1: The column holding the foreign keys already exists, but the foreign key relationship has not been declared / is not enforced yet:
In that case, run this statement:
ALTER TABLE Employee
ADD FOREIGN KEY (ManagerId) REFERENCES Employee (Id);
Case 2: The table exists, but it does not yet have the foreign key column:
ALTER TABLE Employee
ADD ManagerId INT, -- add the column; everything else is the same as with case 1
FOREIGN KEY (ManagerId) REFERENCES Employee (Id);
or more succinctly:
ALTER TABLE Employee
ADD ManagerId INT REFERENCES Employee (Id);
Case 3: The table does not exist yet.
CREATE TABLE Employee -- create the table; everything else is the same as with case 1
(
Id INT NOT NULL PRIMARY KEY,
ManagerId INT
);
ALTER TABLE Employee
ADD FOREIGN KEY (ManagerId) REFERENCES Employee (Id);
or, declare the constraint inline, as part of the table creation:
CREATE TABLE Employee
(
Id INT NOT NULL PRIMARY KEY,
ManagerId INT,
FOREIGN KEY (ManagerId) REFERENCES Employee (Id)
);
or even more succinctly:
CREATE TABLE Employee
(
Id INT NOT NULL PRIMARY KEY,
ManagerId INT REFERENCES Employee (Id)
);
P.S. regarding constraint naming: Up until the previous revision of this answer, the more verbose SQL examples contained CONSTRAINT <ConstraintName> clauses for giving unique names to the foreign key constraints. After a comment by #ypercube I've decided to drop these clauses from the examples, for two reasons: Naming a constraint is an orthogonal issue to (i.e. independent from) putting the constraint in place. And having the naming out of the way allows us to focus on the the actual adding of the constraints.
In short, in order to name a constraint, precede any mention of e.g. PRIMARY KEY, REFERENCES, or FOREIGN KEY with CONSTRAINT <ConstraintName>. The way I name foreign key constraints is <TableName>_FK_<ColumnName>. I name primary key constraints in the same way, only with PK instead of FK. (Natural and other alternate keys would get the name prefix AK.)
You can add the column and constraint in one operation
ALTER TABLE dbo.Projects ADD
parentId INT NULL,
CONSTRAINT FK FOREIGN KEY(parentid) REFERENCES dbo.Projects
Optionally you could specify the PK column in brackets after the referenced table name but it is not needed here.
If the table already exists: Assuming you don't already have a column to store this data. If you do then skip this step.
ALTER TABLE [dbo].[project]
ADD [fkProjectsId] INT;
GO
ALTER TABLE [dbo].[projects]
ADD CONSTRAINT [FK_Projects_ProjectsId] FOREIGN KEY ([fkProjectsId]) REFERENCES [dbo].[Projects] ([ProjectsID])
GO

SQL Update error. FK Conflict

I am trying to change the name of a group from ASSY to Manufacturing but am running into some dificulties. It is on a sql server database. I ran the query below.
Update groups
set group_code= 'Manufacturing'
where site_code = 'TMMBC' and group_code = 'ASSY' and group_description = 'Manufacturing'
But it returned with this error - "The UPDATE statement conflicted with the REFERENCE constraint "user_groups_FK_2". The conflict occurred in database "eci", table "dbo.user_groups"."
Is there a way I can update both tables at the same time to bypass this error?
Is there a way I can update both tables at the same time to bypass
this error?
Yes. You can define the foreign key to cascade on update.
I would consider restructuring it so that groups has an integer surrogate key though and have the textual description as a separate column.
This avoids having to repeat the relatively long string Manufacturing possibly many times in the child table.
Assuming your definition for table user_groups looks something like:
create table dbo.user_groups (
group_code varchar(100),
-- other fields
constraint user_groups_fk_2 foreign key (group_code) references dbo.groups (group_code)
);
You would change the table definition to have the foreign key cascade, like:
create table dbo.user_groups (
group_code varchar(100),
-- other fields
constraint user_groups_fk_2 foreign key (group_code) references dbo.groups (group_code) on delete cascade on update cascade
);
Or through ALTER TABLE statements:
alter table dbo.user_groups drop constraint user_groups_fk_2;
alter table dbo.user_groups add constraint user_groups_fk_2 foreign key (group_code) references dbo.groups (group_code) on delete cascade on update cascade;

Check if data exists in another table on insert?

Table A
(
Table_A_ID int
)
Table B
(
Table_B_ID int
Value int
)
Say I want to insert data into Table B, where 'Value' would be the same as a Table_A_ID.
How would I make a constraint or check that the data actually exists in the table on insertion?
You probably need to enforce data integrity not only on INSERT into Table B, but also on UPDATE and DELETE in both tables.
Anyway options are:
FOREIGN KEY CONSTRAINT on Table B
TRIGGERs on both tables
As a last resort if for some reason 1 and 2 is not an option STORED PROCEDUREs for all insert, delete update operations for both tables
The preferred way to go in most cases is FOREIGN KEY CONSTRAINT.
Yap, I agree with #peterm.
Cause, if your both Table_A_ID and Table_B_Id are primary keys for both tables, then you don't even need two tables to store the value. Since, your two tables are seems to be on 'one-to-one' relationship. It's one of the database integrity issues.
I think you didn't do proper normalisation for this database.
Just suggesting a good idea!
I found this example which demonstrates how to setup a foreign key constraint.
Create employee table
CREATE TABLE employee (
id smallint(5) unsigned NOT NULL,
firstname varchar(30),
lastname varchar(30),
birthdate date,
PRIMARY KEY (id),
KEY idx_lastname (lastname)
) ENGINE=InnoDB;
Create borrowed table
CREATE TABLE borrowed (
ref int(10) unsigned NOT NULL auto_increment,
employeeid smallint(5) unsigned NOT NULL,
book varchar(50),
PRIMARY KEY (ref)
) ENGINE=InnoDB;
Add a constraint to borrowed table
ALTER TABLE borrowed
ADD CONSTRAINT FK_borrowed
FOREIGN KEY (employeeid) REFERENCES employee(id)
ON UPDATE CASCADE
ON DELETE CASCADE;
NOTE: This tells MySQL that we want to alter the borrowed table by adding a constraint called ‘FK_borrowed’. The employeeid column will reference the id column in the employee table – in other words, an employee must exist before they can borrow a book.
The final two lines are perhaps the most interesting. They state that if an employee ID is updated or an employee is deleted, the changes should be applied to the borrowed table.
NOTE: See the above URL for more details, this is just an excerpt from that article!
Create a foreign key constraint on the column 'Value' on table B that references the 'Table_A_ID' column.
Doing this will only allow values that exist in table A to be added into the 'Value' field of table B.
To accomplish this you first need to make Table_A_ID column the primary key for table A, or it at least has to have some sort of unique constraint applied to it to be a foreign key candidate.
BEGIN TRANSACTION -- REMOVE TRANSACTION AND ROLLBACK AFTER DONE TESTING
--PUT A PRIMARY KEY ON TABLE A
CREATE TABLE A
( Table_A_ID int CONSTRAINT PK_A_Table_A_ID PRIMARY KEY)
--ON VALUE ADD A FOREIGN KEY CONSTRAINT THAT REFERENCEs TABLE A
CREATE TABLE B
( Table_B_ID int,
[Value] int CONSTRAINT FK_B_Value_A REFERENCES A(Table_A_ID)
)
-- TEST VALID INSERT
INSERT A (Table_A_ID) VALUES (1)
INSERT B (Table_B_ID, [Value]) VALUES (1,1)
--NOT ALLOW TO INSERT A VALUE THAT DOES NOT EXIST IN A
--THIS WILL THROW A FOREIGN KEY CONSTRAINT ERROR
INSERT B (Table_B_ID, [Value]) VALUES (1,2) -- 2 DNE in table A
ROLLBACK
Note: there is no magic to 'FK_B_Value_A' or 'PK_A_Table_A_ID' it simply a naming convention and be called anything. The syntax on the foreign key and primary key lines work like this:
column-definition CONSTRAINT give-the-constraint-a-name REFERENCES table-name ( table-column )
column-definition CONSTRAINT give-the-constraint-a-name PRIMARY KEY