插入时的SQL触发器,用于调用函数和操作值

插入时的SQL触发器,用于调用函数和操作值,sql,sql-server,Sql,Sql Server,我在知道如何在insert上设置触发器来调用函数并将标识符SiteID传递给该函数时遇到问题,该函数随后会对另一个表中的变量进行操作 我有一个表,其中插入了值: CREATE TABLE [dbo].[Tests] ( [Id] INT IDENTITY (1, 1) NOT NULL, [SiteID] NVARCHAR (128) NOT NULL, [Date] NVARCHAR (MAX) NULL, [Time] NVARCHAR (

我在知道如何在insert上设置触发器来调用函数并将标识符SiteID传递给该函数时遇到问题,该函数随后会对另一个表中的变量进行操作

我有一个表,其中插入了值:

CREATE TABLE [dbo].[Tests] (
   [Id]     INT       IDENTITY (1, 1) NOT NULL,
   [SiteID] NVARCHAR (128) NOT NULL,
   [Date]   NVARCHAR (MAX) NULL,
   [Time]   NVARCHAR (MAX) NULL,
   [Tub]    NVARCHAR (MAX) NULL,
   [FCl]    FLOAT (53)     NOT NULL
   PRIMARY KEY CLUSTERED ([Id] ASC)
);
每次在测试表中插入一个值时,我都希望调用一个函数,该函数使用表回顾来执行一个简单的计算,请参见下面的文章中的触发器:

CREATE TABLE [dbo].[Review] (
   [SiteID] NVARCHAR (128) NOT NULL,
   [TubNum] INT NOT NULL,
   [Supplied]  INT  NULL,
   [Performed] INT  NULL,
   [Remaining] INT  NULL 
   PRIMARY KEY CLUSTERED ([SiteID] ASC)
);
到目前为止,这是我的,但是,我无法将其与我正在使用的函数一起保存,这些函数如下:

触发器-不确定如何传递插入或调用函数的SiteID:

CREATE TRIGGER [dbo].[TRIG_MyTable]
ON [dbo].[Tests]
AFTER INSERT
 AS
   CALL CalcRemaining() //how to pass it SiteID?
以及功能本身:

CREATE FUNCTION [dbo].[CalcRemaining](@ID NVARCHAR (128))
RETURNS NULL
AS
BEGIN
   SELECT (Supplied, Performed FROM Review WHERE SiteID = ID);
   Performed = Performed + 1;
   INSERT INTO Review (Performed, Remaining) VALUES (Performed, (Supplied-Performed))
RETURN;
END

其思想是,调用时将插入行中的SiteID传递给函数,然后该函数从审阅表中选择为该匹配SiteID提供和执行的值。执行的值增加1,新值与检索到的提供值一起减去,并写入审阅表中的剩余字段。

您必须完全确保一次只操作一行

CREATE TRIGGER [dbo].[TRIG_MyTable]
ON [dbo].[Tests]
AFTER INSERT
 AS
DECLARE @SiteID NVARCHAR (128)
SELECT @SiteID = ID FROM inserted
   CALL CalcRemaining(@SiteID)

如果我在评论中询问的假设是有效的,即剩余的和执行的数据总是可以计算的,那么我将如何实现您的数据库结构,而不使用触发器或函数:

CREATE TRIGGER [dbo].[TRIG_MyTable]
ON [dbo].[Tests]
AFTER INSERT
 AS
   CALL CalcRemaining() //how to pass it SiteID?
基表:

CREATE TABLE dbo.Tests (
   [Id]     INT       IDENTITY (1, 1) NOT NULL,
   [SiteID] NVARCHAR (128) NOT NULL,
   [Date]   NVARCHAR (MAX) NULL,
   [Time]   NVARCHAR (MAX) NULL,
   [Tub]    NVARCHAR (MAX) NULL,
   [FCl]    FLOAT (53)     NOT NULL
   PRIMARY KEY CLUSTERED ([Id] ASC)
);
GO
CREATE TABLE dbo._Review (
   [SiteID] NVARCHAR (128) NOT NULL,
   [TubNum] INT NOT NULL,
   [Supplied]  INT  NULL,
   PRIMARY KEY CLUSTERED ([SiteID] ASC)
);
然后,将显示一个用于计算以下内容的视图:

最后是重新创建原始审阅表的视图:


如果需要,此时可以在此审阅视图上创建一个触发器,以允许对其执行任何插入、删除和更新,而不是在无法更改某些调用代码的情况下执行_Review。

您可以尝试该方法,并将其从插入的i传递给方法CalcRemainingSELECT i.[SiteID];为什么要使用NVARCHARMAX存储日期和时间?SQL Server对日期/时间类型有很好的支持。我不知道SQL Server允许函数修改数据库中的其他表。使用该函数计算该值。使用触发器将值插入审阅表。是否应始终提供剩余值-执行?如果是这样,计算列在这里会做得更好。是否始终对给定SiteID的测试行数进行计数?如果是这样,将指示计算此值的视图。总之,这些都可以完全消除对触发器/功能的需求。简言之,不要手动计算可以轻松重新计算的数据。@Damien_不信者-为延迟道歉。是的,你的假设是正确的,这是一个更整洁的方法。你的评论表明你知道这不是一个很好的答案。触发器必须能够处理多行操作,否则它的实现很差。@SeanLange是的,我知道,但我不知道哪个是框架,所以我建议了一个快速解决方案来解决他的问题,当且仅当他一次只有一行具有正确的边条件时,只有一行操作的条件永远不会为真。即使这在今天是真的,也没有任何东西可以阻止将来的应用程序或系统更改,从而破坏这种类型的触发器。我知道至少有一家公司实际上倒闭了,因为他们的触发器没有处理多行操作,一个主要的系统发生了变化,暴露了这个问题,而解决这个问题是他们无法完成的一项重大任务。是的,如果它出现在我的代码审查中,这将是一个瞬间的失败。如果在开始时有一条很长的注释解释了为什么它不能支持多行插入,并且如果它遇到多行插入而不是无提示地失败,那么它可能会被接受。但如果我不想花时间去做,那就不是了work@Damien_The_Unbeliever你说得对,我可以管理多行插入。唯一不正确的是原因是:不幸的是,我没有时间深入解释,因为我还有点忙其他任务。也许最好不要回答,而不是给出一个需要更多理解的答案。我不是讽刺,我曾尝试在sqlfiddle中生成这个,但我在创建唯一聚集索引IX_Tests_Count on dbo时遇到了语法错误。谢谢这个解决方案非常有效。我不完全理解语法,但这是我的家庭作业,至少我可以从中学习到一个解决方案:-
CREATE VIEW dbo.Review
WITH SCHEMABINDING
AS
    SELECT
        r.SiteID,
        r.TubNum,
        r.Supplied,
        COALESCE(tc.Performed,0) as Performed,
        r.Supplied - COALESCE(tc.Performed,0) as Remaining
    FROM
        dbo._Review r
            left join
        dbo._Tests_Count tc WITH (NOEXPAND)
            on
                r.SiteID = tc.SiteID
GO