我有一个我无法解决的问题,我有一个销售点,在卖东西,标题表,细节和客户(按此顺序)后插入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.
答案 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表插入可以通过三个触发器中的任何一个来进行。