如何根据多个列的聚合返回单行

时间:2013-03-25 21:03:54

标签: sql sql-server tsql

对于模棱两可的标题,不确定如何搜索或提出此问题,我们深表歉意。

假设我们有TableA:

RowID        FkId        Rank        Date
ID1          A           1           2013-3-1
ID2          A           2           2013-3-2
ID3          A           2           2013-3-3
ID4          B           3           2013-3-4
ID5          A           1           2013-3-5

我需要创建一个视图,为每个FkId返回1行。该行应该是最大排名和最大日期。因此对于FkId“A”,查询将返回“ID3”的行。

我能够通过使用子查询返回单行;首先我获得MAX(Rank),然后加入另一个通过FkId&获得MAX(Date)组的查询。秩。

SELECT TableA.*
(Select FkId, MAX(Rank) AS Rank FROM TableA GROUP BY FkId) s1 
INNER JOIN (Select FkId, Rank, MAX(Date) AS Date FROM TableA GROUP BY FkId,Rank) s2 ON s1.FkId = s2.FkId AND s1.Rank = s2.Rank 
INNER JOIN TableA ON s2.FkId = TableA.FkId AND s2.Rank = TableA.Rank AND s2.Date = TableA.Date

是否有更高效的查询可以获得相同的结果?谢谢你的期待。

编辑:自上次回答后添加了ID5。如果我尝试了正常的MAX(等级),MAX(日期)GROUP BY FkId,那么对于“A”,我会得到A; 2; 2013年3月5日。此结果与RowId不匹配。

4 个答案:

答案 0 :(得分:4)

您可以将ROW_NUMBERCTE一起使用(假设sql-server> = 2005):

WITH CTE AS
(
   SELECT TableA.*,
      RN = ROW_NUMBER() OVER (PARTITION BY FkId Order By Rank Desc, Date DESC)
   FROM Table A
)
SELECT RowID,FkId, Rank,Date
FROM CTE WHERE RN = 1

答案 1 :(得分:2)

您的问题(在对此答案的评论中澄清)要求:

  1. 每个FkId
  2. 一行
  3. 最大日期和排名
  4. 结果与原始数据中的行对应。
  5. 如果存在具有行的FkIds,使得最大日期和最大等级位于不同的行中,则必须至少放松其中一个要求。

    如果您愿意放宽要求(3),那么您可以使用GROUP BY

    SELECT FkId, MAX(Rank) AS Rank, Max(Date) AS Date
    FROM TableA
    GROUP BY FkId
    

    鉴于评论中的额外信息。如果您想要每个FkId中排名最高的最新条目,则以下内容应该有效:

    SELECT FkId, Rank, MAX(Date) AS Date
    FROM TableA A
    WHERE Rank = (SELECT MAX(Rank) 
                  FROM TableA sub 
                  WHERE A.FkId = sub.FkId 
                  GROUP BY sub.FkId)
    GROUP BY FkId, Rank
    

    这是sqlfiddle to show it in action

答案 2 :(得分:1)

您可以使用Rank()和内联查询来实现它。


select * from TableA
where RowID in (
      select rowID from (
           select FKID, RowID, 
                  rank() over (partition by FKID order by [Rank] desc, [Date] desc) as RankNumber
                  from TableA ) A
      where A.RankNumber=1 ) 

SQL Fiddle Demo

答案 3 :(得分:0)

你也可以偷偷摸摸地完成ljh建议的like this

select top 1 with ties *
from TableA
order by rank() over (
  partition by FKID
  order by [Rank] desc, [Date] desc
)