我正在尝试将排名应用于我的数据集,逻辑如下:
对于每个ID,按ID2 ASC排序和按IsMaster Desc排序对第1行进行排名,仅在ID4值更改时更改
我的数据集和所需的输出如下:
测试数据
' 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
请帮助我,谢谢。
答案 0 :(得分:3)
这是岛屿/缺口问题。
LAG()
查看同一分区上是否有不同的ID4。
partition by IsMaster
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"
,因此具有相同的排名。
编辑:您可以简化前两个查询
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)
考虑到ID2
和IsMaster
中的其他数据,您确定ID
和ID4
的订单会影响所需的结果吗?
我刚尝试使用以下代码:
; 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;
...即使更改了ID2
和IsMaster
的顺序,我也无法将其变为“行为不端” - IF 只有一个{{1} } IsMaster = 1
的{{1}}组中没有重复项。{/ 1}。