SQL Rank() 函数排除行

SQL Rank() function excluding rows

考虑一下我有以下 table。

ID  value
1   100
2   200
3   200
5   250
6   1

我有以下查询,结果如下。我想从 rank 函数中排除值 200,但仍然必须返回该行。

SELECT
CASE WHEN Value = 200 THEN 0
     ELSE DENSE_RANK() OVER ( ORDER BY VALUE DESC)
END AS RANK,
ID,
VALUE
FROM @table

RANK   ID   VALUE
1       5   250
0       2   200
0       3   200
4       1   100
5       6   1

但我想要的结果如下。如何实现?

RANK   ID   VALUE
1       5   250
0       2   200
0       3   200
2       1   100
3       6   1

目前无法排除 Dense Rank 中的 Val,除非你在 where 子句中过滤..这就是原因,你会得到低于结果

RANK   ID   VALUE
1       5   250
0       2   200
0       3   200
4       1   100
5       6   1

你需要先过滤一次,然后再做一个 union all

;with cte(id,val)
as
(
select 1,   100  union all
select 2,   200 union all
select 3,   200 union all
select 5,   250 union all
select 6,   1    )
select  *, dense_rank() over (order by val desc) 
 from cte
 where val<>200
union all
 select 0,id,val from cte where val=200

你也可以试试这个:

SELECT  ISNULL(R, 0) AS Rank ,t.id ,t.value
FROM    tbl1 AS t
    LEFT JOIN ( SELECT  id ,DENSE_RANK() OVER ( ORDER BY value DESC ) AS R
                FROM    dbo.tbl1 WHERE   value <> 200
              ) AS K 
   ON t.id = K.id
ORDER BY t.value DESC

您可以将排名拆分为您想要从排名中 include/exclude 的值的查询和 UNION ALL 结果,如下所示:

独立可执行示例:

CREATE TABLE #temp ( [ID] INT, [value] INT );

INSERT  INTO #temp
        ( [ID], [value] )
VALUES  ( 1, 100 ),
        ( 2, 200 ),
        ( 3, 200 ),
        ( 5, 250 ),
        ( 6, 1 );

SELECT  *
FROM    ( SELECT    0 RANK ,
                    ID ,
                    value
          FROM      #temp
          WHERE     value = 200  -- set rank to 0 for value = 200
          UNION ALL
          SELECT    DENSE_RANK() OVER ( ORDER BY value DESC ) AS RANK ,
                    ID ,
                    value
          FROM      #temp
          WHERE     value != 200  -- perform ranking on records != 200
        ) t
ORDER BY value DESC ,
        t.ID

DROP TABLE #temp

产生:

RANK    ID  value
1       5   250
0       2   200
0       3   200
2       1   100
3       6   1

如果需要,您可以修改语句末尾的顺序,我将其设置为产生您想要的结果。

如果 VAL 列不可为空,考虑到 NULL 是 ORDER BY .. DESC

中的最后一个值
select  *, dense_rank() over (order by nullif(val,200) desc) * case val when 200 then 0 else 1 end
from myTable
order by val desc;

原题的解其实很接近。只需在 dense_rank 中添加一个分区子句就可以解决问题。

SELECT    CASE
               WHEN VALUE = 200 THEN 0
               ELSE DENSE_RANK() OVER(
                    PARTITION BY CASE WHEN VALUE = 200 THEN 0 ELSE 1 END 
                    ORDER BY VALUE DESC
               )
          END AS RANK
          ,ID
          ,VALUE
FROM      @table
ORDER BY  VALUE DESC;

'partition by' 为 dense_rank 创建单独的组,以便单独对这些组执行订单。这实质上意味着您同时创建两个等级,一个用于没有 200 值的组,一个用于只有 200 值的组。后一个在'case when'.

中设置为0

独立可执行示例:

DECLARE @table TABLE
(
     ID     INT NOT NULL PRIMARY KEY
     ,VALUE INT     NULL
)

INSERT INTO @table
(
     ID
     ,VALUE
)
SELECT 1, 100
UNION SELECT 2, 200
UNION SELECT 3, 200
UNION SELECT 5, 250
UNION SELECT 6, 1;

SELECT    CASE
               WHEN VALUE = 200 THEN 0
               ELSE DENSE_RANK() OVER(
                    PARTITION BY CASE WHEN VALUE = 200 THEN 0 ELSE 1 END 
                    ORDER BY VALUE DESC
               )
          END AS RANK
          ,ID
          ,VALUE
FROM      @table
ORDER BY  VALUE DESC;
RANK    ID  VALUE
1   5   250
0   2   200
0   3   200
2   1   100
3   6   1