SQL 数字 - Row_Number() - 允许重复行号
SQL Number - Row_Number() - Allow Repeating Row Number
我正在使用 SQL Server 2008。我在一个查询中返回了这些数据,看起来很像按 Day 和 ManualOrder 排序...
ID Day ManualOrder Lat Lon
1 Mon 0 36.55 36.55
5 Mon 1 55.55 54.44
3 Mon 2 44.33 44.30
10 Mon 3 36.55 36.55
11 Mon 4 36.55 36.55
6 Mon 5 20.22 22.11
9 Mon 6 55.55 54.44
10 Mon 7 88.99 11.22
77 Sun 0 23.33 11.11
77 Sun 1 23.33 11.11
我想要做的是让这些数据按天排序,然后按 ManualOrder...但我想要一个行计数器(我们称它为 MapPinNumber)。问题是我希望这个行计数器在同一天再次遇到相同的 Lat/Lon 时重复。然后它可以继续使用下一行的下一行计数器,如果它是不同的 lat/lon。我们必须在最终结果中维护 Day、ManualOrder 排序。
我会在地图上绘制这些,这个数字应该代表我将在 ManualOrder 顺序中绘制的 pin 号。此数据表示驾驶员的路线,他可能会在一天中多次前往相同的 lat/lon。例如,他开车去沃尔玛,然后是 CVS,然后又回到沃尔玛,最后是沃尔格林。我需要的 MapPinNumber 列应该是 1、2、1、3。由于他周一多次去沃尔玛,但那也是他开车的第一个地方,因此它始终是地图上的 #1。
这是我需要计算的 MapPinNumber 列的结果。我已经用 ROW_NUMBER 和 RANK 尝试了所有我能想到的方法,并且发疯了!我尽量避免使用难看的 CURSOR。
ID Day ManualOrder Lat Lon MapPinNumber
1 Mon 0 36.55 36.55 1
5 Mon 1 55.55 54.44 2
3 Mon 2 44.33 44.30 3
10 Mon 3 36.55 36.55 1
11 Mon 4 36.55 36.55 1
6 Mon 5 20.22 22.11 4
9 Mon 6 55.55 54.44 2
10 Mon 7 88.99 11.22 5
77 Sun 0 23.33 11.11 1
77 Sun 1 23.33 11.11 1
这可能不是最优雅的解决方案,但它有效:
Select a.*, b.MapPinOrder from MyTable a
left join
(
select distinct Day, Lat, Lon
, row_number()
over (partition by Day order by min(ManualOrder)) as MapPinOrder
from MyTable
group by Day, Lat, Lon
) b
on a.day = b.day
and a.lat = b.lat
and a.lon = b.lon
使用您想要的顺序分别计算行,然后将它们重新加入完整 table。
这是我尝试使用 ROW_NUMBER
:
WITH CteRN AS(
SELECT *,
Rn = ROW_NUMBER() OVER(PARTITION BY Day ORDER BY ManualOrder),
Grp = ROW_NUMBER() OVER(PARTITION BY Day, Lat, Lon ORDER BY ManualOrder)
FROM tbl
),
CteBase AS(
SELECT *,
N = ROW_NUMBER() OVER(PARTITION BY Day ORDER BY ManualOrder)
FROM CteRN
WHERE Grp = 1
)
SELECT
r.ID, r.Day, r.ManualOrder, r.Lat, r.Lon,
MapPinNumber = ISNULL(b.N, r.RN)
FROM CteRN r
LEFT JOIN CteBase b
ON b.Day = r.Day
AND b.Lat = r.Lat
AND b.Lon = r.Lon
ORDER BY
r.Day, r.ManualOrder
您可以将聚合函数 MIN
与 OVER
结合使用来创建排名组,然后 DENSE_RANK
像这样在其基础上工作。
简要说明
MIN(ManualOrder)OVER(PARTITION BY Day,Lat,Lon)
得到 Day
、Lat
和 Lon
.
组合的最小值 ManualOrder
DENSE_RANK()
只是将此值设置为 1
.
的增量值
示例数据
CREATE TABLE Tbl ([ID] int, [Day] varchar(3), [ManualOrder] int, [Lat] int, [Lon] int);
INSERT INTO Tbl ([ID], [Day], [ManualOrder], [Lat], [Lon])
VALUES
(1, 'Mon', 0, 36.55, 36.55),
(5, 'Mon', 1, 55.55, 54.44),
(3, 'Mon', 2, 44.33, 44.30),
(10, 'Mon', 3, 36.55, 36.55),
(11, 'Mon', 4, 36.55, 36.55),
(6, 'Mon', 5, 20.22, 22.11),
(9, 'Mon', 6, 55.55, 54.44),
(10, 'Mon', 7, 88.99, 11.22),
(77, 'Sun', 0, 23.33, 11.11),
(77, 'Sun', 1, 23.33, 11.11);
查询
;WITH CTE AS
(
SELECT *,GRP = MIN(ManualOrder)OVER(PARTITION BY Day,Lat,Lon) FROM Tbl
)
SELECT ID,Day,ManualOrder,Lat,Lon,DENSE_RANK()OVER(PARTITION BY Day ORDER BY GRP) AS RN
FROM CTE
ORDER BY Day,ManualOrder
输出
ID Day ManualOrder Lat Lon RN
1 Mon 0 36.55 36.55 1
5 Mon 1 55.55 54.44 2
3 Mon 2 44.33 44.30 3
10 Mon 3 36.55 36.55 1
11 Mon 4 36.55 36.55 1
6 Mon 5 20.22 22.11 4
9 Mon 6 55.55 54.44 2
10 Mon 7 88.99 11.22 5
77 Sun 0 23.33 11.11 1
77 Sun 1 23.33 11.11 1
这将为您提供所需的结果。但是,MapPinNumber
的顺序可能与您的结果中显示的顺序不完全相同。
SELECT *,
MapPinNumber = DENSE_RANK() OVER (PARTITION BY Day ORDER BY Lat, Lon)
FROM Table1
ORDER BY Day, ManualOrder
我正在使用 SQL Server 2008。我在一个查询中返回了这些数据,看起来很像按 Day 和 ManualOrder 排序...
ID Day ManualOrder Lat Lon
1 Mon 0 36.55 36.55
5 Mon 1 55.55 54.44
3 Mon 2 44.33 44.30
10 Mon 3 36.55 36.55
11 Mon 4 36.55 36.55
6 Mon 5 20.22 22.11
9 Mon 6 55.55 54.44
10 Mon 7 88.99 11.22
77 Sun 0 23.33 11.11
77 Sun 1 23.33 11.11
我想要做的是让这些数据按天排序,然后按 ManualOrder...但我想要一个行计数器(我们称它为 MapPinNumber)。问题是我希望这个行计数器在同一天再次遇到相同的 Lat/Lon 时重复。然后它可以继续使用下一行的下一行计数器,如果它是不同的 lat/lon。我们必须在最终结果中维护 Day、ManualOrder 排序。
我会在地图上绘制这些,这个数字应该代表我将在 ManualOrder 顺序中绘制的 pin 号。此数据表示驾驶员的路线,他可能会在一天中多次前往相同的 lat/lon。例如,他开车去沃尔玛,然后是 CVS,然后又回到沃尔玛,最后是沃尔格林。我需要的 MapPinNumber 列应该是 1、2、1、3。由于他周一多次去沃尔玛,但那也是他开车的第一个地方,因此它始终是地图上的 #1。
这是我需要计算的 MapPinNumber 列的结果。我已经用 ROW_NUMBER 和 RANK 尝试了所有我能想到的方法,并且发疯了!我尽量避免使用难看的 CURSOR。
ID Day ManualOrder Lat Lon MapPinNumber
1 Mon 0 36.55 36.55 1
5 Mon 1 55.55 54.44 2
3 Mon 2 44.33 44.30 3
10 Mon 3 36.55 36.55 1
11 Mon 4 36.55 36.55 1
6 Mon 5 20.22 22.11 4
9 Mon 6 55.55 54.44 2
10 Mon 7 88.99 11.22 5
77 Sun 0 23.33 11.11 1
77 Sun 1 23.33 11.11 1
这可能不是最优雅的解决方案,但它有效:
Select a.*, b.MapPinOrder from MyTable a
left join
(
select distinct Day, Lat, Lon
, row_number()
over (partition by Day order by min(ManualOrder)) as MapPinOrder
from MyTable
group by Day, Lat, Lon
) b
on a.day = b.day
and a.lat = b.lat
and a.lon = b.lon
使用您想要的顺序分别计算行,然后将它们重新加入完整 table。
这是我尝试使用 ROW_NUMBER
:
WITH CteRN AS(
SELECT *,
Rn = ROW_NUMBER() OVER(PARTITION BY Day ORDER BY ManualOrder),
Grp = ROW_NUMBER() OVER(PARTITION BY Day, Lat, Lon ORDER BY ManualOrder)
FROM tbl
),
CteBase AS(
SELECT *,
N = ROW_NUMBER() OVER(PARTITION BY Day ORDER BY ManualOrder)
FROM CteRN
WHERE Grp = 1
)
SELECT
r.ID, r.Day, r.ManualOrder, r.Lat, r.Lon,
MapPinNumber = ISNULL(b.N, r.RN)
FROM CteRN r
LEFT JOIN CteBase b
ON b.Day = r.Day
AND b.Lat = r.Lat
AND b.Lon = r.Lon
ORDER BY
r.Day, r.ManualOrder
您可以将聚合函数 MIN
与 OVER
结合使用来创建排名组,然后 DENSE_RANK
像这样在其基础上工作。
简要说明
组合的最小值MIN(ManualOrder)OVER(PARTITION BY Day,Lat,Lon)
得到Day
、Lat
和Lon
.ManualOrder
DENSE_RANK()
只是将此值设置为1
. 的增量值
示例数据
CREATE TABLE Tbl ([ID] int, [Day] varchar(3), [ManualOrder] int, [Lat] int, [Lon] int);
INSERT INTO Tbl ([ID], [Day], [ManualOrder], [Lat], [Lon])
VALUES
(1, 'Mon', 0, 36.55, 36.55),
(5, 'Mon', 1, 55.55, 54.44),
(3, 'Mon', 2, 44.33, 44.30),
(10, 'Mon', 3, 36.55, 36.55),
(11, 'Mon', 4, 36.55, 36.55),
(6, 'Mon', 5, 20.22, 22.11),
(9, 'Mon', 6, 55.55, 54.44),
(10, 'Mon', 7, 88.99, 11.22),
(77, 'Sun', 0, 23.33, 11.11),
(77, 'Sun', 1, 23.33, 11.11);
查询
;WITH CTE AS
(
SELECT *,GRP = MIN(ManualOrder)OVER(PARTITION BY Day,Lat,Lon) FROM Tbl
)
SELECT ID,Day,ManualOrder,Lat,Lon,DENSE_RANK()OVER(PARTITION BY Day ORDER BY GRP) AS RN
FROM CTE
ORDER BY Day,ManualOrder
输出
ID Day ManualOrder Lat Lon RN
1 Mon 0 36.55 36.55 1
5 Mon 1 55.55 54.44 2
3 Mon 2 44.33 44.30 3
10 Mon 3 36.55 36.55 1
11 Mon 4 36.55 36.55 1
6 Mon 5 20.22 22.11 4
9 Mon 6 55.55 54.44 2
10 Mon 7 88.99 11.22 5
77 Sun 0 23.33 11.11 1
77 Sun 1 23.33 11.11 1
这将为您提供所需的结果。但是,MapPinNumber
的顺序可能与您的结果中显示的顺序不完全相同。
SELECT *,
MapPinNumber = DENSE_RANK() OVER (PARTITION BY Day ORDER BY Lat, Lon)
FROM Table1
ORDER BY Day, ManualOrder