【问题标题】:Trigger gives false null values触发器给出错误的空值
【发布时间】:2021-07-06 21:20:44
【问题描述】:

我正在尝试创建一个在插入新行时执行的触发器。 触发器的目标是每次雇主借钱时向表中添加信息。

插入触发器的表:Employer.Loan

ID ToolId CardId Time
1    4     1001    2021-05-08 15:41:47

触发器应该插入信息的表:Employer.LoanStats

CardId Year Month Quantity

例如,我想向 Loan 表添加值:

INSERT INTO Employer.Loan(ToolId,CardId,Time) *ID is automatic
VALUES (3, 1005, GETDATE() - 40, 3, 1005, GETDATE(), (4, 1002, GETDATE())

LoanStats 表中的结果很好:

CardId Year Month Quantity
1005   2021   4      1
1005   2021   3      1
1002   2021   4      1

但是,当我尝试添加更多值时,它会停止工作并给出 NULL 值:

INSERT INTO Employer.Loan(ToolId,CardId,Time) *ID is automatic
VALUES (3, 1005, GETDATE() - 40, (4, 1003, GETDATE())

结果:

CardId Year Month Quantity
---------------------------
1005   2021   4      2
1005   2021   3     NULL
1002   2021   4      1
1003   2021   4     NULL

我尝试了以下方法:

CREATE TRIGGER AddStats
ON Employer.Loan
FOR INSERT
AS
    IF (SELECT COUNT(*) FROM inserted) > 0
    BEGIN
        DECLARE @CardId int,
                @Year int,
                @Month int,
                @Time DATE
 
       DECLARE Updated CURSOR FOR 
            SELECT CardId, Time
            FROM inserted

       OPEN Updated

       FETCH NEXT FROM Updated INTO @CardId, @Time

       WHILE (@@FETCH_STATUS = 0)
       BEGIN
           SET @Year = DATEPART(YEAR, @Time)
           SET @Month = DATEPART(MONTH, @Time)

           IF EXISTS (SELECT * FROM Employer.LoanStats 
                      WHERE CardId = @CardId AND Year = @Year AND Month = @Month)
           BEGIN
               UPDATE Employer.LoanStats
               SET Quantity = (SELECT Employer.LoanStats.Quantity + 1
                               FROM inserted
                               WHERE inserted.CardId = Employer.LoanStats.CardId 
                                 AND Employer.LoanStats.Month = @Month 
                                 AND Employer.LoanStats.Year = @Year)
               WHERE CardId IN (SELECT CardId FROM inserted)
           END
           ELSE
           BEGIN
               INSERT INTO Employer.LoanStats (CardId, Year, Month, Quantity)
               VALUES (@CardId, @Year, @Month, 1)
           END

           FETCH NEXT FROM Updated INTO @CardId, @Time
       END

       CLOSE Updated
       DEALLOCATE Updated
    END

【问题讨论】:

  • 拜托 - 光标在任何地方都不好 - 但在 触发器 中,这可能只是你 WORST 的事情可以做!您应该将触发器重写为正确地基于集合 - 不要使用触发器!很可能,这也可以解决您遇到的问题....
  • 你的触发器只需要一个insertupdate 语句来做你正在做的事情,不需要游标(通常不需要)。因为这将消耗比必要更多的资源,执行插入的事务的所有部分。

标签: sql sql-server tsql triggers


【解决方案1】:

您的UPDATE 语句有缺陷,未正确加入。

尽管如此,整个过程完全是矫枉过正。它可以在单个MERGE 语句中完成:

CREATE TRIGGER AddStats
ON Employer.Loan
AFTER INSERT
AS
    SET NOCOUNT ON;
    IF NOT EXISTS (SELECT 1 FROM inserted)
        RETURN;

    MERGE Employer.LoanStats l
    USING (
        SELECT *,
            Year = DATEPART(YEAR, Time),
            Month = DATEPART(MONTH, Time)
            FROM inserted
    ) i
    ON i.CardId = l.CardId AND i.Year = l.Year AND i.Month = l.Month
    WHEN MATCHED THEN UPDATE SET
        Quantity += 1
    WHEN NOT MATCHED BY TARGET THEN
        INSERT (CardId, Year, Month, Quantity)
        VALUES (i.CardId, i.Year, i.Month, 1);

GO

【讨论】:

    猜你喜欢
    • 2023-03-16
    • 2013-05-13
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    相关资源
    最近更新 更多