【问题标题】:Rank by groups sql server按组排序sql server
【发布时间】:2015-01-21 13:06:49
【问题描述】:

问题看起来很简单,但我无法理解它, 这是用于 sql server 的

 what I have in a table :            What I need as a output .
 cksum          id                      cksum       id
-2162514679     204                    -2162514679  204    1
-2162514679     207                    -2162514679  207    1
-2162514679     215                    -2162514679  215    1
-2162514679     218                    -2162514679  218    1
-2162514679     221                    -2162514679  221    1
-2160286363     257                    -2160286363  257    2
-2160286363     260                    -2160286363  260    2
-2160286363     332                    -2160286363  332    2
-2162514679     335                    -2162514679  335    3
-2162514679     338                    -2162514679  338    3
-2126731931     348                    -2126731931  348    4
-2126731931     387                    -2126731931  387    4

该表按 id 排序,我需要一个 id 列之后的排名,但它对 cksum 进行分组,请注意 cksum 可以返回到以前的值,但由于 ID 仍然具有它的排名(这是这种情况值 2162514679,它在开始时出现 5 次,在下面出现第二次,它们构成两个不同的等级)。我已经用了几个小时了,这似乎真的很愚蠢,就像使用带有分区的 row_number 或使用 CTE 但不......找不到这样做的逻辑......任何人都有回答?

【问题讨论】:

  • 您使用的是哪个 Sql server 版本?
  • 我使用的是 SQL SERVER 2008 R2

标签: sql sql-server group-by rank partition


【解决方案1】:

这有点棘手。您可以通过一个技巧来获得 id 的分组——行号的差异。然后您需要获取每个组的最小 id,以确保最终排名的顺序正确。然后你可以使用 then 你可以使用密集秩:

select cksum, id, dense_rank() over (order by minid)
from (select t.*, min(id) over (partition by cksum, grp) as minid
      from (select t.*,
                   (row_number() over (order by id) -
                    row_number() over (partition by cksum order by id)
                   ) as grp
            from table t
           ) t
     ) t;

【讨论】:

  • 我认为,您对row_number() 的第二次调用缺少order by
  • 这个解决方案很有希望,但我遇到的问题是这一行`row_number() over (partition by cksum Order by id)`不会重置它在最后一个值被取消,所以这有时会按顺序给我开关,因此不遵循 id 顺序列。如果我能够为每个分区将其重置为零,那么它将起作用。
  • @FlyingTurtle 。 . .我不明白你的评论。 (注意:我只是用正确的order by 修复了查询。)这些开关并不重要,因为差异——连同 cksum——唯一地标识了每个组。然后min(id)用于最终排名。
  • 当您剖析 grp 列的计算时,这就是我得到的结果:cksum 1RN 2RN grp -1 1 1 0 -1 2 2 0 -1 3 3 0 -2 4 1 3 -2 5 2 3 -1 6 4 2 -1 7 5 2 -1 8 6 2 从这个结果中可以看出,第一组的第二个 RN 的值与第一个停止(在 4 处),这给出了错误的 grp(两个差异和错误排名的相同 grp 的风险)
  • @FlyingTurtle 。 . .中间子查询中的partition by 使用cksumgrp 的等效值是不相关的,因为不同的 cksum 值是不相关的。该解决方案确实假定 ids 是唯一的。
【解决方案2】:

这是一种不同的方法,它涉及模拟 SQL Server 2008 R2 中不可用的 LAG 窗口函数:

;WITH CTE_RN AS (
   SELECT cksum, id, ROW_NUMBER() OVER(ORDER BY id) AS rn
   FROM Checksums
), CTE_LAG AS (
   SELECT c1.cksum, c1.id, c1.rn,
          (CASE WHEN c2.cksum IS NULL OR c1.cksum = c2.cksum THEN 0
                ELSE 1
           END) AS flag 
   FROM CTE_RN AS c1
   LEFT JOIN CTE_RN AS c2 ON c1.rn = c2.rn+1
)
SELECT cksum, id,  (SELECT SUM(flag)
                    FROM CTE_LAG AS t2        
                    WHERE t2.rn <= t1.rn) + 1 AS [rank]     
FROM CTE_LAG AS t1

CTE_LAG返回如下结果集(基于OP的样本数据):

cksum       id  rn  flag
-------------------------
-2162514679 204 1   0
-2162514679 207 2   0
-2162514679 215 3   0
-2162514679 218 4   0
-2162514679 221 5   0
-2160286363 257 6   1
-2160286363 260 7   0
-2160286363 332 8   0
-2162514679 335 9   1
-2162514679 338 10  0
-2126731931 348 11  1
-2126731931 387 12  0

如果当前cksum不等于之前的cksum,则字段flag等于1,否则flag等于0。

字段rank 只是flag 的总和。

【讨论】:

  • 可以了,很喜欢这种虽然找到解决方案的模式,非常感谢!
猜你喜欢
  • 2012-09-22
  • 1970-01-01
  • 2011-09-20
  • 1970-01-01
  • 1970-01-01
  • 2020-11-21
  • 1970-01-01
  • 1970-01-01
  • 2018-06-20
相关资源
最近更新 更多