检查触发器中删除的几个if语句的条件

时间:2015-01-17 18:40:24

标签: sql sql-server if-statement triggers sql-delete

我有这个触发器,用于检查子表中是否没有数据存储空间混合'与工作区(Areanr,Spacenr)相关,工作区中允许删除工作区'工作区'。否则触发器会触发以防止删除。但是,如果我想对几个儿童桌子进行检查,而不仅仅是“太空混合物”' - 怎么做的?

当前触发码:

CREATE TRIGGER trg_DeleteWorkspace ON Workspaces
FOR DELETE AS
BEGIN

--Check if data is in childtable 'Spacemixes':
IF NOT EXISTS (SELECT * FROM Spacemixes s WHERE
(s.areanr <> (select d.areanr from deleted d))
AND
(s.spacenr <> (select d.spacenr from deleted d))
)
--If not, delete a workpace:
BEGIN
delete from Workspaces
where (areanr = (Select d.areanr FROM deleted d))
and
(spacenr = (select d.spacenr from deleted d))
END

--If there's data in childtable, print out error msg and do a rollback
ELSE
Begin
 raiserror('Cannot delete a workspace when data is stored in child tables!', 16, 1)
 rollback transaction
End

END

示例数据:

--Parent table
CREATE TABLE Workspaces (
Areanr CHAR(2)
CONSTRAINT ck_a_areanr REFERENCES areanr(areanr)
ON DELETE CASCADE
ON UPDATE NO ACTION,
Spacenr INT
CONSTRAINT ck_spacenr CHECK (spacenr > 0 AND spacenr < 1001),
Area DECIMAL(2,1)
CONSTRAINT ck_area CHECK (area > 0),
CONSTRAINT ck_workspaces PRIMARY KEY (areanr, spacenr)
)

--Example of a childtable:
CREATE TABLE Spacemixes (
Areanr CHAR(2),
Spacenr INT,
Woodcode CHAR(1)
CONSTRAINT ck_y_spacemixes REFERENCES Woodtypes(Code),
Percentage INT
CONSTRAINT ck_percentage CHECK (percentage >= 0 AND percentage < 11),
CONSTRAINT fk_spacemixes FOREIGN KEY (Areanr, Spacenr) REFERENCES Workspaces(Areanr, Spacenr)
ON DELETE CASCADE
ON UPDATE NO ACTION,
CONSTRAINT ck_spacemixes PRIMARY KEY (Areanr, Spacenr, Woodcode)
)

期望的结果:

让我们说我试图删除工作区(Areanr和Spacenr是工作区中的PK):

DELETE Workspaces WHERE Areanr=1 AND Spacenr=2

如果存在使用(Areanr = 1和Spacenr = 2)的子表,则不应允许删除。否则应该。

1 个答案:

答案 0 :(得分:0)

您编码的触发器不会处理多行删除。请记住,触发器每个语句触发一次,而不是每行触发一次,因此代码应该假定已删除的表可能包含多行。

下面的技术使用连接而不是标量子查询来识别受影响的行。只需为其他子表添加EXISTS子查询。

CREATE TABLE dbo.Workspaces(
      areanr int
    , spacenr int
    , CONSTRAINT PK_Workspaces PRIMARY KEY(areanr, spacenr)
);

CREATE TABLE dbo.Spacemixes(
      areanr int
    , spacenr int
    , CONSTRAINT PK_Spacemixes PRIMARY KEY(areanr, spacenr)
);

CREATE TABLE dbo.SomeOtherTable(
      areanr int
    , spacenr int
    , CONSTRAINT PK_SomeOtherTable PRIMARY KEY(areanr, spacenr)
);

INSERT INTO dbo.Workspaces VALUES(1,1)
INSERT INTO dbo.Workspaces VALUES(2,2)
INSERT INTO dbo.Workspaces VALUES(3,3)
INSERT INTO dbo.Workspaces VALUES(4,4)

INSERT INTO dbo.Spacemixes VALUES(1,1)
INSERT INTO dbo.SomeOtherTable VALUES(1,1)

INSERT INTO dbo.Spacemixes VALUES(2,2)
INSERT INTO dbo.SomeOtherTable VALUES(3,3)
GO

CREATE TRIGGER trg_DeleteWorkspace ON dbo.Workspaces
    FOR DELETE
AS
    --Check if data is in childtable 'Spacemixes':
    IF EXISTS ( SELECT  *
                    FROM    Spacemixes s
                            JOIN deleted d ON d.areanr = s.areanr
                                              AND d.spacenr = s.spacenr )
        OR EXISTS ( SELECT *
                         FROM   SomeOtherTable s
                                JOIN deleted d ON d.areanr = s.areanr
                                                  AND d.spacenr = s.spacenr  )
        BEGIN
            RAISERROR('Cannot delete a workspace when data is stored in child tables!', 16, 1);
            ROLLBACK TRANSACTION;
        END;
GO

--this fails due to rows in both Spacemixes and SomeOtherTable
DELETE FROM dbo.WorkSpaces
WHERE areanr = 1;
GO

--this fails due to row in Spacemixes
DELETE FROM dbo.WorkSpaces
WHERE areanr = 2;
GO

--this fails due to row in SomeOtherTable
DELETE FROM dbo.WorkSpaces
WHERE areanr = 3;
GO

--this succeeds
DELETE FROM dbo.WorkSpaces
WHERE areanr = 4;
GO