当组合列值是唯一外键时,级联删除

时间:2017-11-04 12:17:49

标签: sql-server foreign-keys cascading-deletes

我有以下表格:

[位置]
    id PK
    标题
    说明

[地板]
    id PK
    locationid FK
    floorlevel
    描述

[室]
    id PK
    locationid FK
    floorid FK
    说明

[特征]
    id PK
    标题

[object_features]
    id PK
    featureid FK
    objectid FK(链接到[locations] .id,[floors] .id或[rooms] .id)
    objectype(值1 =位置,2 =楼层,3 =房间)

现在,如果从[位置]删除位置X,我想删除相关的房间和楼层(是的房间也可以直接与位置相关而不是通过楼层),这可以通过级联删除轻松完成。

但是每个不同的对象类型(位置,楼层和房间)也可以有0个或更多个功能,这些功能存储在[object_features]中 这意味着[object_features] .objectid和[object_features] .objecttype可能具有多次相同的值,但与[object_features] .featureid组合时它是唯一的组合。

因此,当删除某个位置时,我还想删除[object_features]中与[locations],[floors]和/或[rooms]中删除的行相关的所有行,因为该位置X被删除。 我觉得我需要在每个表([locations],[floors],[rooms])上添加一些逻辑,以便在删除行时执行操作。我觉得触发器可能会成功,但我不确定这是否是推荐的方法。而且我也不确定如何实现它,一个例子会很棒。

已在此处查看:CASCADE DELETE on two foreign key constraints,但似乎是另一种解决方案。

DDL

CREATE TABLE [dbo].[locations](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [title] [nvarchar](500) NOT NULL,
 CONSTRAINT [PK_homes] PRIMARY KEY NONCLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO



CREATE TABLE [dbo].[location_floors](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [locationid] [int] NOT NULL,
 CONSTRAINT [PK_location_floors] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[location_floors]  WITH CHECK ADD  CONSTRAINT [FK_location_floors_locations] FOREIGN KEY([locationid])
REFERENCES [dbo].[locations] ([id])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[location_floors] CHECK CONSTRAINT [FK_location_floors_locations]
GO


CREATE TABLE [dbo].[location_rooms](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [locationid] [int] NOT NULL,
    [floorid] [int] NULL,
 CONSTRAINT [PK_location_rooms] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[location_rooms]  WITH CHECK ADD  CONSTRAINT [FK_location_rooms_locations] FOREIGN KEY([locationid])
REFERENCES [dbo].[locations] ([id])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[location_rooms] CHECK CONSTRAINT [FK_location_rooms_locations]
GO


CREATE TABLE [dbo].[features](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [title] [nvarchar](50) NOT NULL,
    [createdate] [datetime] NOT NULL,
 CONSTRAINT [PK_voorzieningen] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[features] ADD  CONSTRAINT [DF_voorzieningen_createdate]  DEFAULT (getdate()) FOR [createdate]
GO


CREATE TABLE [dbo].[object_features](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [objectid] [int] NOT NULL,
    [objecttype] [tinyint] NOT NULL,
    [featureid] [int] NOT NULL,
    [createdate] [datetime] NOT NULL,
 CONSTRAINT [PK_location_voorzieningen] PRIMARY KEY CLUSTERED 
(
    [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[object_features] ADD  CONSTRAINT [DF_location_voorzieningen_createdate]  DEFAULT (getdate()) FOR [createdate]
GO

ALTER TABLE [dbo].[object_features]  WITH CHECK ADD  CONSTRAINT [FK_object_features_features] FOREIGN KEY([featureid])
REFERENCES [dbo].[features] ([id])
ON DELETE CASCADE
GO

ALTER TABLE [dbo].[object_features] CHECK CONSTRAINT [FK_object_features_features]
GO

EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'1=location, 2=floor, 3=room' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'object_features', @level2type=N'COLUMN',@level2name=N'objecttype'
GO

1 个答案:

答案 0 :(得分:0)

在由于多个更新路径而不允许DRI的情况下,SQL Server中可以使用INSTEAD OF DELETE触发器执行级联删除。

以下是按正确顺序执行所需删除的示例。只需在需要级联删除的其他表上按照类似的触发模式。

CREATE TRIGGER tr_location_delete
ON dbo.locations
INSTEAD OF DELETE
AS
SET NOCOUNT ON;

--delete rooms for location
DELETE rooms
FROM dbo.rooms
JOIN dbo.floors ON floors.id = rooms.floorid
JOIN deleted ON deleted.id = rooms.floorid;

--delete floors for location
DELETE floors
FROM dbo.floors
JOIN deleted ON deleted.id = floors.locationid;

--delete location
DELETE locations
FROM dbo.locations
JOIN deleted ON deleted.id = locations.id;
GO