SQL Server:删除行触发器

use*_*696 2 trigger sql-server sql-server-2017

我有这 3 个表:

构造函数员工

  • EID (员工 ID)作为主键和其他键。

项目

  • PID 作为主键和其他键。

项目建设者员工

  • PIDEID作为其他表的外键。

每个ConstructorEmployee可以在几个Projects. 我需要创建一个触发器,如果项目已被删除,我需要删除所有ConstructorEmployee 该工作在这个项目上。我需要从ConstructorEmployee表中删除它们。

我正在研究 SQL Server 2017。

McN*_*ets 6

我假设您的表架构类似于下一个:

CREATE TABLE ConstructorEmployee 
(
    EID int PRIMARY KEY
);

CREATE TABLE Project 
(
    PID int PRIMARY KEY
);

CREATE TABLE ProjectConstructorEmployee 
(
    PID int, 
    EID int, 
    CONSTRAINT PK_PCE PRIMARY KEY(PID, EID),
    CONSTRAINT FK_P FOREIGN KEY (PID) REFERENCES Project (PID),
    CONSTRAINT FK_CE FOREIGN KEY (EID) REFERENCES ConstructorEmployee (EID)
);
GO
Run Code Online (Sandbox Code Playgroud)

ProjectConstructorEmployee桌子上有两个外键。

现在让我添加一些数据 3 名员工和 3 个项目,但 Employee=1 仅适用于第一个项目。

INSERT INTO ConstructorEmployee VALUES (1), (2),(3);  
GO

INSERT INTO Project VALUES (1), (2), (3);
GO

-- EID = 1 worked in PID 1 only
INSERT INTO ProjectConstructorEmployee VALUES
(1, 1), (1, 2), (2, 2), (2, 3), (3, 2), (3, 3);
GO
Run Code Online (Sandbox Code Playgroud)

下一个查询返回仅在一个项目中工作过的员工列表,在本例中为 PID=1

-- Employees working on PID=1 that didn't work in any other project
SELECT EID
FROM   ProjectConstructorEmployee
WHERE  EID IN (SELECT EID FROM ProjectConstructorEmployee WHERE PID=1)
GROUP BY EID
HAVING COUNT(*) = 1
GO

| EID |
| --: |
|   1 |
Run Code Online (Sandbox Code Playgroud)

我需要创建一个触发器...

不,不要使用触发器,让我建议使用存储过程,这对您和任何其他开发人员来说总是更清楚。或者,如果您想使用触发器,请使用调用此过程的 BEFORE DELETE 触发器。

CREATE PROCEDURE DeleteProject(@PID int)
AS
BEGIN
    BEGIN TRY

        DECLARE @employee TABLE (EID int);

        BEGIN TRANSACTION;

        -- save a list of employees that only worked in this proejct
        -- due to FOREIGN KEYS you can't delete ConstructorEmployee table
        -- until you have deleted the other both.
        INSERT INTO @employee
        SELECT EID
        FROM   ProjectConstructorEmployee
        WHERE  EID IN (SELECT EID 
                       FROM ProjectConstructorEmployee 
                       WHERE PID = @PID)
        GROUP BY EID
        HAVING COUNT(*) = 1;                   

        DELETE FROM ProjectConstructorEmployee
        WHERE  PID = @PID;

        DELETE FROM Project
        WHERE  PID = @PID;

        DELETE FROM ConstructorEmployee
        WHERE EID IN (SELECT EID FROM @employee);

        IF @@TRANCOUNT > 0
            COMMIT TRANSACTION;

    END TRY
    BEGIN CATCH

        IF @@TRANCOUNT > 0
            ROLLBACK TRANSACTION;

        -- Your error handler

        THROW;

    END CATCH
END
GO
Run Code Online (Sandbox Code Playgroud)

好的,让我通过删除项目 1 和 2 来尝试:

EXEC DeleteProject @PID = 1;
EXEC DeleteProject @PID = 2;

SELECT * FROM ConstructorEmployee;
SELECT * FROM Project;
SELECT * FROM ProjectConstructorEmployee;
GO
Run Code Online (Sandbox Code Playgroud)

剩余员工:

| EID |
| --: |
|   2 |
|   3 |
Run Code Online (Sandbox Code Playgroud)

项目:

| PID |
| --: |
|   3 |
Run Code Online (Sandbox Code Playgroud)

和项目员工:

PID | EID
--: | --:
  3 |   2
  3 |   3
Run Code Online (Sandbox Code Playgroud)

db<>在这里摆弄

但是……您确定要删除所有这些信息吗?

您将丢失所有项目的历史记录,员工和项目将从您的数据库中消失。也许你可以设置一个像 Active(Yes/No) 这样的标志,让这个信息可供以后想要恢复的人使用。