SQL Server组通过排除某些值

时间:2018-03-21 08:21:52

标签: sql-server sql-server-2008 group-by

我有一些如下记录:

ID Val Amount
1  0   3
2  0   3
3  0   4
4  1   2
5  1   3
6  2   3
7  2   4

我想通过列Val对这些数据进行分组并得到总和(金额),但不要对Val = 0的那些进行分组。

我需要的结果集如下:

Val Amount
0   3
0   3
0   4
1   5
2   7

我通过两种方式做到了,但似乎没有一种方法:

第一个是使用联合,例如,首先使用Val = 0的联合,然后将这些联合分组为Val<>。 0并将两个结果集合并。

第二个更好一点。让我们调用表中的数据@Table:

WITH g AS
(
SELECT Val, Amount, CASE WHEN Val = '0' then Val + ID
      else Val END A FROM @table 
)
SELECT CASE WHEN A LIKE '0%' THEN 0 ELSE A END AS A, SUM(Amount)
FROM g
GROUP BY A

这也有效,但是必须与ID列(或raw_number)连接,而不是使用left函数来删除它不是最佳做法。

因此,我正在寻找更好的方法,既看起来更好,也表现更好。

我在SQL Server 2008上工作,但我对任何需要更新版本的解决方案持开放态度。

2 个答案:

答案 0 :(得分:2)

在这里使用联盟。下面联合的顶部找到不为零的值的总量,底部带来零值记录,而不是聚合。

SELECT Val, SUM(Amount) AS Amount
FROM g
WHERE Val <> 0
GROUP BY Val
UNION ALL
SELECT Val, Amount
FROM g
WHERE Val = 0
ORDER BY Val;

Demo

答案 1 :(得分:2)

最简单的方法如下:

SELECT Val, SUM(Amount)
FROM mytable
GROUP BY Val, CASE WHEN Val = 0 THEN ID ELSE 0 END

Demo here

您也可以使用窗口功能来执行此操作:

;WITH CTE AS (
   SELECT ID, Val, Amount,
          DENSE_RANK() OVER (PARTITION BY Val 
                             ORDER BY CASE 
                                         WHEN Val = 0 THEN ID 
                                         ELSE 0 
                                      END) AS rank
  FROM mytable
) 
SELECT Val, SUM(Amount) AS total_amount
FROM CTE
GROUP BY Val, rank

CTE返回的结果集是:

ID  Val Amount  rank
--------------------
1   0   3       1
2   0   3       2
3   0   4       3
4   1   2       1
5   1   3       1
6   2   3       1
7   2   4       1

因此,使用rank,您可以区分0和其他Val值。

Demo here

您可以使用这两种方法,并了解它们在性能方面相互比较的方式。