有时候我试图在MSSQL中只删除一行,由于外键约束引起的引用,我在层次结构中陷入了无数的删除。 是否有任何快速方法可以自动级联删除而无需使用级联删除设置外键约束?只有这一次,我需要按需级联删除...并不总是。
有机会吗?任何等价物?
答案 0 :(得分:1)
如果你想要一个瞄准和射击动态sql解决方案,它使用递归查询来构建从特定键下降的外键的表层次结构。有了它,就会生成需要执行的删除语句,按顺序(希望)从表中删除特定的行。
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;
答案 1 :(得分:0)
由于你需要它用于一次性目的,但你不希望它总是存在,我认为你最好把它写成存储过程。
首先从最远的桌子上删除,然后按照树木的方式工作
以下是一个例子:
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