我正在直接调用我的数据库中的用户定义函数.问题是,该函数似乎随机返回正确的值或抛出错误Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.,即使在数据库中没有更改,而且它与上一次调用相隔几秒钟.

函数调用语法:

select dbo.uf_construction_price(16)

功能主体:

GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER FUNCTION [dbo].[uf_construction_price]
(
    @id int
)
RETURNS numeric(19,6)
AS
BEGIN
    
    DECLARE @rounding INT
    SELECT @rounding = rounding from construction_settings WHERE construction_id = @id

    DECLARE @price NUMERIC(19,6)

    SET @price = (SELECT ISNULL(ROUND(SUM(ROUND(ROUND(ISNULL(bi.joc,0),2) * ROUND(ISNULL(bi.value,0),isnull(@rounding,3)),2)),2),0) 
    FROM budget_items bi 
    WHERE is_available != 1 AND construction_id = @id)

    RETURN isnull(@price,0.00)
END

我已经try 了很多事情来调试这个问题,这些是基于我的研究的更具描述性的行为:

  • 当按原样调用Body时,它不会抛出错误.
  • 错误抛出在包含SET @price =的行上,其中后续查询sometimes returns multiple results即使在SUM不可能的情况下也会抛出错误(使用TOP 1时,它似乎返回未加和的结果)
  • 兼容性结果似乎与问题(不同的行为)相关,但同样,没有确凿的证据证明这一点.
  • 当我用下面的代码片段替换第SET @price =行时,它似乎工作正常,但我也不知道为什么:
    declare @Temp TABLE (id int)
    insert into @Temp
    SELECT ISNULL(ROUND(SUM(ROUND(ROUND(ISNULL(bi.joc,0),2) * ROUND(ISNULL(bi.value,0),isnull(@rounding,3)),2)),2),0) 
    FROM budget_items bi 
    WHERE is_available != 1 AND construction_id = @id

    SET @price = (SELECT * FROM @Temp)

推荐答案

这个问题可能不是SUM的问题,因为它已经在聚合,并保证返回单个值.几乎可以肯定的是,它出现在前面的查询中

SELECT @rounding = rounding from construction_settings WHERE construction_id = @id

它没有TOP (1)ORDER BY,因此可能会返回多个结果.

如果函数没有内联,那么额外的结果将被忽略.在SQL Server的最新版本中,即使是内联函数也会使用内部ANY()聚合来确保单个结果.

但是您的RTM构建似乎有一个错误,因为它会将它内联到类似于

OUTER APPLY (
    SELECT rounding = (SELECT rounding from construction_settings WHERE construction_id = @id)
)

首先,通过添加TOP (1)ORDER BY来修复问题本身

SELECT TOP (1) @rounding = rounding
FROM construction_settings
WHERE construction_id = @id
ORDER BY someValueHere;

Make sure to upgradelatest build of SQL Server 2019.这将从一开始就阻止这个问题.


Much better,是将标量UDF转换为表值函数,您可以自己内联该函数.

CREATE OR ALTER FUNCTION dbo.uf_construction_price
(
    @id int
)
RETURNS TABLE
AS RETURN

SELECT
  price =
    ISNULL(
      ROUND(
        SUM(
          ROUND(
            ROUND(ISNULL(bi.joc, 0), 2)
            * ROUND(ISNULL(bi.value, 0), isnull(cs.rounding, 3)),
            2
          )
        ),
        2
      ),
      0
    ) 
FROM (
    SELECT TOP (1) cs.rounding
    FROM construction_settings cs
    WHERE cs.construction_id = @id
    ORDER BY someValueHere
) cs
FROM budget_items bi 
WHERE bi.is_available != 1
  AND bi.construction_id = @id
;

我必须说,你的四舍五入逻辑很奇怪,但不管怎样.

Sql相关问答推荐

基于模式或其他行集的数据复制

使用交叉应用透视表在SQL中转换分段时间段&

跨多列的PostgreSQL非不同对

如何退回当年的所有参赛作品?""

如何从多行数据中获取一行合并数据?

Access 365将文本转换回BigInt

如何查询jsonb列是一个对象数组?

BigQuery-当子查询不返回任何结果时,所有结果为零

如何查找所提供日期范围的所有季度开始日期和结束日期

在SQL查询中使用COALESS

将Dense_RANK列为聚合(非解析)函数(&A)

如何根据几个条件 Select 值:如果满足一个范围的SUM,则对另一个范围求和

SQL中相同表内的VLOOKUP等价

将 json 列键映射到第二个表中的匹配列值

如何在 SQL 中将两行(或多行)jsonb 数组合并为一行

REGEXP_SUBSTR使用方法

MS ACCESS 错误插入 X(...) 从 A 联合 Select ... 从 B

PostgresQL-根据另一列找到 3 个最低值

当没有任何行存在时,将一个表中的行插入到另一个表中的更好方法

在 AWS athena 的视图之上创建视图时,如何消除此错误:列别名列表有 1 个条目但t有 4 列可用?