如何让触发器等待?

时间:2018-06-06 20:09:21

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

我有一个我无法解决的问题,我有一个销售点,在卖东西,标题表,细节和客户(按此顺序)后插入3个表。

我有一个存储过程,它将最后一条记录插入到bak表中的" text"列,它插入3个表的连接(这是基础),同时我有一个stuff方法,在一行中收集相应的标题(每个标题只有一行)的所有细节,在执行后的过程插入它可以正常工作,但是当使用触发器执行时,会出现错误,无法在" 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

- TRIGGER

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.

3 个答案:

答案 0 :(得分:0)

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

WAITFOR DELAY '00:00:05'

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

答案 1 :(得分:0)

我最近有一个类似的情况。触发器需要检查单独的表中是否有任何记录用于文件附件,我只想仅在有任何新插入的附件时才触发触发器。但是我的触发器在附件表尚未填充之前就已触发。我试图将触发器移到附件表,但是真正的问题是SQL Server抛出timeout expired错误,因为触发器是调用Web API。因此很明显,它需要异步处理。

您肯定不能简单地在过程中添加WAITFOR DELAY,就像前面答案的注释所指出的那样。

您可以做的是使用service broker创建一个异步触发器。然后,您可以使用WAITFOR DELAY来等待QUEUE ACTIVATION的存储过程。因此,基本上,默认情况下触发器无法等待,除非您使其异步。它对我有用。

答案 2 :(得分:0)

我的理解是::您有数据进入三个表,只有在三个表获得数据后,才需要将数据插入BAK表。您无法控制何时数据将进入三个表。

我建议您采用以下方法:

  • 具有一个批处理存储过程:,它是定期计划的,并且会进行这些类型的批处理插入。您可以使用日期过滤器来仅选择在上次运行之后插入的值

  • 免责声明:这是使用触发器的一种糟糕方法。您需要在三个表中定义三个触发器。始终检查所有三个表中是否存在记录并生成标题。如果标头值为NOT NULL,则将其插入BAK表。因此,这里的BAK表插入可以通过三个触发器中的任何一个来进行。