SQL Server: change primary key with related rows - sql-server

I want to change the primary key value for one row in a table that has relations with other tables:
For example
Table Person { Id, Name, +50 fields }
Table Address { Id, City, +10 fields }
Table Person2Address { Id, PersonId, AddressId }
I want to change Person.Id and Person2Address.PersonId
I try something like:
BEGIN TRANSACTION
UPDATE Pers SET Id = NewId WHERE Id = OldId
UPDATE Person2Address SET PersonId = NewId WHERE PersonId = OldId
COMMIT TRANSACTION
But of course it provides conflicts :)
How can I temporary suppress foreign key constraints or is there a better way to change Id for person?

First off, changing the primary key value is never a good idea. Your main focus should be to try and avoid that by all means.
If you cannot eliminate the need to update the primary key value, then your best bet would be to define the foreign key relationship between those two tables to be using ON UPDATE CASCADE, so that any changes to the main table's primary key will be automatically cascaded down to the child table.
To do this, drop your existing foreign key relationship and then add:
ALTER TABLE dbo.Person2Address
ADD CONSTRAINT FK_Person2Address_Person
FOREIGN KEY (PersonId) REFERENCES dbo.Person(Id)
ON UPDATE CASCADE
That should then automatically update the Person2Address table's PersonId value if the Id on the person changes.
Now you should be able to just call
UPDATE dbo.Person SET Id = NewId WHERE Id = OldId
and that should be all there is!

Your easiest bet for things like this is to use something like:
BEGIN TRANSACTION
UPDATE Pers SET tempId = NewId WHERE Id = OldId
UPDATE Person2Address SET tempPersonId = NewId WHERE PersonId = OldId
COMMIT TRANSACTION
Then drop the Id and PersonId fields and rename the temp ones.

You can drop FK constraints and recreate them when finished.
ALTER TABLE some_table DROP CONSTRAINT my_constraint
Check this article for creating and modifying constraints.

Related

Using triggers for referential integrity

There are 2 tables in the database that contain the following columns:
department table with column dept_no (char(4), not null)
employee table with column dept_no (char(4), null)
The dept_no column needs to be defined as a primary key in the department table and a foreign key in the employee table using a trigger.
I thought this was the correct solution using the deleted and inserted virtual tables to update/delete the foreign key in the corresponding employee table:
CREATE TRIGGER trig_delete_dept_no
ON department
AFTER DELETE
AS
UPDATE employee
SET employee.dept_no = NULL
FROM deleted
WHERE employee.dept_no = deleted.dept_no
CREATE TRIGGER trig_update_dept_no
ON department
AFTER UPDATE
AS
UPDATE e
SET e.dept_no = i.dept_no
FROM employee e
INNER JOIN inserted i ON e.dept_no = i.dept_no
However, when I update the department dept_no row to a different value I do not see the corresponding dept_no update in the employee table:
UPDATE department
SET dept_no = 'd4'
WHERE dept_no = 'd3'
Deleting functions as expected. What am I doing wrong with the update trigger and how can I combine these two triggers into one trigger?
There is an issue in your design. The first thing is you should not use dept_no as PK (Primary Key). You need to have an IDENTITY or GUID column as Primary Key and refer to that column as FK (Foreign Key).
This way you won't need to worry about changing the dept_no.
The second point is you don't need trigger. you can use CASCADE option on DELETE action.
Find more information on CASCADE
Thank you FLICKER and SMor for helping me think through this. I do not believe the assignment wants us to modify the tables by adding IDENTITY or GUID columns and since we are to strictly use Triggers, this is the best solution I can come up with:
CREATE TRIGGER trig_delete_dept_no ON department AFTER DELETE AS
UPDATE employee
SET employee.dept_no = NULL
FROM deleted
WHERE employee.dept_no = deleted.dept_no
CREATE TRIGGER trig_update_dept_no ON department AFTER UPDATE AS
IF UPDATE(dept_no)
BEGIN
IF (SELECT employee.dept_no
FROM employee, inserted
WHERE employee.dept_no = inserted.dept_no) IS NULL
BEGIN
ROLLBACK TRANSACTION
RAISERROR ('Integrity constraint violation, TRIGGER:
trig_update_dept_no, TABLE: department',16,1)
END
ELSE PRINT 'Update successful'
END
This will allow updates to occur in the department as long as there are no orphaned records in the employee table.

Replacing a varchar FK with a new Int FK in SQL Server

I have two tables which we will call Event and EventResponse
Event has PK eventGuid varchar(36) and several other columns
EventResponse has FK eventGuid varchar(36) and other columns
I can easily add an INT identity column to Event with:
ALTER TABLE dbo.[Event]
ADD eventId INT IDENTITY;
And adding a column to EventResponse table is Ok.
How do I update all the eventIds in the response table?
Is this possible with a neat query or do I have to loop through?
Final state should be:
Event has PK eventId, eventGuid varchar(36), other columns
EventResponse has FK eventId, eventGuid varchar(36), other columns
No looping required. Words to live by :)
This should be just about all you need. Use your existing foreign key to update the values for your new key, then drop the old relationship and add the new one.
UPDATE er
SET er.eventID = e.eventID
FROM
dbo.EventResponse AS er
JOIN
dbo.Event as e
ON er.eventGuid = e.eventGuid;
GO
ALTER TABLE dbo.EventResponse
DROP CONSTRAINT <FK_Name>
GO
ALTER TABLE dbo.EventResponse
ADD CONSTRAINT <FK_Name> FOREIGN KEY (eventId)
REFERENCES dbo.Event(eventId)
[ON DELETE CASCADE
ON UPDATE CASCADE]
GO
Then, probably, if you want to save some space in your database:
ALTER TABLE dbo.Event
DROP COLUMN eventGuid;
GO
ALTER TABLE dbo.EventResponse
DROP COLUMN eventGuid;
GO
try this:
update a set a.eventId=b.eventId
from EventResponse a
inner join Event b on a.eventGuid = b.eventGuid

How can we update an column with Foreign key constraint in DB2?

I have 2 Tables , please check images attached
PK: PK
FK: FK
P_Id in Pk table is the primary key
and P_Id in FK table is the foreign key.
I need to add 10 to all records in P_Id column of both PK and FK table( meaning they need to match always)
I know in MS SQL we can easily update cascade as follows:
ALTER TABLE FK
ADD CONSTRAINT FK_P_Id
FOREIGN KEY (P_Id)
REFERENCES PK (P_Id) ON UPDATE CASCADE
and then update the rows of PK , which will automatically update FK too.
update A
set A.P_Id= A.P_Id + 10
from PK A inner join FK B
on A.P_Id = B.P_Id
But, i am not sure how this works in DB2.. can someone please help?
How can i get this to work?
Thanks in advance
Swat
use
SET FOREIGN_KEY_CHECKS = 0;
update both the tables;
and then
SET FOREIGN_KEY_CHECKS = 1;
--remove you foreign key
ALTER TABLE YOURLIB.FK
drop CONSTRAINT YOURLIB.FK_P_Id;
--update FK table
update YOURLIB.FK
set P_Id=P_Id+10;
--update PK table (force)
update YOURLIB.PK overriding system value
set P_Id=P_Id+10;
--recreate foreign key
ALTER TABLE YOURLIB.FK
ADD CONSTRAINT YOURLIB.FK_P_Id
FOREIGN KEY (P_Id)
REFERENCES YOURLIB.PK (P_Id)
ON DELETE RESTRICT;
--If you id on PK is autoincremented, restart it (here 123456 in example but you must found max of id in your PK table --> select max(p_id) from yourlib.pk)
ALTER TABLE YOURLIB.PK
ALTER COLUMN P_Id
RESTART with 123456;
you can modify a key to force like this, only if you update dont create double value key (example your key + 10 already exist in your table), else you must remove the primary key before update (Dangerous, be carefull if someone are working on your table). Ok course you must remove foreign key for do it
update pk f0 overriding system value
set f0.id=f0.id+10
where exists
(
select * from fk f1
where f0.id=f1.id
)

update statement conflicted with foreign key constraint

I have problem on updating column set as primary key, even I made on update set default
this is my code for creating tables, I set on update set default
create table department(
id int default 10 primary key,
name varchar(50)
);
create table employee
(
id int primary key,
dept_id int default 40 foreign key references department(id) on update set default on delete set default,
name varchar(40)
);
after that, I inserted data to the tables
insert into department
values
(1,'hr'),
(2,'programming'),
(3,'telesales'),
(4,'database')
insert into employee
values
(1,1,'mohammed'),
(2,2,'magd'),
(3,1,'soha'),
(4,3,'sameh'),
(5,4,'ashraf')
but, when I run this code to update the column id
update department
set id = 44 where id = 4
I get that error
The UPDATE statement conflicted with the FOREIGN KEY constraint "FK__employee__dept_i__571DF1D5". The conflict occurred in database "test", table "dbo.department", column 'id'.
The statement has been terminated.
but I do not know where is my fault!
thanks
Use ON UPDATE CASCADE in the foreign key constraint, like so:
create table employee
(
id int primary key,
dept_id int default 40 foreign key references department(id) on update cascade on delete set default,
name varchar(40)
);
If there is any update to the id column value, dept_id also gets updated to follow the changed value.
Because employee table have dept_id column *constraint* with id column of department. This error is encountered when the primary key of a table is updated but it is referenced by a foreign key from another table and the update specific is set to No action. The No action is the default option.
If this is your case and No action is set on the update operation you can change the foreign-key definition to Cascade
You can try this:
ALTER TABLE employee
DROP Constraint FK__employee__dept_i__571DF1D5
GO
ALTER TABLE employee
ADD CONSTRAINT New_FK_Constraint
FOREIGN KEY (dept_id) REFERENCES department (id)
ON DELETE CASCADE ON UPDATE CASCADE
GO
it's normally to that error to appear, You have a foreign key relation and you then change the value.
Use ON UPDATE CASCADE in the foreign key constraint
If you don't want to change your table structure, you can run the following query:
ALTER TABLE [UserStore]
NOCHECK CONSTRAINT FK_UserStore_User_UserId
ALTER TABLE [UserIdentity]
NOCHECK CONSTRAINT FK_UserIdentity_User_UserId
BEGIN TRAN
UPDATE [user]
SET Id = 10
WHERE Id = 9
UPDATE [dbo].[UserStore]
SET UserId = 10
WHERE UserId = 9
UPDATE [dbo].UserIdentity
SET UserId = 10
WHERE UserId = 9
COMMIT TRAN
ALTER TABLE [UserStore]
CHECK CONSTRAINT FK_UserStore_User_UserId
ALTER TABLE UserIdentity
CHECK CONSTRAINT FK_UserIdentity_User_UserId

Transfer data with different type Primary key

I'm redesigning very old DB where new tables have PK type UNIQUEIDENTIFIER and old tables have INT. There are also many relationships between tables. Can anyone help with how not to lose any relationships and change PK type when transferring data?
Old Table: Item(PK - itemID(int), FK - Vendor_Id(int), and Manufacture_Id(int) Manufacture ID is not as set FK but it should be in new table.
Let's say you have empty School and Student tables with UNIQUEIDENTIFIER typed primary keys named id.
Let's say the relationship between students and schools is many-to-one, via a school_id foreign key.
The old tables are called oldSchool and oldStudent and have id columns of type int. oldStudent
also has a foreign key named school_id.
Steps to take:
Extend all new tables that are referenced to by foreign keys with an extra column called old_id of type int. In the example table School would get this extra column:
ALTER TABLE School ADD old_id int;
All foreign key columns should get a sybling column of type int, called old_original_name. In our example
Student should get an extra old_school_id column
Temporarily disable foreign key constraints:
SET foreign_key_checks = 0;
Or, if that fails, drop all the foreign keys, to recreate them later, for example:
ALTER TABLE Student DROP FOREIGN KEY fk_school_id;
Also make those foreign key columns nullable:
ALTER TABLE Student MODIFY school_id int NULL;
Insert records from the old tables into the new tables, making sure the values of
primary keys and foreign keys are stored in the target's corresponding old_xxxxxx columns.
In the example, it would look like this:
INSERT INTO School (old_id, name, address)
SELECT id, name, address
FROM oldSchool;
INSERT INTO Student (name, class, old_school_id)
SELECT name, class, school_id
FROM oldStudent;
Update the foreign key columns which are null by looking up the new id via the old_xxxx foreign key values. In our example:
UPDATE Student
SET school_id = (
SELECT id
FROM School
WHERE old_id = Student.old_id);
Now make those foreign key columns not nullable again:
ALTER TABLE Student MODIFY school_id int NOT NULL;
Enable the foreign key constraints again.
SET foreign_key_checks = 1;
Or if you had to drop them, recreate them, for example:
ALTER TABLE Student
ADD CONSTRAINT fk_school_id
FOREIGN KEY (school_id)
REFERENCES School(id);
Optionally drop all the old_xxxxx columns from all your tables. In the example:
ALTER TABLE Student DROP COLUMN old_school_id;
ALTER TABLE School DROP COLUMN old_id;
Optionally drop all old tables. In the example:
DROP TABLE oldStudent;
DROP TABLE oldSchool;
Done.

Resources