Sql server 基于表上两列的SQL Server触发器

Sql server 基于表上两列的SQL Server触发器,sql-server,triggers,Sql Server,Triggers,我有一个包含大量列的表stockm,但我的触发器仅基于其中两个列 我想要一个触发器,当列hold\u flag中的值要用y或y更新或插入时发送电子邮件,但仅当列warehouse中的值为KW时才触发 让我知道我错在哪里 我在表上没有提到主键 CREATE TRIGGER [dbo].[trgStockHold] ON [dbo].[stockm] AFTER UPDATE, INSERT AS BEGIN DECLARE @inserted_held_flag nvarchar(25

我有一个包含大量列的表
stockm
,但我的触发器仅基于其中两个列

我想要一个触发器,当列
hold\u flag
中的值要用
y
y
更新或插入时发送电子邮件,但仅当列
warehouse
中的值为
KW
时才触发

让我知道我错在哪里

我在表上没有提到主键

CREATE TRIGGER [dbo].[trgStockHold]
ON [dbo].[stockm]
AFTER  UPDATE, INSERT
AS 
BEGIN
    DECLARE @inserted_held_flag nvarchar(255)
    DECLARE @inserted_rowstamp nvarchar(255)

    SELECT TOP 1 
        @inserted_held_flag = held_flag, 
        @inserted_rowstamp = rowstamp
    FROM 
        inserted 

    IF (@inserted_held_flag in ('Y','y'))
    BEGIN
        IF EXISTS (SELECT TOP 1 1 
                   FROM dbo.stockm 
                   WHERE rowstamp = @inserted_rowstamp AND warehouse = 'KW')
        BEGIN
            EXEC msdb.dbo.sp_send_dbmail 
                        @profile_name = '', 
                        @recipients = '' , 
                        @body = '',
                        @subject = ' ' 
        END
END

所以让我们后退一步想想这个方法。首先,触发器在事务中运行。该事务可能不会提交,这意味着插入的任何行实际上都不会永久保存在数据库中。因此,从触发器发送电子邮件的想法是一个有问题的操作,因为该电子邮件可能引用实际不存在的信息

其次,交易应该是快速的。您不应该执行可能需要大量时间的逻辑。发送电子邮件通常不需要太多时间,但当您的电子邮件服务器不工作时会发生什么?您的OLTP系统只是停止工作吗?这在您的系统中是可接受的风险吗

最后,触发器以语句为基础进行操作。如果一条语句影响2000行,则虚拟插入/删除表中将出现2000行(取决于操作)。要正确写入触发器,您的逻辑必须能够处理任意数量的行—从零(是的,零!)到多行。您假设一行受到影响-这永远不是一个安全的假设。由于这个假设,我还可以猜测您的测试没有涵盖多行实际受到影响的情况。这是你需要改变的——越快越好

如果您想要更好的设计建议,那么您需要提供有关目标和模式的信息。由于表/列不是特别有意义的名称,因此没有人能够真正猜出它们实际上代表什么。您的读者也不知道您正在建模的实际系统,因此无法从您的描述中推断业务功能


还有最后一件事。如果您打算使用tsql发送电子邮件,显然需要向sp_send_dbmail过程提供正确的信息。如果你还不知道怎么做,那么尝试将其放入触发器显然也行不通。将问题分解为可以实现和测试的部分 其次,交易应该是快速的。您不应该执行可能需要大量时间的逻辑。发送电子邮件通常不需要太多时间,但当您的电子邮件服务器不工作时会发生什么?您的OLTP系统只是停止工作吗?这在您的系统中是可接受的风险吗

最后,触发器以语句为基础进行操作。如果一条语句影响2000行,则虚拟插入/删除表中将出现2000行(取决于操作)。要正确写入触发器,您的逻辑必须能够处理任意数量的行—从零(是的,零!)到多行。您假设一行受到影响-这永远不是一个安全的假设。由于这个假设,我还可以猜测您的测试没有涵盖多行实际受到影响的情况。这是你需要改变的——越快越好

如果您想要更好的设计建议,那么您需要提供有关目标和模式的信息。由于表/列不是特别有意义的名称,因此没有人能够真正猜出它们实际上代表什么。您的读者也不知道您正在建模的实际系统,因此无法从您的描述中推断业务功能


还有最后一件事。如果您打算使用tsql发送电子邮件,显然需要向sp_send_dbmail过程提供正确的信息。如果你还不知道怎么做,那么尝试将其放入触发器显然也行不通。将问题分解为可以实现和测试的部分

问题是您的触发器的数据类型有一个主要缺陷,您似乎认为它每行调用一次—事实并非如此。触发器将对每条语句触发一次,因此,如果导致此触发器触发的
INSERT
语句插入了25行,则触发器将触发一次,但是
Inserted
伪表将包含25行。您的
选择前1名。。。从插入的
将获得任意一行,您将忽略所有其他行。你需要重写你的触发器来考虑这一点!问题是:我无法运行它,如果可能的话,我需要有人帮助我做一个更好的。问题是您的触发器的数据类型存在重大缺陷,您似乎认为它每行调用一次-事实并非如此。触发器将对每条语句触发一次,因此,如果导致此触发器触发的
INSERT
语句插入了25行,则触发器将触发一次,但是
Inserted
伪表将包含25行。您的
选择前1名。。。从插入的
将获得任意一行,您将忽略所有其他行。你需要重写你的触发器来考虑这一点!问题是:我不能运行它,如果可能的话,我需要有人帮助我做一个更好的。