存储过程生成 msg 512 子查询返回超过 1 个值

Posted

技术标签:

【中文标题】存储过程生成 msg 512 子查询返回超过 1 个值【英文标题】:stored procedure generating msg 512 Subquery returned more than 1 value 【发布时间】:2021-07-09 19:03:15 【问题描述】:

在 Sql Server 2019 中我得到了

msg 512 子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

在几个地方,第一个在本节中。

IF (SELECT Job FROM [PRODUCTION].[dbo].[Job] WHERE Part_Number = @PN) is null
    SELECT @Job='NOTHING'
ELSE
    SELECT @Job = (SELECT Job FROM [PRODUCTION].[dbo].[Job] WHERE Status_Date = (SELECT 
       Max(Status_Date) FROM [PRODUCTION].[dbo].[Job] WHERE Part_Number = @PN  AND Status = 
      'Closed'))

我可以自己运行查询并且总是只得到一个结果。我已经尝试使用TOP 1 进行查询,但仍然得到消息 512。

【问题讨论】:

SELECT Max(Status_Date) ... 总是只得到一个结果。 SELECT Job FROM [PRODUCTION].[dbo].[Job] WHERE Status_Date = (...),不一定。它也是您设计中的子查询。 我打赌将top(1) 添加到if (select job 将解决它。 如果您在互联网上搜索该消息,您会发现很多关于为什么会发生此错误以及如何修复(甚至避免)它的讨论。但您似乎有一个常见的“组内第一”查询,而采用非常不同的方法会更合适。 我已经尝试使用 TOP 1 并且仍然得到错误。 Max(Status_Date) 只返回一个值 错误将来自您的第一个if,而不是else; else 中的 select 是否返回许多行都没有关系,分配给 @job 是完全合法的,但是 if(many rows) is null 是不行的。 【参考方案1】:

您的代码中有两个相同的逻辑缺陷。您知道 IF 语句是一个问题,因为它已经被指出。所以通过替换来避免它:

IF (SELECT Job FROM [PRODUCTION].[dbo].[Job] WHERE Part_Number = @PN) is null
    SELECT @Job='NOTHING'

if not exists (select * from dbo.Job where Part_Number = @PN) 
   set @Job = 'NOTHING'; 

注意更好的做法。删除了数据库名称,因为连接应该确定这一点。删除方括号,因为它们不是必需的。使用 SET 分配标量值而不是 SELECT。语句终止符。等等。

附加错误是在用于检索作业值的选择语句中。去除多余的绒毛进行分配,你有:

SELECT Job FROM [PRODUCTION].[dbo].[Job] 
 WHERE Status_Date = 
   (SELECT Max(Status_Date) 
      FROM [PRODUCTION].[dbo].[Job] 
     WHERE Part_Number = @PN  AND Status = 'Closed'
    )

这里的子查询确实会为您想要的零件编号和状态选择一行。但是,您只选择一个日期,并且在 Status_Date 列中可能(并且显然是)许多行具有该特定日期。您没有将外部查询限制为适当的 part_number - 这可能会也可能不会解决您的问题(因为我不知道您的架构)。

因此,我建议您搜索我在 cmets 中使用的术语,并使用 row_number 方法访问“第一行”(实际上是降序排列的最后一行),而不是这种容易出错的方法。

为了完整起见,您可以将作业更改为:

set @Job = (top 1 Job from dbo.Job 
      where Part_Number = @PN and Status = 'Closed' order by Status_Date desc);

这也可能“避免”这个问题,但我不能在不了解您的架构的情况下说。据推测,许多工作可以具有相同的 Part_Number,所以我认为这里缺少一些东西。

【讨论】:

【参考方案2】:

使用exists尝试以下反转逻辑

if exists (select * from dbo.job where part_number = @PN)
  select @job= (....)
else
  select @Job='NOTHING'

【讨论】:

以上是关于存储过程生成 msg 512 子查询返回超过 1 个值的主要内容,如果未能解决你的问题,请参考以下文章

语句错误时的MSSQL案例

子查询返回的值不止一个.当子查询跟随在 =,!=,<,<=,>,>= 之后,或子查询用作

SQL问题,子查询返回的值不止一个!

服务器: 消息 512,级别 16,状态 1,行 1 子查询返回的值多于一个。

SQL Server 子查询返回超过 1 个值。子查询遵循 =, !=, <, <= , >, >=

子查询返回超过 1 个值。当子查询跟随 = 或子查询用作表达式时,这是不允许的