我可以根据多列聚合数据库数据吗?

时间:2013-01-09 20:41:14

标签: sql sql-server aggregate-functions

我想在一行中查找聚合在多个列的属性上的数据。这听起来像是一堆乱码,所以我给你举个例子......这是一个有三列的数据库表:

GroupingId     Type           Date
1              NULL           1/1/11
1              NULL           2/2/22
2              NULL           1/1/11
2              A              2/2/22
3              A              1/1/11
3              B              2/2/22
4              A              1/1/11
4              NULL           2/2/22

我想做一个SELECT,和GROUP BY GroupingId。这很容易。

但是对于其他两列,我想要一些真正依赖于两列的东西。如果我只想要任何给定组的MAX日期,那就很简单了。我真正想要的是Type更喜欢NOT NULL,而Date应该是MAX ...但我希望它们始终来自同一行(Type值为NOT NULL优先)。

所以我的结果应该是

1       NULL      2/2/22       // both Types are null, so last date chosen
2       A         2/2/22       // one Type not null, so that date chosen
3       B         2/2/22       // both Types not null, so last date chosen
4       A         1/1/11       // one Type not null, so that date chosen (and it is not the most recent date)

如果我在日期做MAX,那是不对的。如果我在Type上执行COALESCE,我将在NULL上获得非空值...但不一定是最近的值。

有干净的方法吗?我想我看到如何通过一系列选择,一个表变量和一个UNION来实现这一点,这就是我将要尝试向前发展的方式,但如果有一个干净的SQL解决方案,有人甚至可以在,那将是受欢迎的。

我在SQL Server中,但我猜测如果有一种干净的SQL方法,那么它可能与数据库无关。

2 个答案:

答案 0 :(得分:2)

喜欢这样吗?

;WITH CTESample (GroupingId, Type, Date) AS
(
    SELECT 1, NULL, '1/1/11'    UNION ALL
    SELECT 1, NULL, '2/2/22'    UNION ALL
    SELECT 2, NULL, '1/1/11'    UNION ALL
    SELECT 2, 'A', '2/2/22'     UNION ALL
    SELECT 3, 'A', '1/1/11'     UNION ALL
    SELECT 3, 'B', '2/2/22'     UNION ALL
    SELECT 4, 'A', '1/1/11'     UNION ALL
    SELECT 4, NULL, '2/2/22'    
)
,Partitioned AS
(
    SELECT *
            ,rNum = ROW_NUMBER() OVER (PARTITION BY GroupingID ORDER BY Type DESC, Date DESC)
    FROM CTESample
)
SELECT *
FROM Partitioned
WHERE rNum = 1

答案 1 :(得分:1)

这是使用Rank()的候选人。

所以,我太慢了......不要告诉我的老板。

无论如何一个例子:

SELECT
  [sub].[GroupingID],
  [sub].[Type],
  [sub].[Date]
FROM
(
  SELECT 
    [GroupingID],
    [Type],
    [Date],
    Rank() OVER(PARTITION BY [GroupingID] ORDER BY (CASE WHEN [Type] IS NULL THEN 0 ELSE 1 END) DESC, [Date] DESC, [Type] ASC) AS [Rank]
  FROM [Data]
) AS [sub]
WHERE [sub].[Rank] = 1
ORDER BY [GroupingID] ASC