SQL-使用没有GROUP BY的CASE

时间:2018-04-17 11:08:04

标签: sql sql-server sql-server-2008

如何在GROUP BY中使用CASE表达式获取不使用SQL的值的总和 (或者请建议任何其他最好的方法来实现这一点)

查询

SELECT 
    CASE
        WHEN [lab_date] <= '2018-03-24'
             AND [lab_date] >= '2018-01-01'
        THEN(ISNULL(SUM(ISNULL([cost], 0) * 5 / 100), 0))
        WHEN [lab_date] >= '2018-03-25'
        THEN(ISNULL((SUM(ISNULL([cost], 0))) - (SUM(ISNULL([cost], 0) * 5 / 100)), 0))
    END AS [tax]
FROM [LABOR];

+-------------+--------+
|  lab_date   |  cost  |
+-------------+--------+
| 2018-03-12  |  75.00 |
| 2018-03-01  | 150.00 |
| 2018-03-11  | 450.00 |
| 2018-03-13  |  37.50 |
| 2018-03-15  | 150.00 |
+-------------+--------+

通过lab_date

获取此组
+-------+
|  tax  |
+-------+
| 15.00 |
| 22.50 |
|  3.75 |
|  1.88 |
+-------+

我们如何获得如下结果

+-------+
|  tax  |
+-------+
| 43.13 |
+-------+

2 个答案:

答案 0 :(得分:4)

我认为你想要条件聚合。 。 。其中caseSUM()的参数:

SELECT SUM(CASE WHEN lab_date <= '2018-03-24' AND lab_date >= '2018-01-01' THEN cost * 5.0/100
                WHEN lab_date >= '2018-03-25' THEN cost - cost * 5.0/100
                ELSE 0
           END)  as tax         
FROM LABOR ;

请注意,SQL Server执行整数除法。所以我建议不要写5/100,因为这会评估为0。即使首先执行乘法,不包括小数点也是一个坏习惯。

答案 1 :(得分:0)

为什么要绕过为您的目的而精心设计的功能?

尝试这样的事情:

with
taxes_before(lab_date, tax) as (
  select lab_date, cost*0.05
  from labor
  where lab_date between '2018-01-01' and '2018-03-24'
),
taxes_after(lab_date, tax) as (
  select lab_date, cost*0.95
  from labor
  where lab_date >= '2018-01-25'
),
taxes_all(lab_date, tax) as (
  select lab_date, tax from taxes_before
  union select lab_date, tax from taxes_after
)
select sum(tax)
from taxes_all

免责声明:我这里没有MS SQL Server,如果语法错误,我会感到羞耻。

说明:分别计算X天之前的时间和X之后的时间的两个集合。然后你将这两组联合起来并像往常一样分组。

为什么这比案例表达更好? WHERE子句受益于日期列上的(可能)索引,但是对每行评估case语句,因此查询将扫描表中每个行。