如何临时或按需级联删除?

How to cascade-delete temporarily or on-demand?

有时我试图在 MSSQL 中只删除一行,但由于外键约束的引用,我陷入了层次结构中无数次的删除。 有什么快速的方法可以自动级联删除而不必设置级联删除的外键约束?只有这一次我需要级联删除...按需 -- 并非总是如此。

有机会吗?有等价物吗?

由于一次性需要它,但又不希望它始终存在,因此我认为最好编写一个存储过程。

首先从 table 最远的地方删除,然后沿着树向上移动

这是一个例子:

Create Proc CascaseDeleteMyTable
    @MyTableId Int
As


Delete From ChildTable33 Where ChildParent33Id In (Select ChildParent33Id From ChildParent33 Where MyTableId = @MyTableId)

Delete From ChildTable2 Where MyTableId = @MyTableId

GO

如果您想要一个傻瓜式动态 sql 解决方案,它使用递归查询为从特定键派生的外键构建 table 层次结构。它生成需要执行的删除语句,以便(希望如此)从 table.

中删除特定行
use AdventureWorks2012

declare @tablename sysname = N'Production.Product';
declare @primarykeycolumn sysname = N'ProductId';
declare @value nvarchar(128) = '2';
declare @sql nvarchar(max);

;with tableHierarchy as (
select
    object_id = p.object_id
  , parent_id = cast(null as int)
  , schemaName = schema_name(p.schema_id)
  , tableName = object_name(p.object_id)
  , parentObjectName = cast(null as sysname)
  , parentToChild = cast(object_name(p.object_id) as varchar(max))
  , childToParent = cast(object_name(p.object_id) as varchar(max))
  , treelevel = 0
  , keyName = p.name
  , columnName = c.name
  , columnId = c.column_id
  , parentColumnName = c.name
from sys.objects as p
  inner join sys.columns c
    on p.object_id = c.object_id
where p.object_id  = object_id(@tablename)
  and c.name = @primarykeycolumn
union all
select
    object_id = fk.parent_object_id
  , parent_id = fk.referenced_object_id
  , schemaName = schema_name(fk.schema_id)
  , tableName = object_name(fk.parent_object_id)
  , parentObjectName = object_name(fk.referenced_object_id)
  , parentToChild = parentToChild + ' \ ' + cast(object_name(fk.parent_object_id) as varchar(128))
  , childToParent = cast(object_name(fk.parent_object_id) as varchar(128)) + ' \ ' + childToParent
  , treelevel = th.treelevel + 1
  , keyName = fk.name
  , columnName = c.name
  , columnId = c.column_id
  , parentColumnName = rc.name
from tableHierarchy as th
  inner join sys.foreign_keys as fk
    on fk.referenced_object_id = th.object_id
   and fk.referenced_object_id != fk.parent_object_id 
  inner join sys.foreign_key_columns fkc
    on fk.object_id = fkc.constraint_object_id
  and fkc.referenced_column_id = th.columnId
  inner join sys.columns c
    on fkc.parent_object_id = c.object_id
   and fkc.parent_column_id = c.column_id
  inner join sys.columns rc
    on fkc.referenced_object_id = rc.object_id
   and fkc.referenced_column_id = rc.column_id
)
select @sql = stuff((
  select 
      char(10)
    --+'/* treelevel: '+convert(nvarchar(10),treelevel)
    --+' | ' + childtoparent +' */'+char(10)
    +'delete from '+quotename(schemaName)+'.'+quotename(tableName)
    +' where '+quotename(columnName)+' = '+@value+';'
  from tableHierarchy
  group by treelevel, childtoparent, schemaName, tableName, columnName
  order by treelevel desc, childtoparent
  for xml path (''), type).value('.','nvarchar(max)')
  ,1,1,'')
  option ( maxrecursion 100 );

select @sql as CodeGenerated;
--exec sp_executesql @sql;

生成的代码:

delete from [Sales].[SalesOrderDetail] where [ProductID] = 2;
delete from [Production].[BillOfMaterials] where [ComponentID] = 2;
delete from [Production].[BillOfMaterials] where [ProductAssemblyID] = 2;
delete from [Production].[ProductCostHistory] where [ProductID] = 2;
delete from [Production].[ProductDocument] where [ProductID] = 2;
delete from [Production].[ProductInventory] where [ProductID] = 2;
delete from [Production].[ProductListPriceHistory] where [ProductID] = 2;
delete from [Production].[ProductProductPhoto] where [ProductID] = 2;
delete from [Production].[ProductReview] where [ProductID] = 2;
delete from [Purchasing].[ProductVendor] where [ProductID] = 2;
delete from [Purchasing].[PurchaseOrderDetail] where [ProductID] = 2;
delete from [Sales].[ShoppingCartItem] where [ProductID] = 2;
delete from [Sales].[SpecialOfferProduct] where [ProductID] = 2;
delete from [Production].[TransactionHistory] where [ProductID] = 2;
delete from [Production].[WorkOrder] where [ProductID] = 2;
delete from [Production].[Product] where [ProductID] = 2;