Rom*_*ias 2 foreign-key sql-server sql-server-2014 cascade
在 SQL Server 2014 中,我试图在 3 FK 上添加CASCADE DELETING(我想实际上将字段设置为 null,但相同)。如果我在一个关系中添加级联删除,它工作正常。如果我添加更多级联删除,则不起作用(检测到循环错误消息)。
在上图中,您可以看到用户表和任务表(西班牙语中的“Tareas”)。所以,我需要完成的是,当用户被删除时,我需要将 Tasks 中的标记字段设置为 NULL。
这在数据库中很常见,所以我认为有一种方法可以解决这个问题。
就我而言,我的大多数表都有一对字段,其中包含创建或修改记录的用户的 UserId。所以,我需要解决这个模式来将它应用到几个地方。
您可以创建触发器来更新相关表中的 UserID 列,例如:
USE Tempdb;
CREATE TABLE dbo.Users
(
UserID INT NOT NULL CONSTRAINT PK_Users
PRIMARY KEY CLUSTERED
, ApplicationID INT NOT NULL
, Country VARCHAR(255) NOT NULL
, DefaultTenantID INT NOT NULL
);
GO
CREATE TABLE dbo.Tasks
(
TaskID INT NOT NULL
, TenantID INT NOT NULL
, CreatedBy_UserID INT NULL
CONSTRAINT FK_Tasks_CreatedBy
FOREIGN KEY REFERENCES dbo.Users(UserID)
, ModifiedBy_UserID INT NULL
CONSTRAINT FK_Tasks_ModifiedBy
FOREIGN KEY REFERENCES dbo.Users(UserID)
, AssignedTo_UserID INT NULL
CONSTRAINT FK_Tasks_AssignedTo
FOREIGN KEY REFERENCES dbo.Users(UserID)
);
GO
INSERT INTO dbo.Users (UserID, ApplicationID, Country, DefaultTenantID)
VALUES (1, 1, 'CA', 1);
INSERT INTO dbo.Tasks (TaskID, TenantID, CreatedBy_UserID, ModifiedBy_UserID, AssignedTo_UserID)
VALUES (1, 1, 1, NULL, NULL);
GO
CREATE TRIGGER TG_Users_Trigger
ON dbo.Users
INSTEAD OF DELETE
AS
BEGIN
UPDATE dbo.Tasks
SET CreatedBy_UserID = NULL
WHERE EXISTS (
SELECT 1
FROM deleted d
WHERE d.UserID = CreatedBy_UserID
);
UPDATE dbo.Tasks
SET ModifiedBy_UserID = NULL
WHERE EXISTS (
SELECT 1
FROM deleted d
WHERE d.UserID = ModifiedBy_UserID
);
UPDATE dbo.Tasks
SET AssignedTo_UserID = NULL
WHERE EXISTS (
SELECT 1
FROM deleted d
WHERE d.UserID = AssignedTo_UserID
);
DELETE
FROM dbo.Users
WHERE EXISTS (
SELECT 1
FROM deleted d
WHERE d.UserID = UserID
);
END
GO
DELETE
FROM dbo.Users;
SELECT *
FROM dbo.Users;
SELECT *
FROM dbo.Tasks;
/* - cleanup removed for safety
DROP TRIGGER TG_Users_Trigger;
DROP TABLE dbo.Tasks;
DROP TABLE dbo.Users;
*/
Run Code Online (Sandbox Code Playgroud)
但是,我建议不要从用户表中删除行,而是建议更新位列以指示用户已被删除。这允许用户的历史记录,以及这些用户在 Tasks 表中采取的操作。例如:
CREATE TABLE dbo.Users
(
UserID INT NOT NULL CONSTRAINT PK_Users
PRIMARY KEY CLUSTERED
, ApplicationID INT NOT NULL
, Country VARCHAR(255) NOT NULL
, DefaultTenantID INT NOT NULL
, IsDeleted BIT NOT NULL /* Default this to false */
CONSTRAINT DF_Users_IsDeleted DEFAULT ((0))
);
CREATE TABLE dbo.Tasks
(
TaskID INT NOT NULL
, TenantID INT NOT NULL
, CreatedBy_UserID INT NULL
CONSTRAINT FK_Tasks_CreatedBy
FOREIGN KEY REFERENCES dbo.Users(UserID)
, ModifiedBy_UserID INT NULL
CONSTRAINT FK_Tasks_ModifiedBy
FOREIGN KEY REFERENCES dbo.Users(UserID)
, AssignedTo_UserID INT NULL
CONSTRAINT FK_Tasks_AssignedTo
FOREIGN KEY REFERENCES dbo.Users(UserID)
);
/* Note we are not specifying the state of the IsDeleted column here
since it defaults to zero, which indicates they are active
*/
INSERT INTO dbo.Users (UserID, ApplicationID, Country, DefaultTenantID)
VALUES (1, 1, 'CA', 1);
INSERT INTO dbo.Tasks (TaskID, TenantID, CreatedBy_UserID, ModifiedBy_UserID, AssignedTo_UserID)
VALUES (1, 1, 1, NULL, NULL);
/* This is how we "delete" a user */
UPDATE dbo.Users
SET IsDeleted = 1
WHERE UserID = 1;
/* Any queries that access the Tasks table now need to be cognizant
of the state of the user (deleted or not)
*/
SELECT T.*
FROM dbo.Tasks T
INNER JOIN dbo.Users U ON T.CreatedBy_UserID = U.UserID
WHERE U.IsDeleted = 0;
Run Code Online (Sandbox Code Playgroud)