触发器:插入之前

Trigger: BEFORE INSERT

如何检查 DATEtable 中的 insertedupdated 是否介于另一个 table 的 two other dates 之间。

附加信息: 我有 2 tables:

Activity:

SubActivity:

When EndDate IS NOT NULL I check if: StartDateSubActivityDateEndDate

When EndDate IS NULL I check if: StartDateSubActivityDate

我试图编写一个 BEFORE INSERT 触发器,但我发现它不存在。

那我能做什么?

  1. 插入后?
  2. 代替插入?看起来比第一个解决方案更好
  3. 仅使用 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