SQL Rank()函数排除行

时间:2016-10-05 10:09:06

标签: sql sql-server window-functions

考虑我有下表。

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

5 个答案:

答案 0 :(得分:6)

如果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;

答案 1 :(得分:0)

目前没有办法在密集排名中排除Val,除非你在where子句中过滤..这就是原因,你得到的结果

sortSelect(document.getElementsByName("options"));

您需要过滤一次然后再进行联合

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

答案 2 :(得分:0)

你也可以试试这个:

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

答案 3 :(得分:0)

您可以将排名拆分为对要包含/排除在排名中的值的单独查询以及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

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

答案 4 :(得分:0)

原始问题中的解决方案实际上非常接近。只需在density_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”会为density_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