I have around 40 delete query statement in a procedure for delete record from multiple tables for foreign key records.
example
Create Proc usp_delete_record(#id int)
as
Begin
Delete from table1 where id=#id;
Delete from table2 where id=#id;
Delete from table3 where id=#id;
Delete from table4 where id=#id;
Delete from table5 where id=#id;
Delete from table6 where id=#id;
Delete from table7 where id=#id;
Delete from table8 where id=#id;
....................
.................
Delete from table40 where id=#id;
End
It is very slow or hang execution.
How to handle this?
no needed of a procedure since u have it as a foreign key. just delete in the parent table with cascade.
so recreate your foriegn key for all child tables as
ALTER TABLE <childtables> WITH CHECK
ADD CONSTRAINT <fk_blah_blah> FOREIGN KEY(id)
REFERENCES <parenttable> (id)
ON DELETE CASCADE
Once you have this in place, you can delete the single record in parent table and so all 40 tables data are deleted
USE ON DELETE CASCADE:
CREATE TABLE parent (parent_id integer primary key );
CREATE TABLE child (child_name TEXT primary key,parent_id integer REFERENCES parent (parent_id) ON DELETE CASCADE);
Related
I have two tables: T_User and T_Order
T_User
--------
ID
Name
T_Order has to foreign keys to T_User
T_Order
--------
ID
FK_UserActionOwnerID
FK_UserActionReceiverID
I made two relations then on my diagram from T_User ID to both FK's in T_Order. I also set for both relationships delete and update rules to cascade because i want if T_User record will be deleted so therefore records in T_Order should be deleted or if T_User ID would change then also update it in T_Order. Nevertheless i get following error:
'T_User' table saved successfully 'T_Order' table
- Unable to create relationship 'FK_T_Order_T_Users1'. Introducing FOREIGN KEY constraint 'FK_T_Order_T_Users1' on table 'T_Order' may
cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or
ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could
not create constraint or index. See previous errors.
Real diagram:
click here
The Foreign key constraint may cause cycles or multiple cascade paths? question linked to by #Martin-Brown suggests using triggers instead of cascading foreign keys. Here's an example of using an INSTEAD OF DELETE trigger to do what (I think) you want to do.
-- Create tables
create table dbo.T_User (
ID int identity not null primary key,
Name varchar(100) not null
)
create table dbo.T_Order (
ID int identity not null primary key,
FK_UserActionOwnerID int not null,
FK_UserActionReceiverID int not null
)
go
-- Create foreign keys
alter table dbo.T_Order add constraint FK_T_Order_T_Users1 FOREIGN KEY (FK_UserActionOwnerID) REFERENCES dbo.T_User (ID)
alter table dbo.T_Order add constraint FK_T_Order_T_Users2 FOREIGN KEY (FK_UserActionReceiverID) REFERENCES dbo.T_User (ID)
go
-- Create trigger
create trigger tr_T_User_Delete on dbo.T_User instead of delete as
begin
if (##rowcount = 0) return
delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionOwnerID
delete o from dbo.T_Order o inner join deleted d on d.ID = o.FK_UserActionReceiverID
delete u from dbo.T_User u inner join deleted d on d.ID = u.ID
end
go
-- Demo
insert dbo.T_User (Name) values ('Peter'), ('Paul') -- Assume identity ID 1 and 2
insert dbo.T_Order (FK_UserActionOwnerID, FK_UserActionReceiverID) values (1, 1), (1, 2), (2, 2)
select * from dbo.T_Order
delete from dbo.T_User where ID = 1
select * from dbo.T_Order
You can use INSTEAD OF UPDATE triggers in the same way but you might want to have a think about whether it makes sense for IDs to be updated - I wouldn't normally expect this.
This trigger should delete a row from the parent table that is not deleted from the child table. The error is in the image below.
My code attempt:
CREATE TRIGGER ProductDeleted ON Product
for DELETE AS
BEGIN
DELETE FROM OrderItem
WHERE ProductID = (SELECT ProductID FROM DELETED)
END
help me please
You could simplify it by adding a CASCADE DELETE hint on a foreign key constraint such as
CREATE TABLE OrderItem
(
ID INT ,
ProductID NOT NULL UNIQUE
CONSTRAINT fk_Products
REFERENCES Products (ID) ON DELETE CASCADE
);
Since you already have a table, all you need to do is drop the constraint and recreate a new one.
ALTER TABLE OrderItem DROP
CONSTRAINT fk_ProductID;
ALTER TABLE OrderItem ADD
CONSTRAINT fk_ProductID
FOREIGN KEY (ID)
REFERENCES Product (ID)
ON DELETE CASCADE;
What this means, is that , any time you delete a record from the parent table (Product), child records from (OrderItem)will be deleted as well, so you dont have to use triggers, unless if you want to do some recording.
If you are really insisting on using triggers then you can tweak it a little bit like this :
ALTER TRIGGER ProductDeleted on Product
INSTEAD OF DELETE AS
BEGIN
SET NOCOUNT ON;
/* First we are deleting referenced columns in OrderItem table */
DELETE FROM OrderItem
where ProductID IN (select deleted.ID /* Columns from product Table */ from deleted)
/* Now we are doing actual delete statement */
DELETE FROM Products where ID IN (select deleted.ID from deleted)
END
But once again you should consider using ON CASCADE DELETE, its much simpler to setup, easier to maintain and you can have only one INSTEAD OF trigger per table, so if you ever need to do something more meaningful you would have to change this one, and add extra overhead.
Add SET NOCOUNT ON as the first thing in the trigger's body (after BEGIN).
I have three tables
GroupTable
GroupId
Name
Each group has a one to many with Users
Users
UserId
Name
GroupId
And each User has one to many with 'Challenges'
Challenges
Name
UserId
I want to be able to delete a group with the users assigned to that specific group
I have tried this where I do manage to delete the Group based on id without getting a foreign key constraint error but ALL the users added to the user table and ALL the challenges get deleted as well
ALTER TABLE GroupTable NOCHECK CONSTRAINT ALL
ALTER TABLE UserTable NOCHECK CONSTRAINT ALL
ALTER TABLE Challanges NOCHECK CONSTRAINT ALL
DELETE FROM GroupTable
WHERE ID = #GroupId
DELETE FROM child
FROM Challanges as child
INNER JOIN UserTable AS parent
ON child.UserId = parent.ID
WHERE parent.GroupId = #GroupId
DELETE FROM parent
FROM UserTable AS parent
WHERE GroupId = GroupId
How can I ammend the above so that I only delete the gropu with the specific Users and there challenges assigned to the Group?
Do not disable the constraints for this, as it will compromise data integrity.
Either use on delete cascade option on the foreign keys, or delete the data from all three tables in the correct order, inside a single transaction.
To add on cascade delete to an existing foreign key you must use the alter table statement to drop the existing constraint and then add it again with the on delete cascade option:
ALTER TABLE table_name
DROP CONSTRAINT constraint_name
ALTER TABLE table_name
ADD CONSTRAINT constraint_name
FOREIGN KEY (column_name)
REFERENCES other_table_name(other_column_name) ON DELETE CASCADE
(of course, this can be done using ssms's design table window)
Deleting the rows from the related tables in the correct order will ensure you will encounter no problems with the existing foreign key constraints, wrapping all the delete statement in a single transaction will ensure you will only delete from every table or none at all:
DECLARE #GroupId int = 5
BEGIN TRY
BEGIN TRANSACTION
DELETE c
FROM Challanges c
INNER JOIN UserTable u ON(c.UserId = u.UserId)
WHERE u.GroupId = #GroupId
DELETE
FROM Users
WHERE GroupId = #GroupId
DELETE
FROM GroupTable
WHERE ID = #GroupId
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF ##TRANCOUNT > 0
ROLLBACK TRANSACTION
END CATCH
I have 2 tables: T1 and T2, they are existing tables with data. We have a one to many relationship between T1 and T2. How do I alter the table definitions to perform cascading delete in SQL Server when a record from T1 is deleted, all associated records in T2 also deleted.
The foreign constraint is in place between them. I don't want to drop the tables or create a trigger to do the deletion for T2. For example, when I delete an employee, all the review record should be gone, too.
T1 - Employee,
Employee ID
Name
Status
T2 - Performance Reviews,
Employee ID - 2009 Review
Employee ID - 2010 Review
To add "Cascade delete" to an existing foreign key in SQL Server Management Studio:
First, select your Foreign Key, and open it's "DROP and Create To.." in a new Query window.
Then, just add ON DELETE CASCADE to the ADD CONSTRAINT command:
And hit the "Execute" button to run this query.
By the way, to get a list of your Foreign Keys, and see which ones have "Cascade delete" turned on, you can run this script:
SELECT
OBJECT_NAME(f.parent_object_id) AS 'Table name',
COL_NAME(fc.parent_object_id,fc.parent_column_id) AS 'Field name',
delete_referential_action_desc AS 'On Delete'
FROM sys.foreign_keys AS f,
sys.foreign_key_columns AS fc,
sys.tables t
WHERE f.OBJECT_ID = fc.constraint_object_id
AND t.OBJECT_ID = fc.referenced_object_id
ORDER BY 1
And if you ever find that you can't DROP a particular table due to a Foreign Key constraint, but you can't work out which FK is causing the problem, then you can run this command:
sp_help 'TableName'
The SQL in that article lists all FKs which reference a particular table.
Hope all this helps.
Apologies for the long finger. I was just trying to make a point.
You will need to,
Drop the existing foreign key constraint,
Add a new one with the ON DELETE CASCADE setting enabled.
Something like:
ALTER TABLE dbo.T2
DROP CONSTRAINT FK_T1_T2 -- or whatever it's called
ALTER TABLE dbo.T2
ADD CONSTRAINT FK_T1_T2_Cascade
FOREIGN KEY (EmployeeID) REFERENCES dbo.T1(EmployeeID) ON DELETE CASCADE
You can do this with SQL Server Management Studio.
→ Right click the table design and go to Relationships and choose the foreign key on the left-side pane and in the right-side pane, expand the menu "INSERT and UPDATE specification" and select "Cascade" as Delete Rule.
Use something like
ALTER TABLE T2
ADD CONSTRAINT fk_employee
FOREIGN KEY (employeeID)
REFERENCES T1 (employeeID)
ON DELETE CASCADE;
Fill in the correct column names and you should be set. As mark_s correctly stated, if you have already a foreign key constraint in place, you maybe need to delete the old one first and then create the new one.
ON DELETE CASCADE
It specifies that the child data is deleted when the parent data is deleted.
CREATE TABLE products
( product_id INT PRIMARY KEY,
product_name VARCHAR(50) NOT NULL,
category VARCHAR(25)
);
CREATE TABLE inventory
( inventory_id INT PRIMARY KEY,
product_id INT NOT NULL,
quantity INT,
min_level INT,
max_level INT,
CONSTRAINT fk_inv_product_id
FOREIGN KEY (product_id)
REFERENCES products (product_id)
ON DELETE CASCADE
);
For this foreign key, we have specified the ON DELETE CASCADE clause which tells SQL Server to delete the corresponding records in the child table when the data in the parent table is deleted. So in this example, if a product_id value is deleted from the products table, the corresponding records in the inventory table that use this product_id will also be deleted.
First To Enable ONCascade property:
1.Drop the existing foreign key constraint
2.add a new one with the ON DELETE CASCADE setting enabled
Ex:
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Response'))
BEGIN
ALTER TABLE [dbo].[Response] DROP CONSTRAINT [FK_Response_Request]
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END
ELSE
BEGIN
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END
Second To Disable ONCascade property:
1.Drop the existing foreign key constraint
2.Add a new one with the ON DELETE NO ACTION setting enabled
Ex:
IF EXISTS(SELECT 1 FROM sys.foreign_keys WHERE parent_object_id = OBJECT_ID(N'dbo.Response'))
BEGIN
ALTER TABLE [dbo].[Response] DROP CONSTRAINT [FK_Response_Request]
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE CASCADE
END
ELSE
BEGIN
ALTER TABLE [dbo].[Response] WITH CHECK ADD CONSTRAINT [FK_Response_Request] FOREIGN KEY([RequestId])
REFERENCES [dbo].[Request] ([RequestId])
ON DELETE NO ACTION
END
If the one to many relationship is from T1 to T2 then it doesn't represent a function and therefore cannot be used to deduce or infer an inverse function that guarantees the resulting T2 value doesn't omit tuples of T1 join T2 that are deductively valid, because there is no deductively valid inverse function. ( representing functions was the purpose of primary keys. ) The answer in SQL think is yes you can do it. The answer in relational think is no you can't do it. See points of ambiguity in Codd 1970. The relationship would have to be many-to-one from T1 to T2.
I think you cannot just delete the tables property what if this is actual production data, just delete the contents that dont affect the table schema.
Suppose I have 3 tables
t1
Nid name
1 aaa
2 bbb
3 ccc
delT1
Nid name
t2
Sid Nid value
1 1 AAA
2 1 BAC
3 2 CSA
In table t1 Nid is primary key which is foreign key for t2
Now what I want is when I delete value from t1 it automatically deletes all values from t2 where t1.Nid=t2.Nid and a value of deleted t1 get inserted into delT1
How can I create a trigger for this type of task?
Please help me since I am new to sql
A normal trigger wouldn't work: the foreign key would give an error before the code runs.
What you can do is set a CASCADE on your foreign key so a delete in T1 will delete from T2 automatically.
Personally, I'd use a stored proc and transaction to delete from T2 first, then T1.
Modify the FK in T2 to be ON DELETE CASCADE:
ALTER TABLE T2 DROP CONSTRAINT FK_T1_Nid; <-- your constraint name here
ALTER TABLE T2 ADD CONSTRAINT FK_T1_Nid FOREIGN KEY (Nid)
REFERENCES T1 (Nid) ON DELETE CASCADE;
Then create a trigger on T1 to push the information to delT1:
CREATE TRIGGER TR_T1_D ON T1 FOR DELETE
AS
SET NOCOUNT ON;
INSERT delT1
SELECT Nid, Name
FROM Deleted;
Note this trigger prevents you from using an OUTPUT clause on DELETEs against T1. BOL says:
If the OUTPUT clause is specified without also specifying the INTO keyword, the target of the DML operation cannot have any enabled trigger defined on it for the given DML action. For example, if the OUTPUT clause is defined in an UPDATE statement, the target table cannot have any enabled UPDATE triggers.
#gbn has the preferred way to go. Since you asked for a trigger, you could do this for comparison's sake:
CREATE TRIGGER t1_Delete ON t1
INSTEAD OF DELETE AS BEGIN SET NOCOUNT ON;
INSERT INTO delT1 (Nid, name)
SELECT Nid, name
FROM DELETED;
DELETE FROM t2
WHERE t2.Nid IN (SELECT Nid FROM DELETED);
DELETE FROM t1
WHERE t1.Nid IN (SELECT Nid FROM DELETED);
END;