Rub*_*uck 11 trigger database-design sql-server t-sql
我在设计时态数据库时遇到问题。我需要知道如何确保在商店的任何给定时间范围内我只有一个活动记录。我已经阅读了这个答案,但恐怕我无法理解触发器的工作原理。特别是,我如何将触发器工作到我现有的触发器中,以防止更新记录,而是插入新记录。我真正的问题是,当完成日期为空时,我不知道如何防止 Store 有多个生效日期。(即防止商店的 2 个活动记录)。
这就是我所拥有的,但它允许我为具有不同生效日期的商店插入新记录。
表定义:
/****** Object: Table [PCR].[Z_STORE_TEAM] Script Date: 05/09/2014 13:05:57 ******/
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Z_STORE_TEAM]') AND type in (N'U'))
DROP TABLE [Z_STORE_TEAM]
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Z_STORE_TEAM]') AND type in (N'U'))
BEGIN
CREATE TABLE [Z_STORE_TEAM](
[STORENUM] [int] NOT NULL,
[TEAM] [varchar](10) NULL,
[EFFECTIVE] [date] NOT NULL,
[FINISHED] [date] NULL,
PRIMARY KEY CLUSTERED
(
[STORENUM] ASC,
[EFFECTIVE] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
END
GO
Run Code Online (Sandbox Code Playgroud)
样本数据:
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (1, N'1', CAST(0x01380B00 AS Date), CAST(0x81380B00 AS Date))
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (1, N'2', CAST(0x81380B00 AS Date), NULL)
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (2, N'1', CAST(0x01380B00 AS Date), NULL)
INSERT [Z_STORE_TEAM] ([STORENUM], [TEAM], [EFFECTIVE], [FINISHED]) VALUES (2, N'2', CAST(0x20380B00 AS Date), NULL)
Run Code Online (Sandbox Code Playgroud)
而不是更新触发器:
CREATE TRIGGER [tr_ZStoreTeam_update]
ON [Z_STORE_TEAM]
INSTEAD OF UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
INSERT INTO PCR.Z_STORE_TEAM(STORENUM,TEAM,EFFECTIVE)
SELECT I.STORENUM,I.TEAM,GETDATE() AS EFFECTIVE
FROM inserted I
INNER JOIN PCR.Z_STORE_TEAM ST
ON I.STORENUM = ST.STORENUM
UPDATE ST
SET FINISHED = GETDATE()
FROM PCR.Z_STORE_TEAM ST
INNER JOIN inserted I
ON ST.STORENUM = I.STORENUM
AND ST.EFFECTIVE = I.EFFECTIVE
END
GO
Run Code Online (Sandbox Code Playgroud)
Pau*_*ite 14
执行此操作的最安全方法是使用内置参照完整性约束来强制执行您的业务规则,正如 Alexander Kuznetsov 在他的文章“无重叠存储时间间隔”中所述。
将此处列出的技术应用于示例表会产生以下脚本:
CREATE TABLE [Z_STORE_TEAM](
[STORENUM] [int] NOT NULL,
[TEAM] [varchar](10) NULL,
[EFFECTIVE] [date] NOT NULL,
[FINISHED] [date] NULL,
PRIMARY KEY CLUSTERED
(
[STORENUM] ASC,
[EFFECTIVE] ASC
)
) ON [PRIMARY];
INSERT [Z_STORE_TEAM]
([STORENUM], [TEAM], [EFFECTIVE], [FINISHED])
VALUES
(1, N'1', CAST(0x01380B00 AS Date), CAST(0x81380B00 AS Date)),
(1, N'2', CAST(0x81380B00 AS Date), NULL),
(2, N'1', CAST(0x01380B00 AS Date), NULL);
Run Code Online (Sandbox Code Playgroud)
修改:
-- New column to hold the previous finish date
ALTER TABLE dbo.Z_STORE_TEAM
ADD PreviousFinished date NULL;
GO
-- Populate the previous finish date
UPDATE This
SET PreviousFinished = Previous.FINISHED
FROM dbo.Z_STORE_TEAM AS This
CROSS APPLY
(
SELECT TOP (1)
Previous.FINISHED
FROM dbo.Z_STORE_TEAM AS Previous
WHERE
Previous.STORENUM = This.STORENUM
AND Previous.FINISHED <= This.EFFECTIVE
ORDER BY
Previous.FINISHED DESC
) AS Previous;
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT UQ_STORENUM_PreviousFinished
UNIQUE (STORENUM, PreviousFinished);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT CK_PreviousFinished_NotAfter_Effective
CHECK (PreviousFinished = EFFECTIVE);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT UQ_STORENUM_FINISHED
UNIQUE (STORENUM, FINISHED);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT FK_STORENUM_PreviousFinished
FOREIGN KEY (STORENUM, PreviousFinished)
REFERENCES dbo.Z_STORE_TEAM (STORENUM, FINISHED);
GO
ALTER TABLE dbo.Z_STORE_TEAM
ADD CONSTRAINT CK_EFFECTIVE_Before_FINISHED
CHECK (EFFECTIVE < FINISHED);
Run Code Online (Sandbox Code Playgroud)
尝试插入第四行样本数据现在失败并显示错误消息:
INSERT [Z_STORE_TEAM]
([STORENUM], [TEAM], [EFFECTIVE], [FINISHED])
VALUES
(2, N'2', '20140201', NULL);
Run Code Online (Sandbox Code Playgroud)

请阅读 Alex 的文章以了解这些约束如何确保您的表数据始终有效。拥有一组约束来强制您的数据完整性意味着不需要触发代码。
同一作者的相关文章:
| 归档时间: |
|
| 查看次数: |
1400 次 |
| 最近记录: |