Sql 触发器:插入前
如何检查表中插入或更新的日期是否在另一个表的两个其他日期之间 附加信息: 我有两张桌子: 活动: 起始日期不为空 可为空的结束日期 亚活性: 子活动日期不为空 当EndDate不为空时,我检查是否为:StartDate≤ 亚活性酸≤ 结束日期 当EndDate为空时,我检查是否为:StartDate≤ 亚活性酸 我试图写一个BEFORE-INSERT触发器,但我发现它并不存在 那我能做什么呢 插入后? 而不是插入?看起来比第一个解决方案好 是否可以仅使用检查约束? 我如何解决这个问题 编辑 我刚刚使用了CHECK constraint+函数: 约束条件: 功能:Sql 触发器:插入前,sql,sql-server,function,tsql,constraints,Sql,Sql Server,Function,Tsql,Constraints,如何检查表中插入或更新的日期是否在另一个表的两个其他日期之间 附加信息: 我有两张桌子: 活动: 起始日期不为空 可为空的结束日期 亚活性: 子活动日期不为空 当EndDate不为空时,我检查是否为:StartDate≤ 亚活性酸≤ 结束日期 当EndDate为空时,我检查是否为:StartDate≤ 亚活性酸 我试图写一个BEFORE-INSERT触发器,但我发现它并不存在 那我能做什么呢 插入后? 而不是插入?看起来比第一个解决方案好 是否可以仅使用检查约束? 我如何解决这个问题 编辑
最好的是一个接一个的情况。约束保证正确的值,但将整个事务回滚到一个错误的值上。触发器允许您进行更多的控制,但也因此变得更加复杂 创建并填充表 约束方法: 触发器方法我的首选方法 约束条件: 功能:
“插入”和“删除”是表,因此它们可以表示集合操作的结果。假设他们总是只处理一行,设计触发器通常是一个糟糕的计划。如果您绝对确定不会有超过一行,那么请添加对行数的检查,并使用RaIsError或Throw显式通知稍后出现的人,他们试图执行不可接受的语句。如果选择Count*from inserted>1,则会出现错误“FooTable_Insert:最多只能处理一行”。、25、42使用登录名而不是更新,则插入和删除的可能会有多个结果,对吗?但是在一个代替插入的例子中,插入的allways只有一行,对吗?感谢您提供了这么多行验证代码。另一个问题:在代替更新中,我如何检查PK是否正在更新它。如果我能检查它,我肯定只会有1行。这是对行数的唯一保证:INSERT语句不会导致deleted被填充,DELETE语句会使inserted为空。否则,表可能包含多行。您可以使用检查PK或任何其他列是否正在更新。请注意,返回的值仅取决于对列的赋值,实际值可能没有更改。请告诉我,更新PK对你意味着什么?我没说我想更新PK。我想说的是,我想确保PK正在更新表。e、 g更新子活动集子活动日期='2015-10-10',其中子活动ID=10;其中SubActivityID是SubActivity表的主键,您可以确保插入的所有行恰好具有相同的列值,例如SubActivityID。这可能只是巧合,您无法确定,因为您没有访问触发器中的触发语句。1活动有许多子活动。是否可以约束来自其他表的检查值?在INSTEAD OF UPDATE触发器中,如何检查表是否由PK更新?如果用户试图通过另一个字段进行更新,我想引发一个错误。谢谢。看看这些,就知道PK是否正在用触发器更新表,我不知道如何检查。我不知道这是否可能。你应该有一些标准的方式来更新它,所以我想你会想使用一个存储过程。谢谢你的链接。我想它解决了我的问题。
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
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;
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
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