触发器:插入之前
Trigger: BEFORE INSERT
如何检查 DATE
在 table
中的 inserted
或 updated
是否介于另一个 table 的 two other dates
之间。
附加信息:
我有 2 tables
:
Activity
:
-
StartDate
日期 NOT NULL
-
EndDate
日期 NULLABLE
SubActivity
:
-
SubActivityDate
日期 NOT NULL
When EndDate IS NOT NULL
I check if: StartDate
≤ SubActivityDate
≤ EndDate
When EndDate IS NULL
I check if: StartDate
≤ SubActivityDate
我试图编写一个 BEFORE INSERT 触发器,但我发现它不存在。
那我能做什么?
- 插入后?
- 代替插入?看起来比第一个解决方案更好
- 仅使用 CHECK 约束是否可行?
如何解决这个问题?
编辑
我刚刚使用 CHECK 约束 + 函数:
约束条件:
ALTER TABLE SubActivity
ADD CONSTRAINT CK_SubActivity_Date CHECK (dbo.ufnIsSubactivityDateValid(ActivityID, SubActivityDate) = 1);
函数:
CREATE FUNCTION ufnIsSubactivityDateValid(@ActivityID [int], @SubActivityDate [date])
RETURNS [bit]
AS
BEGIN
DECLARE @StartDate date, @EndDate date;
SELECT @StartDate = StartDate , @EndDate = EndDate
FROM Activity
WHERE ActivityID = @ActivityID;
IF (@SubActivityDate < @StartDate )
RETURN 0; -- out of range date
IF (@EndDate IS NULL)
RETURN 1; -- good date
ELSE
IF (@SubActivityDate > @EndDate)
RETURN 0; -- out of range date
RETURN 1; -- good date
END
最好是视情况而定。约束保证正确的值但回滚整个交易一个错误的值。触发器允许您进行更多控制,但也因此变得更加复杂。
创建并填充您的 Table
IF OBJECT_ID('dbo.yourTable') IS NOT NULL
DROP TABLE yourTable;
CREATE TABLE yourTable
(
ID INT IDENTITY(1,1) PRIMARY KEY,
StartDate DATE NOT NULL,
SubActivityDate DATE NULL,
EndDate DATE NULL
);
INSERT INTO yourTable(StartDate,SubActivityDate,EndDate)
VALUES ('20150101',NULL,NULL),
('20150101',NULL,NULL),
('20150101',NULL,'20150201'),
('20150101',NULL,'20150201');
约束方法:
ALTER TABLE yourTable
ADD CONSTRAINT chk_date CHECK (StartDate <= SubActivityDate AND SubActivityDate <= EndDate);
UPDATE yourTable
SET SubActivityDate = CASE
WHEN ID = 1 THEN '20140101' --bad
WHEN ID = 2 THEN '20150102' --good
WHEN ID = 3 THEN '20140101' --bad
WHEN ID = 4 THEN '20150102' --good
END
SELECT *
FROM yourTable;
由于至少有一个值不符合约束条件,整个事务被回滚,结果SubActivitDate保持为NULL。
结果:
ID StartDate SubActivityDate EndDate
----------- ---------- --------------- ----------
1 2015-01-01 NULL NULL
2 2015-01-01 NULL NULL
3 2015-01-01 NULL 2015-02-01
4 2015-01-01 NULL 2015-02-01
触发方法(我的首选方法)
CREATE TRIGGER trg_check_date ON yourTable
INSTEAD OF UPDATE
AS
BEGIN
UPDATE yourTable
SET SubActivityDate = CASE
WHEN inserted.SubActivityDate >= inserted.StartDate AND ((Inserted.EndDate IS NULL) OR Inserted.SubActivityDate <= Inserted.EndDate) THEN inserted.SubActivityDate
ELSE NULL
END
FROM yourTable
INNER JOIN inserted
ON yourTable.ID = inserted.ID
END;
GO
UPDATE yourTable
SET SubActivityDate = CASE
WHEN ID = 1 THEN '20140101' --bad
WHEN ID = 2 THEN '20150102' --good
WHEN ID = 3 THEN '20140101' --bad
WHEN ID = 4 THEN '20150102' --good
END
SELECT *
FROM yourTable
此方法允许正确的值,而对于不正确的值则简单地 returns null。如果需要,您甚至可以将插入的 table 中的不正确值导出到日志 table 中,这样您就可以知道哪些无效。或者发出错误消息并列出不起作用的值。简而言之,您可以完全控制局势。
结果:
ID StartDate SubActivityDate EndDate
----------- ---------- --------------- ----------
1 2015-01-01 NULL NULL
2 2015-01-01 2015-01-02 NULL
3 2015-01-01 NULL 2015-02-01
4 2015-01-01 2015-01-02 2015-02-01
约束条件:
ALTER TABLE SubActivity
ADD CONSTRAINT CK_SubActivity_Date CHECK (dbo.ufnIsSubactivityDateValid(ActivityID, SubActivityDate) = 1);
函数:
CREATE FUNCTION ufnIsSubactivityDateValid(@ActivityID [int], @SubActivityDate [date])
RETURNS [bit]
AS
BEGIN
DECLARE @StartDate date, @EndDate date;
SELECT @StartDate = StartDate , @EndDate = EndDate
FROM Activity
WHERE ActivityID = @ActivityID;
IF (@SubActivityDate < @StartDate )
RETURN 0; -- out of range date
IF (@EndDate IS NULL)
RETURN 1; -- good date
ELSE
IF (@SubActivityDate > @EndDate)
RETURN 0; -- out of range date
RETURN 1; -- good date
END
如何检查 DATE
在 table
中的 inserted
或 updated
是否介于另一个 table 的 two other dates
之间。
附加信息:
我有 2 tables
:
Activity
:
-
StartDate
日期 NOT NULL -
EndDate
日期 NULLABLE
SubActivity
:
-
SubActivityDate
日期 NOT NULL
When
EndDate IS NOT NULL
I check if:StartDate
≤SubActivityDate
≤EndDate
When
EndDate IS NULL
I check if:StartDate
≤SubActivityDate
我试图编写一个 BEFORE INSERT 触发器,但我发现它不存在。
那我能做什么?
- 插入后?
- 代替插入?看起来比第一个解决方案更好
- 仅使用 CHECK 约束是否可行?
如何解决这个问题?
编辑
我刚刚使用 CHECK 约束 + 函数:
约束条件:
ALTER TABLE SubActivity
ADD CONSTRAINT CK_SubActivity_Date CHECK (dbo.ufnIsSubactivityDateValid(ActivityID, SubActivityDate) = 1);
函数:
CREATE FUNCTION ufnIsSubactivityDateValid(@ActivityID [int], @SubActivityDate [date])
RETURNS [bit]
AS
BEGIN
DECLARE @StartDate date, @EndDate date;
SELECT @StartDate = StartDate , @EndDate = EndDate
FROM Activity
WHERE ActivityID = @ActivityID;
IF (@SubActivityDate < @StartDate )
RETURN 0; -- out of range date
IF (@EndDate IS NULL)
RETURN 1; -- good date
ELSE
IF (@SubActivityDate > @EndDate)
RETURN 0; -- out of range date
RETURN 1; -- good date
END
最好是视情况而定。约束保证正确的值但回滚整个交易一个错误的值。触发器允许您进行更多控制,但也因此变得更加复杂。
创建并填充您的 Table
IF OBJECT_ID('dbo.yourTable') IS NOT NULL
DROP TABLE yourTable;
CREATE TABLE yourTable
(
ID INT IDENTITY(1,1) PRIMARY KEY,
StartDate DATE NOT NULL,
SubActivityDate DATE NULL,
EndDate DATE NULL
);
INSERT INTO yourTable(StartDate,SubActivityDate,EndDate)
VALUES ('20150101',NULL,NULL),
('20150101',NULL,NULL),
('20150101',NULL,'20150201'),
('20150101',NULL,'20150201');
约束方法:
ALTER TABLE yourTable
ADD CONSTRAINT chk_date CHECK (StartDate <= SubActivityDate AND SubActivityDate <= EndDate);
UPDATE yourTable
SET SubActivityDate = CASE
WHEN ID = 1 THEN '20140101' --bad
WHEN ID = 2 THEN '20150102' --good
WHEN ID = 3 THEN '20140101' --bad
WHEN ID = 4 THEN '20150102' --good
END
SELECT *
FROM yourTable;
由于至少有一个值不符合约束条件,整个事务被回滚,结果SubActivitDate保持为NULL。
结果:
ID StartDate SubActivityDate EndDate
----------- ---------- --------------- ----------
1 2015-01-01 NULL NULL
2 2015-01-01 NULL NULL
3 2015-01-01 NULL 2015-02-01
4 2015-01-01 NULL 2015-02-01
触发方法(我的首选方法)
CREATE TRIGGER trg_check_date ON yourTable
INSTEAD OF UPDATE
AS
BEGIN
UPDATE yourTable
SET SubActivityDate = CASE
WHEN inserted.SubActivityDate >= inserted.StartDate AND ((Inserted.EndDate IS NULL) OR Inserted.SubActivityDate <= Inserted.EndDate) THEN inserted.SubActivityDate
ELSE NULL
END
FROM yourTable
INNER JOIN inserted
ON yourTable.ID = inserted.ID
END;
GO
UPDATE yourTable
SET SubActivityDate = CASE
WHEN ID = 1 THEN '20140101' --bad
WHEN ID = 2 THEN '20150102' --good
WHEN ID = 3 THEN '20140101' --bad
WHEN ID = 4 THEN '20150102' --good
END
SELECT *
FROM yourTable
此方法允许正确的值,而对于不正确的值则简单地 returns null。如果需要,您甚至可以将插入的 table 中的不正确值导出到日志 table 中,这样您就可以知道哪些无效。或者发出错误消息并列出不起作用的值。简而言之,您可以完全控制局势。
结果:
ID StartDate SubActivityDate EndDate
----------- ---------- --------------- ----------
1 2015-01-01 NULL NULL
2 2015-01-01 2015-01-02 NULL
3 2015-01-01 NULL 2015-02-01
4 2015-01-01 2015-01-02 2015-02-01
约束条件:
ALTER TABLE SubActivity
ADD CONSTRAINT CK_SubActivity_Date CHECK (dbo.ufnIsSubactivityDateValid(ActivityID, SubActivityDate) = 1);
函数:
CREATE FUNCTION ufnIsSubactivityDateValid(@ActivityID [int], @SubActivityDate [date])
RETURNS [bit]
AS
BEGIN
DECLARE @StartDate date, @EndDate date;
SELECT @StartDate = StartDate , @EndDate = EndDate
FROM Activity
WHERE ActivityID = @ActivityID;
IF (@SubActivityDate < @StartDate )
RETURN 0; -- out of range date
IF (@EndDate IS NULL)
RETURN 1; -- good date
ELSE
IF (@SubActivityDate > @EndDate)
RETURN 0; -- out of range date
RETURN 1; -- good date
END