【问题标题】:DENSE_RANK() without duplicationDENSE_RANK() 没有重复
【发布时间】:2017-06-16 10:04:35
【问题描述】:

我的数据如下所示:

| col1 | col2 | denserank | whatiwant |
|------|------|-----------|-----------|
| 1    | 1    | 1         | 1         |
| 2    | 1    | 1         | 1         |
| 3    | 2    | 2         | 2         |
| 4    | 2    | 2         | 2         |
| 5    | 1    | 1         | 3         |
| 6    | 2    | 2         | 4         |
| 7    | 2    | 2         | 4         |
| 8    | 3    | 3         | 5         |

这是我目前的查询:

SELECT col1, col2, DENSE_RANK() OVER (ORDER BY COL2) AS [denserank]
FROM [table1]
ORDER BY [col1] asc

我想要实现的是,每当 col2 的值发生变化时(即使值本身被重用),我的 denserank 列都会递增。我实际上不能按我有 denserank 的列排序,所以这行不通)。有关示例,请参见 whatiwant 列。

有没有什么方法可以通过DENSE_RANK() 实现这一点?或者有其他选择吗?

【问题讨论】:

    标签: sql sql-server sql-server-2016 dense-rank


    【解决方案1】:

    使用窗口函数试试这个:

    with t(col1  ,col2) as (
    select 1 , 1 union all  
    select 2 , 1 union all  
    select 3 , 2 union all  
    select 4 , 2 union all  
    select 5 , 1 union all  
    select 6 , 2 union all  
    select 7 , 2 union all  
    select 8 , 3
    )
    select t.col1,
        t.col2,
        sum(x) over (
            order by col1
            ) whatyouwant
    from (
        select t.*,
            case 
                when col2 = lag(col2) over (
                        order by col1
                        )
                    then 0
                else 1
                end x
        from t
        ) t
    order by col1;
    

    生产:

    它读取单个表并按照 col1 的升序形成一组连续相等的 col2 值,然后在其上找到密集排名。

    • x:如果前一行的 col2 与本行的 col2 相同,则赋值为 0(按递增顺序 col1),否则为 1
    • whatyouwant:通过对上一步生成的 x 值进行增量求和,创建 col2 的相等值组,以增加 col1 的顺序,这就是您的输出。

    【讨论】:

    • 你只是以不同的方式复制了我的代码,这是不公平的。以前你的代码是如此不同
    【解决方案2】:

    这是使用SUM OVER(Order by)窗口聚合函数的一种方式

    SELECT col1,Col2,
           Sum(CASE WHEN a.prev_val = a.col2 THEN 0 ELSE 1 END) OVER(ORDER BY col1) AS whatiwant 
    FROM   (SELECT col1,
                   col2,
                   Lag(col2, 1)OVER(ORDER BY col1) AS prev_val
            FROM   Yourtable) a
    ORDER  BY col1; 
    

    工作原理:

    LAG窗口函数用于为col1排序的每一行查找前一个col2

    SUM OVER(Order by) 只会在前一个col2 不等于当前col2 时增加数字

    【讨论】:

      【解决方案3】:

      我会用这样的递归 cte 来做:

      declare @Dept table (col1 integer, col2 integer)
      
      insert into @Dept values(1, 1),(2, 1),(3, 2),(4, 2),(5, 1),(6, 2),(7, 2),(8, 3)
      
      ;with a as (
      select col1, col2, 
      ROW_NUMBER() over (order by col1) as rn
      from @Dept),
      s as 
      (select col1, col2, rn, 1 as dr from a where rn=1
      union all
      select a.col1, a.col2, a.rn, case when a.col2=s.col2 then s.dr else s.dr+1 end as dr 
      from a inner join s on a.rn=s.rn+1)
      col1, col2, dr from s
      
      result:
      
      col1        col2        dr
      ----------- ----------- -----------
      1           1           1
      2           1           1
      3           2           2
      4           2           2
      5           1           3
      6           2           4
      7           2           4
      8           3           5
      

      仅当您的 col1 值不连续时才需要 ROW_NUMBER。如果是,您可以立即使用递归 cte

      【讨论】:

        【解决方案4】:

        我认为这在纯 SQL 中使用一些间隙和孤岛技巧是可能的,但阻力最小的路径可能是使用会话变量结合LAG() 来跟踪计算的密集排名何时更改值。在下面的查询中,我使用@a 来跟踪密集等级的变化,当它发生变化时,这个变量会增加 1。

        DECLARE @a int
        SET @a = 1
        SELECT t.col1,
               t.col2,
               t.denserank,
               @a = CASE WHEN LAG(t.denserank, 1, 1) OVER (ORDER BY t.col1) = t.denserank
                         THEN @a
                         ELSE @a+1 END AS [whatiwant]
        FROM
        (
            SELECT col1, col2, DENSE_RANK() OVER (ORDER BY COL2) AS [denserank]
            FROM [table1]
        ) t
        ORDER BY t.col1
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-05-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-03
          • 1970-01-01
          相关资源
          最近更新 更多