如果语句包含没有 INTO 子句的 OUTPUT 子句,则 DML 语句的目标表“RECEIPT”不能有任何启用的触发器
Posted
技术标签:
【中文标题】如果语句包含没有 INTO 子句的 OUTPUT 子句,则 DML 语句的目标表“RECEIPT”不能有任何启用的触发器【英文标题】:target table `RECEIPT` of the DML statement cannot have any enabled triggers if the statement contains an OUTPUT clause without INTO clause 【发布时间】:2016-01-15 08:56:33 【问题描述】:我有一个名为INVOICE
的表,它存储有关订单/订单的账单信息,该表中的一列是名为paid
的列,它是一种位。顾名思义,此列表示特定订单/订单账单是否已支付。
我有另一个名为 RECEIPT
的表,该表存储有关特定发票的任何付款流程的信息。
因此,每次用户为指定发票支付金额时,都会创建一个新的收据记录。
现在我要做的是创建一个触发器,更新 INVOICE
表中的 paid
列并将其设置为 1。如果收据总和属于发票等于INVOICE
表中的amount_due
。
换句话说,如果发票到期金额 = 100$
用户支付了 50 美元
然后,迟到了,他付了另外 50 美元
INVOICE 表中的paid
列应设置为 1,因为总付款等于发票到期金额
这是我为实现上述目的而创建的触发器
CREATE TRIGGER tg_invoice_payment ON RECEIPT
AFTER INSERT
AS
BEGIN
UPDATE INVOICE
SET paid = 1
WHERE INVOICE.invoice_id = (SELECT inserted.invoice_id FROM inserted)
AND (SELECT SUM(RECEIPT.amount_paid)
FROM RECEIPT
JOIN inserted ON RECEIPT.receipt_id = inserted.receipt_id
WHERE RECEIPT.invoice_id = inserted.invoice_id) = (SELECT INVOICE.amount_due
FROM INVOICE
JOIN inserted ON INVOICE.invoice_id = inserted.invoice_id
WHERE INVOICE.invoice_id = inserted.invoice_id)
END;
编译成功,但在运行时出现以下错误:
【问题讨论】:
问题出在您没有向我们展示的一段代码中,即执行INSERT ... OUTPUT ...
,并且,正如错误消息也指出(很清楚,IMO),它没有使用INTO
.
另外,你的触发器坏了。当inserted
包含多行时,INVOICE.invoice_id = (SELECT inserted.invoice_id FROM inserted)
将产生错误。
收据表是否有自动递增的标识列?请参考:sql-server-helper.com/error-messages/msg-334.aspx
【参考方案1】:
我个人认为您应该在触发器范围之外更新paid
状态。如果您在RECEIPT
中执行INSERT
,则可以在此之后立即执行UPDATE INVOICE ...
语句(当然是在TRANSACTION
中)。这样会更干净、更可预测。
关于您遇到的错误,根据您提供给我们的信息,很难说出是什么原因造成的。也许TRIGGER
正在触发其他TRIGGER
s,从而产生您遇到的错误?您提供的语句根本没有OUTPUT
语句。
在任何情况下,您提供的语句都没有正确编写(正如 Damien 指出的那样),因为 inserted
表可以有多行。这是为了纠正至少那部分的重写:
CREATE TRIGGER tg_invoice_payment ON RECEIPT
AFTER INSERT
AS
BEGIN
UPDATE
INVOICE
SET
paid = 1
FROM
inserted AS ins
INNER JOIN INVOICE AS inv ON
inv.invoice_id=ins.invoice_id
WHERE
inv.amount_due=(
SELECT
SUM(r.amount_paid)
FROM
RECEIPT AS r
WHERE
r.receipt_id=ins.invoice_id
);
END;
但正如我之前提到的,您可能不会通过TRIGGER
执行此操作。在任何INSERT/UPDATE
之后立即从您的程序中执行此语句。或者,编写一个用于插入RECEIPT
的存储过程,并在INSERT
之后立即执行UPDATE
语句。
【讨论】:
非常感谢,我对 SQL 语法不是很熟悉,但我从错误中了解到,如果有OUTPUT
语句,则必须有 INTO
子句,但实际上我的代码和你的不包含任何OUTPUT
语句。我不知道我是否理解正确,再次感谢@TT
@AliAlhamaly 此语句中没有 OUTPUT 子句。这是您的线索,您应该在其他地方寻找您遇到的问题的原因。 GL!
我想我找到了问题的原因,RECEIPT
表中的 id 列是一个自动递增的标识列。在 google 上进行一些搜索,我发现包含更新语句的启用触发器无法在包含此类 id 列的表上触发,我的意思是自动递增的标识表。所以我现在需要解决这个问题来绕过这个错误。但仍然不确定这是否是真正的原因
这个*** thread 似乎是关于你的情况。您正在插入/更新收据,并且插入语句显然有一个 OUTPUT 子句。要么在语句中添加INTO ...
,要么重写语句以不包含 OUTPUT 子句。以上是关于如果语句包含没有 INTO 子句的 OUTPUT 子句,则 DML 语句的目标表“RECEIPT”不能有任何启用的触发器的主要内容,如果未能解决你的问题,请参考以下文章
修改要插入的数据的触发器不起作用(语句包含没有 INTO 子句的 OUTPUT 子句)
选择列表中的列无效,因为该列没有包含在聚合函数或 GROUP BY 子句中