我有一个 sp 可以从孙子表中删除数据。
但我需要更改光标并使用临时表或 while 循环而不是光标。我试过但没有工作,有人可以帮忙。
Sp在下面添加
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
我必须说,我通常建议您使用级联外键,或者手动编写代码。
尽管如此,您不需要游标或
WHILE
循环。您可以使用递归 CTE 构建查询,它获取每个外键关系并构造它的动态 CTE,然后按顺序从每个外键中删除。请注意,我的过程没有考虑自引用外键(为此您需要动态递归 CTE),也没有处理多个级联路径。我把它留给读者作为练习。
您需要连接列的 TVF,因为您不能在递归 CTE 中进行聚合。
最后的程序是
db<>小提琴
例如,生成的 SQL 可能如下所示
如果
STRING_AGG
您的 SQL Server 版本不支持,您需要使用FOR XML
和