除以零错误遇到错误。通过聚合或其他 SET 操作消除空值

Divide by zero error encountered error. Null value is eliminated by an aggregate or other SET operation

在我尝试创建的 SP 的这个特定部分,我遇到了一个错误:

[Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Divide by zero error encountered. Additional error <2>: ErrorMsg: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Warning: Null value is eliminated by an aggregate or other SET operation., SqlState: 01003, NativeError: 8153

我相信这是因为我试图除以 null 或 0。我不确定如何解决这个问题。我尝试使用 ISNULL,但我认为我做的不对。

select 
    id_date,
    id_company,
    id_kpi,
    sum(CASE WHEN id_kpi=50 THEN -actual_mes END) /
    sum(CASE WHEN id_kpi=51 THEN actual_mes END) Amount
from dual;

有人能指出我正确的方向吗?我已经查看了其他几个与此相关的话题,但我仍然不确定如何解决这个问题。

您可以使用 case when .. else ... endisnull,例如

select 
    id_date,
    id_company,
    id_kpi,
    CASE WHEN ISNULL(sum(CASE  WHEN id_kpi=51 THEN ISNULL(actual_mes, 0) ELSE 0 END), 0) = 0
    THEN 0
    ELSE 
        sum(CASE  WHEN id_kpi=50 THEN -ISNULL(actual_mes, 0) ELSE 0 END) /
        sum(CASE  WHEN id_kpi=51 THEN ISNULL(actual_mes, 0) ELSE 0 END)
    END Amount
from dual;

而不是 CASE,我通常在分母上选择 NullIf()

例子

select id_date,
       id_company,
       id_kpi,
       sum(CASE  WHEN id_kpi=50 THEN -actual_mes END) /
       nullif(sum(CASE  WHEN id_kpi=51 THEN actual_mes END),0) Amount
  from dual;

我将一个安全除法函数放在一起,因为我们对发票数据进行了很多除法,它避免了在构建查询时必须添加条件化的绒毛。相反,只需使用您的枚举数和分母调用该函数,如果您的分母为 0 或 NULL,它将 return 0。如果您愿意,您可以将 @Return 调整为不同的数据类型(即 FLOAT),这样输入就更合适了……我们通常只需要 4 位小数,所以我们将它标准化为相反。

IF OBJECT_ID('dbo.fn_SafeDivide') IS NOT NULL
    DROP FUNCTION dbo.fn_SafeDivide
GO    

CREATE FUNCTION dbo.fn_SafeDivide(
@Numerator FLOAT, 
@Denominator FLOAT 
) 
RETURNS DEC(14,4) 
AS
BEGIN
DECLARE @Return DEC(14,4)

IF COALESCE(@Denominator, 0) = 0
    SET @Return = 0
ELSE
    SET @Return = @Numerator / @Denominator

RETURN @Return
END
GO

使用:

select 
    dbo.fn_SafeDivide(
        SUM(CASE WHEN id_kpi=50 THEN -actual_mes END), 
        SUM(CASE WHEN id_kpi=51 THEN actual_mes END)
    ) as Amount
from dual;