0

I just need some in help to implement delete cascade in my stored procedure because I have REFERENCE constraint error

Create PROCEDURE [dbo].[DeleteProject]
    @ProjectID uniqueidentifier
AS
BEGIN
    -- Insert statements for procedure here
    DELETE FROM [TaskManagementSystem_DB].[dbo].[Projects]
    WHERE projectID = @ProjectID
END
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

2 Answers2

2

You don't implement delete cascade in the proc.

You either implement delete cascase on the foriegn key constraint itself:

ALTER TABLE [ChildTable] WITH CHECK ADD CONSTRAINT [FK_ChildTable_Projects] FOREIGN KEY ([ProjectID})
REFERENCES [Project] ([ProjectID])
ON DELETE CASCADE

or you need to explicitly delete the child record before you delete the master.

Create PROCEDURE [dbo].[DeleteProject]
@ProjectID uniqueidentifier
AS
BEGIN

DELETE child
FROM [TaskManagementSystem_DB].[dbo].[Projects] proj
    JOIN [TaskManagementSystem_DB].[dbo].[ChildTable] child
        ON proj.ProjectID = child.ProjectID

DELETE FROM [TaskManagementSystem_DB].[dbo].[Projects]
    WHERE projectID = @ProjectID

END
Jon Egerton
  • 40,401
  • 11
  • 97
  • 129
1

Here you can find a implementation that deletes all rows in the table specified that conform to the criteria selected, while also deleting any child/grandchild records and so on.
It first reads the sysforeignkeys table to find any child tables, then deletes the soon-to-be orphan records from them using recursive calls to this procedure. Once all child records are gone, the rows are deleted from the selected table: Awesome SQL Delete Cascade Stored Procedure!

Here it is the code, in case you are having problems following the link:

CREATE Procedure spDeleteRows
/* 
Recursive row delete procedure. 

It deletes all rows in the table specified that conform to the criteria selected, 
while also deleting any child/grandchild records and so on.  This is designed to do the 
same sort of thing as Access's cascade delete function. It first reads the sysforeignkeys 
table to find any child tables, then deletes the soon-to-be orphan records from them using 
recursive calls to this procedure. Once all child records are gone, the rows are deleted 
from the selected table.   It is designed at this time to be run at the command line. It could 
also be used in code, but the printed output will not be available.
*/
 (
 @cTableName varchar(50), /* name of the table where rows are to be deleted */
 @cCriteria nvarchar(1000), /* criteria used to delete the rows required */
 @iRowsAffected int OUTPUT /* number of records affected by the delete */
 )
As
set nocount on
declare  @cTab varchar(255), /* name of the child table */
 @cCol varchar(255), /* name of the linking field on the child table */
 @cRefTab varchar(255), /* name of the parent table */
 @cRefCol varchar(255), /* name of the linking field in the parent table */
 @cFKName varchar(255), /* name of the foreign key */
 @cSQL nvarchar(1000), /* query string passed to the sp_ExecuteSQL procedure */
 @cChildCriteria nvarchar(1000), /* criteria to be used to delete 
                                           records from the child table */
 @iChildRows int /* number of rows deleted from the child table */

/* declare the cursor containing the foreign key constraint information */
DECLARE cFKey CURSOR LOCAL FOR 
SELECT SO1.name AS Tab, 
       SC1.name AS Col, 
       SO2.name AS RefTab, 
       SC2.name AS RefCol, 
       FO.name AS FKName
FROM dbo.sysforeignkeys FK  
INNER JOIN dbo.syscolumns SC1 ON FK.fkeyid = SC1.id 
                              AND FK.fkey = SC1.colid 
INNER JOIN dbo.syscolumns SC2 ON FK.rkeyid = SC2.id 
                              AND FK.rkey = SC2.colid 
INNER JOIN dbo.sysobjects SO1 ON FK.fkeyid = SO1.id 
INNER JOIN dbo.sysobjects SO2 ON FK.rkeyid = SO2.id 
INNER JOIN dbo.sysobjects FO ON FK.constid = FO.id
WHERE SO2.Name = @cTableName

OPEN cFKey
FETCH NEXT FROM cFKey INTO @cTab, @cCol, @cRefTab, @cRefCol, @cFKName
WHILE @@FETCH_STATUS = 0
     BEGIN
 /* build the criteria to delete rows from the child table. As it uses the 
           criteria passed to this procedure, it gets progressively larger with 
           recursive calls */
 SET @cChildCriteria = @cCol + ' in (SELECT [' + @cRefCol + '] FROM [' + 
                              @cRefTab +'] WHERE ' + @cCriteria + ')'
 print 'Deleting records from table ' + @cTab
 /* call this procedure to delete the child rows */
 EXEC spDeleteRows @cTab, @cChildCriteria, @iChildRows OUTPUT
 FETCH NEXT FROM cFKey INTO @cTab, @cCol, @cRefTab, @cRefCol, @cFKName
     END
Close cFKey
DeAllocate cFKey
/* finally delete the rows from this table and display the rows affected  */
SET @cSQL = 'DELETE FROM [' + @cTableName + '] WHERE ' + @cCriteria
print @cSQL
EXEC sp_ExecuteSQL @cSQL
print 'Deleted ' + CONVERT(varchar, @@ROWCOUNT) + ' records from table ' + @cTableName
Luxspes
  • 6,268
  • 2
  • 28
  • 31
  • This approach can be ok, however it carries a risk: If the person who designed the database didn't include the `DELETE CASCADE` on the FK there could well be a reason for that. Ignoring that and going ahead with the delete can cause deletions the aren't desired. eg hypothetically: deleting a product might delete all orders related to that product that have already been fulfilled – Jon Egerton Aug 22 '12 at 16:08
  • Well, it dependes, from a different perspective, the sad thing about DELETE CASCADE is that it is an all or nothing proposition, you can no change the behavior dinamically based in business rules, it either deletes in cascade always.. or it does not. An approach based in a stored procedure can override this base on the particular problem that the developer is intending to solve – Luxspes Aug 22 '12 at 18:22