【问题标题】:Incorrect Syntax in Trigger creation触发器创建中的语法不正确
【发布时间】:2019-09-20 05:19:53
【问题描述】:

我正在尝试在数据库中的一个表上创建触发器,如下所示

CREATE TRIGGER tr_JTIA_ForInsert
ON MyTable
FOR INSERT 
AS
BEGIN
    DECLARE @JTIItemID INT,
            @UserWWID INT

    IF EXISTS (SELECT * 
               FROM [MyTable] JTIA 
               INNER JOIN inserted NewItem ON NewItem.ItemID = JTIA.ItemID 
                                           AND NewItem.UserWWID = JTIA.UserWWID 
                                           AND NewItem.Status = JTIA.Status)
    BEGIN
        SELECT 
            @JTIItemID = inserted.ItemID, 
            @UserWWID = inserted.UserWWID 
        FROM
            inserted

        EXEC msdb.dbo.sp_send_dbmail
              @recipients = 'edwin@gmail.com', 
              @profile_name = 'App Administrator',
              @body = SELECT CONCAT('User : ',(SELECT CONVERT(varchar(20),12345)), ' was assigned a duplicate JTIItemID: ', (SELECT CONVERT(varchar(20),1234567)), ' at timestamp: ', (select convert(varchar, getdate(), 22))),
              @subject = 'Duplicate record Was Assigned to user:'; 
    END
END

当我执行上述触发器时,我在创建时收到以下错误消息。

消息 156,级别 15,状态 1,过程 tr_JTIA_ForInsert,第 16 行 [批处理开始第 0 行]
关键字“SELECT”附近的语法不正确。

消息 137,级别 15,状态 1,过程 tr_JTIA_ForInsert,第 17 行 [批处理开始第 0 行]
必须声明标量变量“@subject”。

不知道我错过了什么

【问题讨论】:

  • 您需要在调用EXEC msdb.dbo.sp_send_dbmail之前构建您的电子邮件消息的@body。在调用这个系统存储过程时,你应该只使用字符串文字和字符串变量——没有复杂的SELECT和其他逻辑来创建结果stirng
  • 另外:您的触发器有 MAJOR 缺陷,您似乎认为它会被调用 每行一次 - 事实并非如此。触发器将每条语句触发一次,因此如果您的INSERT 导致此触发器触发插入 25 行,您将触发触发器一次和@987654326 @ 伪表将包含 25 行。您的代码将从Inserted 中选择这 25 行中的哪一行?它是不确定的,您将获得任意行,而您将忽略所有其他行。您需要重写触发器以考虑到这一点!

标签: sql-server tsql database-trigger


【解决方案1】:

这是您需要的粗略修改示例。我没有桌子,所以我无法测试它,但我怀疑它非常接近。

CREATE TRIGGER tr_JTIA_ForInsert
ON dbo.MyTable
AFTER INSERT 
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    DECLARE @JTIItemID int;
    DECLARE @UserWWID int;
    DECLARE @EmailBody nvarchar(max);

    DECLARE @EmailsToSend TABLE
    (
        EmailsToSendID int NOT NULL IDENTITY(1,1) PRIMARY KEY,
        JTIItemID int,
        UserWWID int
    );

    INSERT @EmailsToSend (JTIItemID, UserWWID)
    SELECT i.JTIItemID, i.UserWWID
    FROM inserted AS i
    INNER JOIN dbo.MyTable AS mt
    ON mt.ItemID = i.ItemID 
    AND mt.UserWWID = i.UserWWID
    AND mt.[Status] = i.[Status];

    DECLARE @Counter int = 1;
    WHILE @Counter <= (SELECT MAX(EmailsToSendID) FROM @EmailsToSend)
    BEGIN
        SELECT @JTIItemID = ets.JTIItemID,
               @UserWWID = ets.UserWWID
        FROM @EmailsToSend AS ets
        WHERE ets.EmailsToSendID = @Counter;

        SET @EmailBody = CONCAT(N'User : ',
                                (SELECT CONVERT(varchar(20),12345)), 
                                N' was assigned a duplicate JTIItemID: ', 
                                (SELECT CONVERT(varchar(20),1234567)), 
                                N' at timestamp: ', 
                                (SELECT convert(varchar, GETDATE(), 22)));

        EXEC msdb.dbo.sp_send_dbmail
              @recipients = N'edwin@gmail.com', 
              @profile_name = N'App Administrator',
              @body = @EmailBody,
              @subject = N'Duplicate record Was Assigned to user:'; 
        SET @Counter += 1;
    END;
END;
GO

希望对你有所帮助。

【讨论】:

  • 只使用一个游标——while循环并没有更好,应用将一堆行转储到临时表/表变量然后从中选择的典型无意义模式没有任何优势跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多