【问题标题】:T-SQL help needed regarding CASE statement in SELECT clauseSELECT 子句中的 CASE 语句需要 T-SQL 帮助
【发布时间】:2013-09-16 07:17:17
【问题描述】:

什么是最好的方法

方法-I

SELECT 
SUM(CASE WHEN CODE = 'A' THEN ISNULL(UNIT,0.00)+ISNULL(UNIT_1,0.00) END) AS UNIT_SUM
FROM tblA

方法二

SELECT 
ISNULL(SUM(CASE WHEN CODE = 'A' THEN UNIT+UNIT_1 END),0.00) AS UNIT_SUM
FROM tblA

1) 我关心的是我是否必须将 ISNULL 放在 CASE 语句或外部 CASE 语句中。 它是否影响单位总和或两个查询给出相同的结果。 如果任何 UNIT 列的值为 NULL,会发生什么情况。它会导致总计为 NULL。

2) 我必须在 CASE 语句中使用 ELSE,如下所示:

那么 ... ELSE 0.00 结束

【问题讨论】:

  • isnull 放在外面只会影响sum() 的总结果。
  • 当你尝试各种可能性时会发生什么?
  • 我尝试了一些结果集,两者都给出了相同的结果。因为将来的记录会增加,这是我正在寻找的最佳方法

标签: sql sql-server tsql


【解决方案1】:

您有其他答案指出您最好将过滤器= 'A' 放入 where 子句以加快查询速度,这是正确的做法。 我还想指出,如果没有要求和的行,您的查询会产生不同的结果:

SELECT 
ISNULL(SUM(CASE WHEN CODE = 'A' THEN UNIT END),0.00) AS UNIT_SUM
FROM tblA;
-- output: 0

SELECT 
SUM(CASE WHEN CODE = 'A' THEN ISNULL(UNIT,0.00) END) AS UNIT_SUM
FROM tblA;
-- output: null

如果您想获取所有行的总和并将这些数据放入列中,您可以使用以下查询:

select
    isnull(sum(case when code = 'A' then unit end), 0) as [A],
    isnull(sum(case when code = 'B' then unit end), 0) as [B]
from tblA
-- filter out rows if there's more codes in your table
where code in ('A', 'B')

sql fiddle demo

【讨论】:

  • 一个一个地计算总数并最终加入它们会更优雅。您的查询根本不是可推广的。在 where 子句中包含过滤器只是为了提高性能并不优雅。一种与易维护代码不匹配的冗余代码。语句长大后容易陷入矛盾。
  • 我不认为逐个计算总数会更优雅,尝试用 10 个元素来计算,你就会明白为什么。至于我的查询 - 它更通用,但我认为有一种方法可以改进它,当 sqlfiddle 可以工作时会尝试它(现在有一些问题)
【解决方案2】:

回答原问题:

我必须将 ISNULL 放在 CASE 语句中吗...?

不,你没有。 SUM() 忽略 NULLs。因此,NULL 值的存在不会影响求和的结果。例外情况是所有值都为 NULL,或者您根本没有任何值。在这种情况下,您将得到NULL

我必须在 CASE 语句中使用 ELSE 吗?

不,你不这样做是出于同样的原因。

...我需要在CASE之外使用ISNULL()吗?

如果所有值都是NULLs 或者您没有任何值,这取决于您对结果集中的期望。如果您想要0 或任何其他值,请使用ISNULL()COALESCE()。否则不要。

这里是SQLFiddle演示

更新

鉴于您更改后的问题中的表达方式

SUM(CASE WHEN CODE = 'A' THEN UNIT + UNIT_1 END)

如果您想将其中一列的缺失值视为零值,您很可能希望在 UNITUNIT_1 周围使用 ISNULL()COALESCE()。 在这种情况下,如果您想在结果集中获得零,即使没有与您的CASE 条件匹配的值,您仍然需要SUM() 周围使用ISNULL()COALESCE()

SELECT ISNULL(SUM(CASE WHEN CODE = 'A' 
                       THEN ISNULL(UNIT, 0) + ISNULL(UNIT_1, 0) 
                  END), 0) AS UNIT_SUM

SELECT COALESCE(SUM(CASE WHEN CODE = 'A' 
                         THEN COALESCE(UNIT, 0) + COALESCE(UNIT_1, 0) 
                    END), 0) AS UNIT_SUM

这里是SQLFiddle演示

【讨论】:

  • 这是最接近问题解决方案的答案。
  • 我对有问题的 CASE 语句做了一点改动。请检查一下。
  • @Sukhi 你的问题发生了很大的变化。请参阅更新的答案。简而言之,在这种情况下,您很可能希望在 SUM() 聚合内部和外部都使用 ISNULL()
  • @Sukhi 太棒了。我很高兴能帮上忙 :) 祝你好运。
【解决方案3】:

如果您只想要 CODE='A' 的情况的总和,那么我会这样写:

SELECT ISNULL(SUM(UNIT),0.00) AS UNIT_SUM
FROM tblA
WHERE CODE = 'A'

如果您也选择其他列,那么我会这样做:

SELECT ISNULL(SUM(CASE WHEN CODE = 'A' THEN UNIT ELSE 0.00 END)) AS UNIT_SUM
FROM tblA

【讨论】:

    【解决方案4】:

    要么,正确的做法是:

    SELECT 
    ISNULL(SUM(UNIT),0.00) AS UNIT_SUM
    FROM tblA
    WHERE CODE = 'A'    --<------------ Index friendly
    

    您的方法很糟糕,因为它不适合索引。此外,使用 case 语句,您应该评估每一行。

    如果您有更多列要聚合,您可以执行 CTE 查询然后连接结果:

    ;with cte_a as (
        SELECT 
        coalesce(SUM(UNIT),0.00) AS UNIT_SUM_A
        FROM tblA
        WHERE CODE = 'A'
    ),
    cte_b as (
        SELECT 
        coalesce(SUM(UNIT),0.00) AS UNIT_SUM_B
        FROM tblA
        WHERE CODE = 'B'
    )
    SELECT UNIT_SUM_A, UNIT_SUM_B
    FROM cte_a cross join cte_b b 
    

    已编辑@RomanPekar 评论的第二个查询。

    【讨论】:

    • 第二个查询真的很丑陋,根本无法推广,甚至可以改进(cross join 而不是full outer join,将'total'移到最终选择中)。在生产代码中看到这样的查询我会感到震惊。
    【解决方案5】:

    如果您使用方法-II,则不需要 ELSE,所以我认为代码越少越好。

    【讨论】:

      【解决方案6】:

      两种变体返回相同的结果:

      第一个在 SUM 之前 用零替换 NULL,第二个在 SUM 之后 替换一个 NULL,即没有带“A”的行。

      顺便说一句,我会用标准 SQL COALESCE(UNIT,0.00) 替换专有的 ISNULL。

      当然,您可以简单地将其替换为:

      CASE WHEN CODE = 'A' THEN UNIT ELSE 0.00 END
      

      【讨论】:

      • 如果没有要求和的行可能会产生不同的结果
      • 你是对的。我假设这不是完整的查询,会有一些其他列或 GROUP BY other_column。
      猜你喜欢
      • 1970-01-01
      • 2011-11-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多