SQL Server:如何处理查询中被0除的情况

发布于 2024-09-14 19:02:19 字数 388 浏览 6 评论 0原文

我有一个如下所示的查询,它正在获取百分比:

SELECT SUM(convert(decimal(3,2),
          CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
          SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) * 100
FROM SomeTable

在正常情况下,这可能会返回类似 59.77803 的内容。但事实证明,在某些情况下,第二个 SUM(分母)可能为 0。有谁知道一种方法来解释这种情况并避免除以 0 异常?

我正在使用 SQL Server 2005。谢谢。

I have a query that looks like this, and which is getting a percentage:

SELECT SUM(convert(decimal(3,2),
          CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
          SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) * 100
FROM SomeTable

This may return something like 59.77803 in a normal case. But it turns that there are (rightly) cases when the second SUM -- the denominator -- could be 0. Does anyone know of a way to account for this case and avoid a divide by 0 exception?

I'm using SQL Server 2005. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

遇见了你 2024-09-21 19:02:19

我可能会使用 NULL 来表示不可计算,但这取决于您在问题域中的意图(代码扩展以显示发生的情况):

SELECT SUM(convert(decimal(3,2),
                   CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END)
          )
       /
       NULLIF(
           SUM(convert(decimal(3,2),
                       CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)
           )
           , 0
       )
       * 100
FROM SomeTable

表中没有行时的结果,因此分母为零 - 转换为NULL 因此整个表达式最终为 NULL。

该代码也可以稍微简化(可能是因为它已经是一个简化的玩具问题):

SELECT SUM( convert(decimal(3,2), CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END) )
       /
       NULLIF( convert(decimal(3,2), COUNT(*)), 0 )
       * 100
FROM SomeTable
WHERE State_ID = 14

作为将许多不同的事物组合到一个查询中的示例:

SELECT CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END AS Category
       ,SUM(convert(decimal(3,2),
                   CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END)
          )
       /
       convert(decimal(3,2), COUNT(*))
       * 100
FROM SomeTable
GROUP BY CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END

I would probably use a NULL to represent uncalculatable, but it depends upon your intent in your problem domain (code expanded to show what's going on):

SELECT SUM(convert(decimal(3,2),
                   CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END)
          )
       /
       NULLIF(
           SUM(convert(decimal(3,2),
                       CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)
           )
           , 0
       )
       * 100
FROM SomeTable

The result when there are no rows in the table so the denominator would be zero - gets converted to NULL so the whole expression ends up NULL.

That code can also be simplified a little (probably because it's already a simplified toy problem):

SELECT SUM( convert(decimal(3,2), CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END) )
       /
       NULLIF( convert(decimal(3,2), COUNT(*)), 0 )
       * 100
FROM SomeTable
WHERE State_ID = 14

As an example of combining a number of different things into one query:

SELECT CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END AS Category
       ,SUM(convert(decimal(3,2),
                   CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END)
          )
       /
       convert(decimal(3,2), COUNT(*))
       * 100
FROM SomeTable
GROUP BY CASE WHEN State_ID = 14 THEN 'State_ID = 14'
            WHEN State_ID IN (1, 2, 3) THEN 'State_ID IN (1, 2, 3)'
            ELSE 'DEFAULT'
       END
指尖上得阳光 2024-09-21 19:02:19

问问自己,当分母为 0 时,您想要返回什么结果?
然后据此相应地修复查询。

没有好的内置方法可以做到这一点。这是一个商业逻辑的事情。

ask yourself what's the result you want to return when the denominator is 0?
then based on that fix the query accordingly.

there's no good built-in way to do it. It's a business logic thing.

吐个泡泡 2024-09-21 19:02:19

如果我没读错的话,这应该有效:

SELECT SUM(convert(decimal(3,2), 
          CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END))/ 
          SUM(convert(decimal(3,2),1)) * 100 
FROM SomeTable 
WHERE State_ID = 14 

If I'm reading it right, this should work:

SELECT SUM(convert(decimal(3,2), 
          CASE WHEN Status_ID = 1 THEN 1 ELSE 0 END))/ 
          SUM(convert(decimal(3,2),1)) * 100 
FROM SomeTable 
WHERE State_ID = 14 
时光暖心i 2024-09-21 19:02:19
SELECT SUM(convert(decimal(3,2),
          CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
          SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) + 0.00000000001 * 100
FROM SomeTable
SELECT SUM(convert(decimal(3,2),
          CASE WHEN Status_ID = 1 AND State_ID = 14 THEN 1 ELSE 0 END))/
          SUM(convert(decimal(3,2),CASE WHEN State_ID = 14 THEN 1 ELSE 0 END)) + 0.00000000001 * 100
FROM SomeTable
小草泠泠 2024-09-21 19:02:19

为了避免除以 0 异常,您可以使用接受分子、分母和默认值的函数,当分母为 0 时传递。并调用该函数进行除法。

CREATE FUNCTION [dbo].[fn_divide] 
(
    @numerator DECIMAL(3,2),@denominator DECIMAL(3,2),@default DECIMAL(3,2)
)  
RETURNS DECIMAL(3,2) 

AS  BEGIN

 DECLARE @result DECIMAL(3,2)

 IF @denominator = 0
 BEGIN
    set @result=@default
 END
ELSE
 BEGIN
    set @result=@numerator/@denominator
 END 

  return @result
END

To avoid divide by 0 exception you can use a function which accepts numerator,denominator and default value to pass when denominator is 0. And call that function to do division.

CREATE FUNCTION [dbo].[fn_divide] 
(
    @numerator DECIMAL(3,2),@denominator DECIMAL(3,2),@default DECIMAL(3,2)
)  
RETURNS DECIMAL(3,2) 

AS  BEGIN

 DECLARE @result DECIMAL(3,2)

 IF @denominator = 0
 BEGIN
    set @result=@default
 END
ELSE
 BEGIN
    set @result=@numerator/@denominator
 END 

  return @result
END
不奢求什么 2024-09-21 19:02:19

真正的问题是,当您尝试除以零时,“答案”应该是什么?我会将其设置为 NULL,因此请尝试这样的操作:

DECLARE @x int

set @x=5
select 1.0/NULLIF(@x,0)

set @x=0
select 1.0/NULLIF(@x,0)

输出:

---------------------------------------
0.200000000000

(1 row(s) affected)


---------------------------------------
NULL

(1 row(s) affected)

您的代码将是:

SELECT SUM(convert(decimal(3,2), CASE
                                     WHEN Status_ID = 1 AND State_ID = 14 THEN 1 
                                     ELSE 0 
                                 END
                  )
          ) 
        /
        SUM(convert(decimal(3,2),CASE
                                     WHEN State_ID = 14 THEN 1 
                                     ELSE NULL   --<<<<<<<<<<<<force null if div by zero
                                 END
                   )
           )
        * 100
FROM SomeTable

我不太明白 WHEN Status_ID = 1 AND St​​ate_ID = 14 THEN 1,但那是OP代码。

The real question is what should the "answer" be when you try to divide by zero? I'd make it NULL, so try something like this:

DECLARE @x int

set @x=5
select 1.0/NULLIF(@x,0)

set @x=0
select 1.0/NULLIF(@x,0)

OUTPUT:

---------------------------------------
0.200000000000

(1 row(s) affected)


---------------------------------------
NULL

(1 row(s) affected)

your code would be:

SELECT SUM(convert(decimal(3,2), CASE
                                     WHEN Status_ID = 1 AND State_ID = 14 THEN 1 
                                     ELSE 0 
                                 END
                  )
          ) 
        /
        SUM(convert(decimal(3,2),CASE
                                     WHEN State_ID = 14 THEN 1 
                                     ELSE NULL   --<<<<<<<<<<<<force null if div by zero
                                 END
                   )
           )
        * 100
FROM SomeTable

I don't really understand the WHEN Status_ID = 1 AND State_ID = 14 THEN 1, but that is the OPs code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文