触发:在插入之前

时间:2015-03-31 23:37:45

标签: sql sql-server function tsql constraints

如何检查DATEinserted updatedtable是否介于另一个表的two other dates之间。

网络信息 我有2 tables

Activity:     

            
  • StartDate日期非空
  •         
  • EndDate日期 NULLABLE
  •     

SubActivity:     

            
  • SubActivityDate日期非空
  •     

  

EndDate IS NOT NULL时检查:StartDate是否SubActivityDateEndDate

     

EndDate IS NULL时,我会检查:StartDate是否为SubActivityDate

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

那么我能做什么?

  1. 插入后?
  2. INSERT IN INSE?看起来比第一个解决方案更好
  3. 是否可以使用CHECK约束?
  4. 如何解决这个问题?

    修改

    我刚接受 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
    

2 个答案:

答案 0 :(得分:0)

最好的情况是情况。约束保证正确的值,但在一个错误的值上回滚整个事务。触发器允许您进行更多控制,但由于它更复杂。

创建并填充表

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

此方法允许使用正确的值,并为不正确的值返回null。如果需要,您甚至可以将插入表中的错误值导出到日志表中,以便了解哪些不起作用。或者引发错误消息并列出不起作用的值。简而言之,您完全可以控制局势。

结果:

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

答案 1 :(得分:0)

<强>约束:

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