SQL Row_Number() (Partition by... Order By...) IGNORES Order 语句
SQL Row_Number() (Partition by… Order By…) IGNORES Order statement
我找不到支持我尝试实现的功能的函数。
假设我们有以下 table,其中包含字段排序顺序和某些重复项
+----------+----------+-----+-------------+-----------+
| UniqueId | Id | Qty | RetailPrice | SortOrder |
+----------+----------+-----+-------------+-----------+
| 3124 | 92361725 | 25 | 269.99 | 1 |
| 2627 | 92361725 | 25 | 269.99 | 2 |
| 7635 | 92361725 | 25 | 269.99 | 3 |
| 8732 | 92361725 | 25 | 269.99 | 4 |
| 3791 | 92361725 | 20 | 269.99 | 5 |
| 4328 | 92361725 | 25 | 269.99 | 6 |
+----------+----------+-----+-------------+-----------+
我想枚举我的行,在发现重复项时增加它们的值,如果没有,则重置行号。如果 Qty 是要评估的列,则结果必须显示在以下 table 列 rn 中:
+----------+----------+-----+-------------+-----------+----+
| UniqueId | Id | Qty | RetailPrice | SortOrder | rn |
+----------+----------+-----+-------------+-----------+----+
| 3124 | 92361725 | 25 | 269.99 | 1 | 1 |
| 2627 | 92361725 | 25 | 269.99 | 2 | 2 |
| 7635 | 92361725 | 25 | 269.99 | 3 | 3 |
| 8732 | 92361725 | 25 | 269.99 | 4 | 4 |
| 3791 | 92361725 | 20 | 269.99 | 5 | 1 |
| 4328 | 92361725 | 25 | 269.99 | 6 | 1 |
+----------+----------+-----+-------------+-----------+----+
我尝试使用 ROW_NUMBER() 函数,但无法得到我想要的结果
;WITH Table1 AS(
SELECT 3124 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 1 SortOrder UNION ALL
SELECT 2627 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 2 SortOrder UNION ALL
SELECT 7635 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 3 SortOrder UNION ALL
SELECT 8732 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 4 SortOrder UNION ALL
SELECT 3791 UniqueId,92361725 Id, 20 Qty, 269.99 RetailPrice, 5 SortOrder UNION ALL
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 6 SortOrder
)
SELECT UniqueId, Id, Qty, RetailPrice, SortOrder,
ROW_NUMBER() OVER (PARTITION BY Qty ORDER BY SortOrder) rn
FROM Table1
+----------+----------+-----+-------------+-----------+----+
| UniqueId | Id | Qty | RetailPrice | SortOrder | rn |
+----------+----------+-----+-------------+-----------+----+
| 3791 | 92361725 | 20 | 269.99 | 5 | 1 |
| 3124 | 92361725 | 25 | 269.99 | 1 | 1 |
| 2627 | 92361725 | 25 | 269.99 | 2 | 2 |
| 7635 | 92361725 | 25 | 269.99 | 3 | 3 |
| 8732 | 92361725 | 25 | 269.99 | 4 | 4 |
| 4328 | 92361725 | 25 | 269.99 | 6 | 5 |
+----------+----------+-----+-------------+-----------+----+
Order By 完全被忽略了,有人可以帮忙吗?
给你。因为你是在 2008 年,所以我通过在 SortOrder +/- 1 上自我加入这个 table 来复制 Lead 和 Lag。我还更新了你的样本集以说明数量为 25 的新岛屿。
抱歉文字太长,但我必须更新您的示例集以向岛屿 3 添加 2 行并创建 2 个 CTE 以获得岛屿范围。
--Updates Sample Set with 3 Islands.
WITH Table1 AS(
SELECT 3124 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 1 SortOrder UNION ALL --Island 1
SELECT 2627 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 2 SortOrder UNION ALL --Island 1
SELECT 7635 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 3 SortOrder UNION ALL --Island 1
SELECT 8732 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 4 SortOrder UNION ALL --Island 1
SELECT 3791 UniqueId,92361725 Id, 20 Qty, 269.99 RetailPrice, 5 SortOrder UNION ALL --Island 2
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 6 SortOrder UNION ALL --Island 3
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 7 SortOrder UNION ALL --Island 3
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 8 SortOrder --Island 3
),
--Creating a CTE to get the Lead and Lag since this is 2008. This will allow us to determine if a row is the first or last row of an island.
LeadLagTable AS(
SELECT
Table1.UniqueId,
Table1.Id,
Table1.Qty,
Table1.RetailPrice,
Table1.SortOrder,
LeadTable.SortOrder AS LeadSortOrder,
LagTable.SortOrder AS LagSortOrder,
CASE
WHEN LagTable.SortOrder IS NULL THEN 1
ELSE 0
END AS StartRowFlag,
CASE
WHEN LeadTable.SortOrder IS NULL THEN 1
ELSE 0
END AS LastRowFlag
FROM Table1
LEFT JOIN Table1 LeadTable ON
Table1.SortOrder = LeadTable.SortOrder - 1
AND Table1.Qty = LeadTable.Qty
LEFT JOIN Table1 LagTable ON
Table1.SortOrder = LagTable.SortOrder + 1
AND Table1.Qty = LagTable.Qty
),
--With the LeadLagTable we can now get the ranges for each island, as well as a unique ID for each island.
Ranges AS (
SELECT
RangeStart,
RangeEnd,
ROW_NUMBER() OVER (ORDER BY RangeStart) AS RangeRowNum
FROM (
SELECT
StartRow.SortOrder AS RangeStart,
EndRow.SortOrder RangeEnd,
ROW_NUMBER() OVER (PARTITION BY StartRow.SortOrder ORDER BY EndRow.SortOrder) AS rn
FROM LeadLagTable StartRow
JOIN LeadLagTable EndRow ON
StartRow.StartRowFlag = 1
AND EndRow.LastRowFlag = 1
AND StartRow.SortOrder <= EndRow.SortOrder
AND StartRow.Qty = EndRow.Qty
) tbl
WHERE rn = 1
)
这是实际的查询。
--We now join on the island ranges, and partition by the Island ID.
SELECT
UniqueId,
Id,
Qty,
RetailPrice,
SortOrder,
ROW_NUMBER() OVER (PARTITION BY RangeRowNum ORDER BY SortOrder) AS rn
FROM Table1
LEFT JOIN Ranges ON
Table1.SortOrder >= Ranges.RangeStart
AND Table1.SortOrder <= Ranges.RangeEnd
我找不到支持我尝试实现的功能的函数。
假设我们有以下 table,其中包含字段排序顺序和某些重复项
+----------+----------+-----+-------------+-----------+ | UniqueId | Id | Qty | RetailPrice | SortOrder | +----------+----------+-----+-------------+-----------+ | 3124 | 92361725 | 25 | 269.99 | 1 | | 2627 | 92361725 | 25 | 269.99 | 2 | | 7635 | 92361725 | 25 | 269.99 | 3 | | 8732 | 92361725 | 25 | 269.99 | 4 | | 3791 | 92361725 | 20 | 269.99 | 5 | | 4328 | 92361725 | 25 | 269.99 | 6 | +----------+----------+-----+-------------+-----------+
我想枚举我的行,在发现重复项时增加它们的值,如果没有,则重置行号。如果 Qty 是要评估的列,则结果必须显示在以下 table 列 rn 中:
+----------+----------+-----+-------------+-----------+----+ | UniqueId | Id | Qty | RetailPrice | SortOrder | rn | +----------+----------+-----+-------------+-----------+----+ | 3124 | 92361725 | 25 | 269.99 | 1 | 1 | | 2627 | 92361725 | 25 | 269.99 | 2 | 2 | | 7635 | 92361725 | 25 | 269.99 | 3 | 3 | | 8732 | 92361725 | 25 | 269.99 | 4 | 4 | | 3791 | 92361725 | 20 | 269.99 | 5 | 1 | | 4328 | 92361725 | 25 | 269.99 | 6 | 1 | +----------+----------+-----+-------------+-----------+----+
我尝试使用 ROW_NUMBER() 函数,但无法得到我想要的结果
;WITH Table1 AS(
SELECT 3124 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 1 SortOrder UNION ALL
SELECT 2627 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 2 SortOrder UNION ALL
SELECT 7635 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 3 SortOrder UNION ALL
SELECT 8732 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 4 SortOrder UNION ALL
SELECT 3791 UniqueId,92361725 Id, 20 Qty, 269.99 RetailPrice, 5 SortOrder UNION ALL
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 6 SortOrder
)
SELECT UniqueId, Id, Qty, RetailPrice, SortOrder,
ROW_NUMBER() OVER (PARTITION BY Qty ORDER BY SortOrder) rn
FROM Table1
+----------+----------+-----+-------------+-----------+----+ | UniqueId | Id | Qty | RetailPrice | SortOrder | rn | +----------+----------+-----+-------------+-----------+----+ | 3791 | 92361725 | 20 | 269.99 | 5 | 1 | | 3124 | 92361725 | 25 | 269.99 | 1 | 1 | | 2627 | 92361725 | 25 | 269.99 | 2 | 2 | | 7635 | 92361725 | 25 | 269.99 | 3 | 3 | | 8732 | 92361725 | 25 | 269.99 | 4 | 4 | | 4328 | 92361725 | 25 | 269.99 | 6 | 5 | +----------+----------+-----+-------------+-----------+----+
Order By 完全被忽略了,有人可以帮忙吗?
给你。因为你是在 2008 年,所以我通过在 SortOrder +/- 1 上自我加入这个 table 来复制 Lead 和 Lag。我还更新了你的样本集以说明数量为 25 的新岛屿。
抱歉文字太长,但我必须更新您的示例集以向岛屿 3 添加 2 行并创建 2 个 CTE 以获得岛屿范围。
--Updates Sample Set with 3 Islands.
WITH Table1 AS(
SELECT 3124 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 1 SortOrder UNION ALL --Island 1
SELECT 2627 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 2 SortOrder UNION ALL --Island 1
SELECT 7635 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 3 SortOrder UNION ALL --Island 1
SELECT 8732 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 4 SortOrder UNION ALL --Island 1
SELECT 3791 UniqueId,92361725 Id, 20 Qty, 269.99 RetailPrice, 5 SortOrder UNION ALL --Island 2
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 6 SortOrder UNION ALL --Island 3
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 7 SortOrder UNION ALL --Island 3
SELECT 4328 UniqueId,92361725 Id, 25 Qty, 269.99 RetailPrice, 8 SortOrder --Island 3
),
--Creating a CTE to get the Lead and Lag since this is 2008. This will allow us to determine if a row is the first or last row of an island.
LeadLagTable AS(
SELECT
Table1.UniqueId,
Table1.Id,
Table1.Qty,
Table1.RetailPrice,
Table1.SortOrder,
LeadTable.SortOrder AS LeadSortOrder,
LagTable.SortOrder AS LagSortOrder,
CASE
WHEN LagTable.SortOrder IS NULL THEN 1
ELSE 0
END AS StartRowFlag,
CASE
WHEN LeadTable.SortOrder IS NULL THEN 1
ELSE 0
END AS LastRowFlag
FROM Table1
LEFT JOIN Table1 LeadTable ON
Table1.SortOrder = LeadTable.SortOrder - 1
AND Table1.Qty = LeadTable.Qty
LEFT JOIN Table1 LagTable ON
Table1.SortOrder = LagTable.SortOrder + 1
AND Table1.Qty = LagTable.Qty
),
--With the LeadLagTable we can now get the ranges for each island, as well as a unique ID for each island.
Ranges AS (
SELECT
RangeStart,
RangeEnd,
ROW_NUMBER() OVER (ORDER BY RangeStart) AS RangeRowNum
FROM (
SELECT
StartRow.SortOrder AS RangeStart,
EndRow.SortOrder RangeEnd,
ROW_NUMBER() OVER (PARTITION BY StartRow.SortOrder ORDER BY EndRow.SortOrder) AS rn
FROM LeadLagTable StartRow
JOIN LeadLagTable EndRow ON
StartRow.StartRowFlag = 1
AND EndRow.LastRowFlag = 1
AND StartRow.SortOrder <= EndRow.SortOrder
AND StartRow.Qty = EndRow.Qty
) tbl
WHERE rn = 1
)
这是实际的查询。
--We now join on the island ranges, and partition by the Island ID.
SELECT
UniqueId,
Id,
Qty,
RetailPrice,
SortOrder,
ROW_NUMBER() OVER (PARTITION BY RangeRowNum ORDER BY SortOrder) AS rn
FROM Table1
LEFT JOIN Ranges ON
Table1.SortOrder >= Ranges.RangeStart
AND Table1.SortOrder <= Ranges.RangeEnd