【问题标题】:Subquery returned more than 1 value when trigger run触发器运行时子查询返回超过 1 个值
【发布时间】:2021-07-20 23:59:13
【问题描述】:

我正在尝试创建 DML 触发器以在 2 个表中执行某些删除和更新操作,

我有 3 张桌子:payments_yearlypayments_yearly_detailscheque_in

payments_yearly 表有所有付款,这些付款的详细信息(付款方式和值)保存在payments_yearly_details 中,付款方式可以是现金、签证、支票。检查详细信息将保存在cheque_in 表中。

我有一个查询,它从详细信息中获取付款信息​​ + 总和值,如下所示:

SELECT dbo.payments_yearly.ID, SUM(dbo.payments_yearly_details.value) AS value, dbo.payments_yearly.note,
dbo.payments_yearly.date, dbo.payments_yearly.app_user FROM dbo.payments_yearly INNER JOIN
dbo.payments_yearly_details ON dbo.payments_yearly.ID = dbo.payments_yearly_details.pay_id where payments_yearly.con_id=@con_id
GROUP BY dbo.payments_yearly.ID, dbo.payments_yearly.con_id, dbo.payments_yearly.note, dbo.payments_yearly.date, dbo.payments_yearly.app_user

因此,如果用户从payments_yearly 表中删除付款,我创建了一个触发器以从cheque_in 表中删除所有支票,并且我的触发器如下所示:

ALTER TRIGGER [dbo].[delete_cheque_after_delete_payment] on [dbo].[payments_yearly]
AFTER Delete
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

Declare @payid as int
set @payid= (select ID from payments_yearly_details where pay_id=(SELECT deleted.ID FROM deleted) and method =N'شيك')
Delete from cheque_in where pay_id =@payid

END

但是当我从payments_yearly 删除任何付款时,支票也没有删除,所以我不知道这里的错误在哪里。 我试图将@pay_id 值更改为cheque_in 表中的静态值,例如25,但它与我创建的另一个触发器冲突,该触发器用于更新付款方式检查的payments_yearly_details 表值“因为这个值可能来自多张支票”当用户更改支票价值或删除与付款相关的支票时,触发如下:

ALTER TRIGGER [dbo].[Update_payments_yearly_detailson_cheque_UpdateDelete] on [dbo].[cheque_in]
after UPDATE, DELETE
AS 
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

IF EXISTS (SELECT 1 FROM payments_yearly_details WHERE ID=(SELECT deleted.pay_id FROM deleted)) 
BEGIN
Declare @value as decimal(10,2)
set @value= (SELECT SUM(cheque_in.cheque_value) from cheque_in where cheque_in.pay_id = (SELECT deleted.pay_id FROM deleted))
Update payments_yearly_details set value=@value where ID=(SELECT deleted.pay_id FROM deleted)
END
END

此触发器运行良好,并在删除支票或更新支票值时更新付款值,但它与第一​​个触发器冲突,并出现以下错误消息: System.Data.SqlClient.SqlException: 'Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression. The statement has been terminated.'

我是触发器的新手,所以我的问题是:为什么我的第一个触发器不起作用?如果我为第一个触发器分配了一个静态值(在检查中,在这种情况下我的触发器工作),为什么我会在第二个触发器上收到错误消息。

谢谢。

【问题讨论】:

  • inserteddeleted 是表,因此它们可以表示集合操作的结果。每个 statement 触发一次触发器,而不是 row。如果您绝对确定不会超过一排,那么添加对行数的检查,并使用RaIsErrorThrow 明确告知以后来的人他们有试图执行不可接受的语句。 (if ( select Count(*) from inserted ) > 1 RaIsError( 'FooTable_Insert: No more than one row may be processed.', 25, 42 ) with log)

标签: sql-server tsql triggers


【解决方案1】:

你的问题是这样的:

 (select ID from payments_yearly_details where pay_id=(SELECT deleted.ID FROM deleted) and method =N'شيك')

如果此语句返回多个值,您将收到您提到的错误。你不能用标量子查询来做到这一点。我的意思是在系统抛出硬错误的事实之外 - 考虑一下 - 我的变量现在等于这个和那个?这没有意义。

您可以像使用 DISTINCT 或 GROUP BY 一样使用廉价的技巧来修复它,但这并不能解决问题的逻辑方面。

编辑

所以你刚刚指出了你的问题:

 (SELECT deleted.ID FROM deleted)

如果您一次删除多个 ID,则会出现此错误。

编辑 2

所以现在我们知道您每行有多个 id,并且我们知道您尝试分配给变量的方式不起作用,所以试试这个。

改变这个:

Declare @payid as int
set @payid= (select ID from payments_yearly_details where pay_id IN (SELECT deleted.ID FROM deleted) and method =N'شيك')
Delete from cheque_in where pay_id =@payid

到这里:

Delete from cheque_in where pay_id IN ((select ID from payments_yearly_details where pay_id IN ((SELECT deleted.ID FROM deleted)) and method =N'شيك'))

【讨论】:

  • 但是如果我像这样运行这个查询:select ID from payments_yearly_details where pay_id=(27) and method =N'شيك' 我会得到一个结果是“25”。为什么我的第一个触发器一开始就不起作用,你能看出它有什么问题吗??
  • 哦,现在有道理了,您认为完成此任务的最佳方法是什么??
  • 把它变成一个相关的子查询——这样每个结果集都绑定到外部查询,这将防止你的查询被轰炸。
  • 您也可以将该比较运算符转换为 IN 而不是 =
  • 为什么我不能从这个查询中得到结果?? set @payid= (select ID from payments_yearly_details where pay_id in (SELECT deleted.ID FROM deleted) and method =N'شيك'),如果我在触发器中使用它,触发器将什么也不做,但如果我用静态数字 39 替换它,触发器就可以正常工作。
猜你喜欢
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多