【问题标题】:SQL Server Trigger Update and Increment counterSQL Server 触发器更新和增量计数器
【发布时间】:2012-08-27 22:47:25
【问题描述】:

我有两张桌子。一个表有一个字段,用于简单地保存一个计数器,另一个表有许多搜索字段,其中一个字段必须包含另一个表中的计数器值。

我正在尝试创建一个触发器

  1. 当第二个表发生更新时,将第一个表中的值加 1
  2. 第一个表中增加的值将用于设置第二个表中的字段
  3. 1 和 2 仅在第二个表和字段(即状态等于特定值)中发生更新时才会发生。
  4. 为多条记录处理 1,2 和 3。

1) 我已经设法编写了这个触发器,但是 a) 它看起来非常慢 b) 我找到了一篇解释得很好的文章,但是正如示例所示,这仅适用于一个记录。如果更新了多条记录,它确实提供了一个解决方案,但我的问题是如何处理为每条记录增加第一个表中的值,然后为每条记录更新一个新值?

知道为什么它很慢(好吧,使用 sql server 管理控制台)?

我找到的文章可以在http://benreichelt.net/blog/2005/12/13/making-a-trigger-fire-on-column-change/找到

我根据这篇文章写的触发器如下:

CREATE TRIGGER [dbo].[trig_DataTable] ON [dbo].[DataTable]
FOR UPDATE
AS
IF UPDATE(Status)
BEGIN
SET NOCOUNT ON;

  DECLARE @newStatus NVARCHAR(50)
  DECLARE @oldStatus NVARCHAR(50)   
  DECLARE @maxRefNo INT

  DECLARE @id BIGINT

  SET @maxRefNo = (SELECT MAX(RefNo) FROM CounterTable) + 1
  UPDATE CounterTable SET RefNo = @maxRefNo

  SET @newStatus = (SELECT Status FROM Inserted)
  SET @oldStatus = (SELECT Status FROM Deleted)

  IF (@newStatus != @oldStatus) AND (@newStatus = 'Approved')
  BEGIN   
    SET @Id = (SELECT Id FROM Inserted)
    UPDATE DataTable
    SET UniqueRef = @maxRefNo
    WHERE Id = @Id
  END

END

关于上述问题的另一个快速问题!由于上述触发器仅适用于单个记录,我是否需要使用 where 部分?需要这个似乎没有意义。

不是很重要,因为我需要的是与上面相同的行为,但它需要处理包含在 INSERTED/DELETED 表中的多条记录。

我能否编写一个函数来获取下一个可用数字并更新 CounterTable,然后从文章中解释的类似 SQL 调用此函数

INSERT INTO PriceHistory(ItemId, OldPrice, NewPrice, UniqueRef)
 SELECT I.ItemId, D.Price, I.Price, dbo.GetNextRefNo()
 FROM INSERTED I INNER JOIN DELETED D ON I.ItemId = D.ItemId
 WHERE I.Price != D.Price

我不确定是否诚实...我会在一秒钟内试一试,但如果你们中的任何人对如何实现这一点有任何想法,请告诉我...会很棒!谢谢。

我希望以上是有道理的。

干杯。

T.

【问题讨论】:

  • 您展示的INSERT 是在正确的轨道上。您想在Id 上的JOIN inserteddeleted 表,其中Status 已更改为“已批准”。诀窍是你想要UPDATE 两个表,CounterTableDataTable。您可以通过将正在处理的行数添加到RefNo 来“保留”一个幻数块吗?如果是这样,更新到DataTable 应该会更容易一些。

标签: sql sql-server database triggers


【解决方案1】:

使用下面的查询:

CREATE TRIGGER [dbo].[trig_DataTable] ON [dbo].[DataTable]
FOR UPDATE
AS BEGIN
    SET NOCOUNT ON;
    DECLARE @maxRefNo INT
    DECLARE @id BIGINT

    SET @maxRefNo = ISNULL((SELECT MAX(RefNo) FROM CounterTable),0)

    UPDATE CounterTable 
    SET RefNo = @maxRefNo + (SELECT COUNT(*) 
                            FROM INSERTED A 
                            INNER JOIN DELETED D ON D.id=A.id
                            WHERE A.STATE = 'Approved'
                              AND A.STATE <> D.State)

    UPDATE DataTable
    SET UniqueRef = @maxRefNo + ROW_NUMBER() OVER (ORDER BY A.id)
    FROM INSERTED A
    INNER JOIN DELETED D ON D.id = A.id
    WHERE DataTable.Id = A.Id
        AND A.STATE = 'Approved'
        AND A.STATE <> D.State
END

当您编写触发器时,必须使用插入表中的多条记录执行该触发器。没有任何记录。

【讨论】:

  • CounterTable 中获取和更新RefNo 的值可以通过在UPDATE 语句上使用OUTPUT 子句来实现原子化。这样就不需要单独的SELECT 来获取值和两个语句之间的任何更改风险。
  • 好东西!!再次感谢!
  • 我说得很快。我在“OVER BY(ORDER BY A.id)上收到错误。我收到的错误是:Msg 156, Level 15, State 1, Procedure trig_DataTable, Line 19 关键字'BY'附近的语法不正确。有什么想法吗?
  • @Thierry;我编辑我的查询,Row_Number 语法是:ROW_NUMBER() Over (Order By A.Id)
  • @mehdilotfi;我现在遇到另一个错误。 Msg 4108, Level 15, State 1, Procedure trig_DataTable, Line 22 窗口化函数只能出现在 SELECT 或 ORDER BY 子句中,我这边的第 22 行是“SET REF = @maxRefNo + (SELECT COUNT(*) FROM INSERTED A INNER JOIN DELETED DELETED D ON D.id=A.id WHERE A.Status = 'Approved' AND A.Status D.Status)" ... 有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 2011-06-03
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 1970-01-01
  • 2016-11-03
相关资源
最近更新 更多