【问题标题】:How can I make the trigger wait?如何让触发器等待?
【发布时间】:2018-06-06 20:09:20
【问题描述】:

我有一个我无法解决的问题,我有一个销售点,它在销售某物后插入 3 个表,标题表、详细信息和客户(按此顺序)。

我有一个存储过程,它在 bak 表中插入最后一条记录,在“文本”列中,它插入了 3 个表的串联(这是基本的),同时我有一个东西方法可以收集所有单行中的详细信息与相应的标题(每个标题只有一行),插入后执行程序时可以正常工作,但是使用触发器执行时会出现错误,无法在“中插入空值” text" 列,这是因为触发器指向表头,而其他 2 个表指向一个不填充,如果我把它放在详细级别,stuff 方法不起作用(因为它每个表头插入一条记录) ,想法是指向表头但等到一切都完成,有什么办法吗?我不能从销售点触及任何东西,一切都在数据库级别(SQL SERVER 2008),可以做些什么吗?是否可以延迟触发器以等待其他 2 个表的填充完成?

--中间表

CREATE TABLE [bak]
(
    [id] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [date] [date] NOT NULL,
    [serie] [varchar](2) NOT NULL,
    [text] [varchar](6000) NOT NULL
);

--存储过程

CREATE PROCEDURE sp_bak
AS
BEGIN
  ;
  WITH CTE
  AS (SELECT
    h.date InsertDate,
    h.series DocumentSerie,
    ('349891894' + h.date + h.series + h.total +
    h.type + CHAR(13) + CHAR(10)) HeaderData,
    (d.quantity + d.price + d.description + c.name + 
    c.identification) DetailData
  FROM header h
  FULL JOIN detail d
    ON a.cod = b.cod
  FULL JOIN customers c
    ON b.cod = c.cod)
  INSERT dbo.bak (date, serie, text)
    SELECT TOP 1
      InsertDate,
      DocumentSerie,
      HeaderData + REPLACE(STUFF((SELECT
        ';' + DetailData
      FROM CTE C
      WHERE C.HeaderData = T.HeaderData
      FOR xml PATH ('')), 1, 1, ''), ';', CHAR(13) + CHAR(10))
    FROM CTE T
    GROUP BY HeaderData,
             DocumentSerie,
             InsertDate
  order by InsertDate DESC
END

--触发

CREATE TRIGGER dbo.tr_bak
ON dbo.header
AFTER INSERT
AS
BEGIN
    EXEC sp_bak
END
GO

--错误

Msg 515, Level 16, State 2, Procedure sp_bak, Line 4
Cannot insert the value NULL into column 'text', table 'VIDEOJUEGOS.dbo.bak'; column does not allow nulls. INSERT fails.

【问题讨论】:

  • 你的逻辑对我来说根本没有任何意义,只是为了回答你的问题,不。触发器同步触发。您为使其等待所做的任何事情都只会延迟引发错误的时间。稍微绕路,sp_前缀不是个好习惯。您应该更改您的前缀,或者最好根本没有前缀。 sqlperformance.com/2012/10/t-sql-queries/sp_prefix你能把触发器放在最后一张桌子上吗?
  • 另外,您的触发器没有引用插入或删除的虚拟表。这是一个巨大的危险信号,表明您的触发器中有问题。您很可能应该使用 insert 而不是 TOP 1 查询。
  • 我的程序要大得多,我已经减少了它以便能够更好地解释我的疑问(可能是某些东西已经移动,因为如果它在不使用触发器的情况下对我有用的话),on “sp_”的主题,如果是我的错误,我通常使用“usp_”,所以我是在研究所教的。我担心我不会看到解决方案,希望以后在 sql server 中添加一个选项,比如他们在 sql-server 2017 中添加的 string_agg 来模拟东西 xml 路径,我将不得不这样做没有别的工作,非常感谢。我不会说英语,对不起。
  • 好的,所以从表面上看触发器并说这是一个例子,我仍然不明白你真正想要做什么。为什么不能将触发器放在最后插入的表上?然后,您将在其他两个表中有行。您不能引用此触发器中不存在的行。

标签: sql-server sql-server-2008 stored-procedures triggers for-xml-path


【解决方案1】:

我的理解是:你有数据进入三个表,只有在三个表得到数据后,你必须将数据插入到 BAK 表中。您无法控制数据何时进入三个表。

我会建议你以下方法:

  • 有一个批量存储过程: 定期安排并执行此类批量插入。您可以使用日期过滤器仅选择在上次运行后插入的值

  • 免责声明:这是使用触发器的不好方法。您需要在三个表中定义三个触发器。始终检查所有三个表中是否存在记录并生成表头。如果标头值不为空,则插入到 BAK 表中。因此,这里的 BAK 表插入可以通过三个触发器中的任何一个来实现。

【讨论】:

    【解决方案2】:

    在您的 sp_bak 存储过程中,您可以将第一条语句设为:

    WAITFOR DELAY '00:00:05'
    

    时间可以是任意秒数,但在其他表被插入值之前就足够了。上述语句将 WAITFOR 之后的语句的执行延迟 5 秒。 请注意,这可能不是处理此类问题的好方法,因为如果延迟时间太长,触发器可能会花费时间执行并导致操作延迟。

    【讨论】:

    • 这有什么帮助?该过程从该表上的触发器运行。所有这一切都会在同样的错误发生前增加 5 秒。
    • 当存储过程等待时,值会被插入到detail和customers表中,存储过程中的语句会根据需要从这些表中返回值。
    • 不,那样不会发生。当他们插入 bak 时,触发器将触发,这将调用此过程。触发器不是异步的,因此原始代码中的其他插入将等待插入完成。并且该插入正在等待触发器完成。所有这些都是 ACID 的原子部分所必需的。
    • Kashyap MNVL,我已经尝试过了,正如 Sean Lange 所说,这不起作用,他唯一做的就是延迟错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 2021-11-01
    • 2011-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多