SQL Server排名问题

时间:2017-03-15 13:49:08

标签: sql-server sql-server-2014 ranking-functions

我正在尝试将排名应用于我的数据集,逻辑如下:

对于每个ID,按ID2 ASC排序和按IsMaster Desc排序对第1行进行排名,仅在ID4值更改时更改

我的数据集和所需的输出如下:

desired output]

测试数据

' 0 1\n0 a 0,1\n1 b 0,2\n'

这是我到目前为止所尝试的:

CREATE TABLE Test_Table 
(ID INT ,ID2 INT, IsMaster INT, ID4 VARCHAR(10))
GO

INSERT INTO Test_Table  (ID ,ID2 , IsMaster , ID4 )
VALUES 
 (1,    101,    1   ,'AAA')  -- 1  <-- Desired output for rank
,(1,    102,    0   ,'AAA')  -- 1
,(1,    103,    0   ,'AAB')  -- 2
,(1,    104,    0   ,'AAB')  -- 2
,(1,    105,    0   ,'CCC')  -- 3
,(2,    101,    1   ,'AAA')  -- 1
,(2,    102,    0   ,'AAA')  -- 1
,(2,    103,    0   ,'AAA')  -- 1
,(2,    104,    0   ,'AAB')  -- 2
,(2,    105,    0   ,'CCC')  -- 3
请帮助我,谢谢。

4 个答案:

答案 0 :(得分:3)

这是岛屿/缺口问题。

  • 首先使用LAG()查看同一分区上是否有不同的ID4。
    • 重要的是,您还需要partition by IsMaster
  • 然后在ID4更改时创建islands
  • 最后使用推理SUM()来获得正确的排名。

<强> Sql Demo

WITH id4_change as (
    SELECT  *, 
            LAG(ID4) OVER (PARTITION BY ID, IsMaster ORDER BY ID2) as prev
    FROM Test_Table
), islands as (
    SELECT *, 
           CASE WHEN ID4 = PREV 
                THEN 0 
                ELSE 1 
           END as island
    FROM id4_change
) 
SELECT *,
       SUM(island) OVER (PARTITION BY ID, IsMaster ORDER BY ID2) rank
FROM islands       
ORDER BY ID, ID2, IsMaster DESC
;

输出:您可以看到ID4 = PREV何时未创建新的"Island",因此具有相同的排名。

enter image description here

编辑:您可以简化前两个查询

WITH id4_change as (
    SELECT  *, 
            CASE WHEN ID4 = LAG(ID4) OVER (PARTITION BY ID, IsMaster ORDER BY ID2)
                 THEN 0
                 ELSE 1
            END as island
    FROM Test_Table
) 
SELECT *,
       SUM(island) OVER (PARTITION BY ID, IsMaster ORDER BY ID2) rank
FROM id4_change       
ORDER BY ID, ID2, IsMaster DESC
;

答案 1 :(得分:1)

这可以使用当前输入集获得所需的输出:

SELECT *
    ,DENSE_RANK() OVER (PARTITION BY ID  ORDER BY ID4 ASC ) rn
FROM Test_Table

您的密集排名基于ID4列,该列具有重复项,而不是ID2列,它看起来是唯一的。如果数据的排序方式不同,这将无效,因此为了进行调整,您需要为最终语句包含ORDER BY子句,如下所示:

CREATE TABLE Test_Table 
(ID INT ,ID2 INT, IsMaster INT, ID4 VARCHAR(10))
GO

INSERT INTO Test_Table  (ID ,ID2 , IsMaster , ID4 )
VALUES 
 (1,    102,    0   ,'AAA')  -- 1
,(1,    103,    0   ,'AAB')  -- 2
,(1,    104,    0   ,'AAB')  -- 2
,(1,    105,    0   ,'CCC')  -- 3
,(2,    102,    0   ,'AAA')  -- 1
,(2,    103,    0   ,'AAA')  -- 1
,(2,    104,    0   ,'AAB')  -- 2
,(2,    105,    0   ,'CCC')  -- 3
,(1,    101,    1   ,'AAA')  -- 1  <-- Reordered inputs
,(2,    101,    1   ,'AAA')  -- 1

SELECT *
    ,DENSE_RANK() OVER (PARTITION BY ID  ORDER BY ID4 ASC ) rn
FROM Test_Table
ORDER BY ID, rn, IsMaster DESC

答案 2 :(得分:1)

另一种可能效率较低但可行的方法。

WITH X AS
(
 SELECT *
       ,ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID2) RowNum
 FROM dbo.Test_Table
)
, CTE_VehicleNumber
as
(
    SELECT  T.ID , T.ID2, t.IsMaster ,T.ID4 , t.RowNum  , 1 as [Rank]
    FROM X  as T
    WHERE T.IsMaster = 1 

    UNION ALL

    SELECT  T.ID, T.ID2, t.IsMaster ,T.ID4 , t.RowNum , CASE WHEN t.ID4 <> c.ID4 THEN 1+ C.[Rank]
                                                              ELSE 0+ C.[Rank]
                                                         END  as [Rank]
    FROM CTE_VehicleNumber as C
        inner join X  as T ON T.RowNum = C.RowNum + 1
                                              AND t.ID = c.ID
)
SELECT ID , ID2, IsMaster ,ID4  , [Rank] 
FROM CTE_VehicleNumber 
ORDER BY ID , ID2, IsMaster ,ID4  , [Rank]
OPTION (MAXRECURSION 0);

答案 3 :(得分:0)

考虑到ID2IsMaster中的其他数据,您确定IDID4的订单会影响所需的结果吗?

我刚尝试使用以下代码:

; WITH CTE AS (
    SELECT DISTINCT ID, ID4, DENSE_RANK() OVER (ORDER BY ID4) Rnk
    FROM #Test_Table
)
SELECT t.*, c.Rnk
FROM #Test_Table t
    INNER JOIN CTE c ON t.ID = c.ID AND t.ID4 = c.ID4;

...即使更改了ID2IsMaster的顺序,我也无法将其变为“行为不端” - IF 只有一个{{1} } IsMaster = 1的{​​{1}}组中没有重复项。{/ 1}。