微软 SQL。级联删除和触发器

Posted

技术标签:

【中文标题】微软 SQL。级联删除和触发器【英文标题】:MS SQL. Cascade Delete and triggers 【发布时间】:2015-11-26 08:57:07 【问题描述】:

小问题:“当我使用级联删除 DeliveryHeader 时,DeliveryLine 上没有触发触发器”

详情:

我有一张桌子

CREATE TABLE [dbo].[DeliveryHeader](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    CONSTRAINT [PK_DeliveryHeader] PRIMARY KEY CLUSTERED 
    ([Id] ASC)
); 

CREATE TABLE [dbo].[DeliveryLine](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [DeliveryHeaderId] [int] NOT NULL,
    CONSTRAINT [PK_DeliveryLine] PRIMARY KEY CLUSTERED 
    (   [Id] ASC )
);

外键级联删除:

ALTER TABLE [dbo].[DeliveryLine]  WITH CHECK ADD  CONSTRAINT [FK_DeliveryLine_DeliveryHeader] FOREIGN KEY([DeliveryHeaderId])
REFERENCES [dbo].[DeliveryHeader] ([Id])
ON DELETE CASCADE;

我在 DeliveryLine 上有一个触发器

CREATE TRIGGER [dbo].[trg_DeliveryLine_DeleteLog]   
    ON [dbo].[DeliveryLine]
    AFTER DELETE
AS 
BEGIN
    SET NOCOUNT ON;
    -- some code    
END

但是当我删除 DeliveryHeader 时,DeliveryLine 上的触发器没有触发

DELETE FROM [dbo].[DeliveryHeader];

有什么方法可以通过级联删除触发触发器吗?我只知道迂回的方式:

    从外键中删除级联。 更新:

    编写另一个触发器:

    CREATE TRIGGER [dbo].[trg_DeliveryHeader_DeleteLog]   
    ON [dbo].[DeliveryHeader]
    INSTEAD OF DELETE
    AS 
    BEGIN
        SET NOCOUNT ON;
    
        DELETE FROM [dbo].[DeliveryLine] WHERE [DeliveryHeaderId] IN (SELECT Id from deleted)
        DELETE FROM [dbo].[DeliveryHeader] WHERE [Id] IN (SELECT Id from deleted)
    END
    

【问题讨论】:

我真的相信级联删除是邪恶的。另一种方法是创建一个过程来删除您想要的内容,并在其中明确说明您要删除的内容。 是的,我知道。我使用它非常罕见。一个很仔细。 【参考方案1】:
IF OBJECT_ID('dbo.[DeliveryLine]', 'U') IS NOT NULL
    DROP TABLE dbo.[DeliveryLine]
GO
IF OBJECT_ID('dbo.[DeliveryHeader]', 'U') IS NOT NULL
    DROP TABLE dbo.[DeliveryHeader]
GO
CREATE TABLE dbo.DeliveryHeader (
    Id INT /*IDENTITY(1,1)*/ PRIMARY KEY
)
GO
CREATE TABLE dbo.DeliveryLine (
    Id INT IDENTITY(1,1) PRIMARY KEY,
    DeliveryHeaderId INT NOT NULL
)

ALTER TABLE dbo.DeliveryLine WITH CHECK
    ADD CONSTRAINT FK_DeliveryLine_DeliveryHeader FOREIGN KEY(DeliveryHeaderId)
    REFERENCES dbo.DeliveryHeader(Id)
    ON DELETE CASCADE
GO

CREATE TRIGGER [dbo].[trg_DeliveryLine_DeleteLog]   
    ON [dbo].[DeliveryLine]
    AFTER DELETE
AS 
BEGIN

    SET NOCOUNT ON;
    PRINT 'all works!!!'

END
GO

INSERT INTO dbo.DeliveryHeader (Id) VALUES (0)
INSERT INTO dbo.DeliveryLine (DeliveryHeaderId) VALUES (0)
GO

DELETE FROM dbo.DeliveryHeader WHERE Id = 0 -- trigger fire only when data exists in both tables


INSERT INTO dbo.DeliveryHeader (Id) VALUES (1) -- trigger not fire
DELETE FROM dbo.DeliveryHeader WHERE Id = 1

【讨论】:

然后呢?不能加两个字吗? 正确。对不起,我没有真正的数据。这就是为什么没有工作 @Giorgi Nakeuri,我更喜欢简洁地回答:) @Devart,我更喜欢阅读 OP 的代码有什么问题。您可以只说“嘿,OP,它应该可以工作,检查您的数据”,而不是从问题中逐字复制粘贴代码并将其作为答案。抱歉,我不赞成。

以上是关于微软 SQL。级联删除和触发器的主要内容,如果未能解决你的问题,请参考以下文章

sql中级联删除,级联更新是怎么理解的?

sql2000 如何用触发器实现级联删除

sql中如何实现级联表的操作

如何在 SQL Server 中使用级联删除?

SQL数据库怎么进行多表级联更新,求个存储过程

SQL Server - 使用递归外键级联删除