【问题标题】:How to make ROW_NUMBER work with duplicate records?如何使 ROW_NUMBER 与重复记录一起工作?
【发布时间】:2015-06-24 16:08:15
【问题描述】:

我有一个包含重复事务记录的表。这些不是错误的重复项,但需要为它们分配值以使它们对表唯一。记录的用途是随着时间的推移按顺序查看它们,我使用 ROW_NUMBER 按 ID 和 ORDER BY Time 对它们进行分区。

有时它会起作用。有时会失败。

示例

CASE WHEN [Record] = 'Start' 
     THEN 0 
ELSE -1 + ROW_NUMBER() OVER(PARTITION BY [ID] ORDER BY [Date] DESC
END AS [RowNo]

预期结果

ID,   Date,  RowNo
2002, 12:30, 1
2002, 12:29, 2
2002, 12:29, 3
2002, 12:29, 4
2002, 12:28, 5
3212, 01:10, 1
3212, 01:09, 2
3212, 01:08, 3

实际结果

ID,   Date,  RowNo
2002, 12:30, 1
2002, 12:29, 2 <---Right
2002, 12:29, 2 <---Wrong
2002, 12:29, 3 <---Right
2002, 12:28, 4
3212, 01:10, 1
3212, 01:09, 2
3212, 01:08, 3

有没有更好的方法来确保准确性?

【问题讨论】:

  • 你确定你使用的是rownumber而不是rank,dense rank吗?行号以 1 开头。您没有向我们展示实际的语句...
  • 是的。那是我的错。实际上,我有一个 CASE 语句,其原始代码根据示例中未显示的另一个字段将第一条记录从 1 更改为 0。
  • 显示实际代码。您当前的代码应该可以工作...
  • 更新清晰。
  • 仍然很难判断出了什么问题。您能否提供一些数据以便我们重现该行为?

标签: sql-server sql-server-2008 tsql


【解决方案1】:

嗯。 ROW_NUMBER() 确实适用于重复记录。 (当有重复时,不确定哪一行会得到哪个值。)

您的陈述中还有其他内容,但没有显示出来。一个连接操作,一个 GROUP BY,一些额外的过滤。我们不知道那是什么,但我们知道 ROW_NUMBER() 确实可以处理重复项。


编辑

这很可疑:

CASE WHEN [Record] = 'Start' 
    THEN 0 
ELSE -1 + ROW_NUMBER() OVER(PARTITION BY [ID] ORDER BY [Date] DESC
END AS [RowNo]

我以前从未见过像这样的CASE 表达式中的分析函数。在我看来,ROW_NUMBER() 只会在 ELSE 的上下文中进行评估。 (我不确定 SQL Server 是如何实际处理的。)

如果我希望 RowNo 为 0、1、2、...我只需减去 1...

ROW_NUMBER() OVER(PARTITION BY [ID] ORDER BY [Date] DESC) - 1 AS RowNo

如果需要将[Record] = 'Start' 上的条件作为ROW_NUMBER 评估的一部分,那么我会将其包含在PARTITION

  OVER(PARTITION BY [ID],CASE WHEN [Record]='Start' THEN 0 END ORDER BY ...) 

如果我需要操作 ROW_NUMBER() 返回的值,我会找到一种方法来在内联视图或 CTE 的上下文中对其进行评估,以评估并返回该值,并且 然后在外部查询中使用返回值。

关键是ROW_NUMBER() 可以很好地处理重复项。如果你得到了你不期望的结果,那是因为语句中还有其他的东西,比如那个 CASE 表达式,或者一个连接,或者什么。

【讨论】:

  • 我在 UPDATE SELECT 语句中使用它。可能是当记录加入表时,重复的记录正在更新,而不是具有正确 ROW_COUNT 的实际唯一记录。那是因为我在技术上是在重复项之上加入重复项。
  • 哦,我不知道你可以在 Over 中放置一个 CASE。整洁的!但是,我假设 ROW_NUMBER 正在 ELSE 语句中应用于与 Case 条件不匹配的每条记录。它工作得很好。就像我上面所说的那样,我认为问题在于我将其应用于 UPDATE SELECT 语句,该语句将重复项加入重复项。这意味着 ROW_NUMBER 可能正确应用,这是粗略的 JOIN,因为 SQL 不知道要加入什么重复项。因此成败。
  • 标记这个是正确的,以帮助我得出正确的答案,首先解释 ROW_NUMBER 与重复项一起工作,然后帮助我确定这是我可能认为不是问题的代码中的问题,最后, 教我一些新东西。
【解决方案2】:

另一种获取每行唯一标识符的方法是使用 %%Physloc%%(或 SQL Server 2005 中的 %%lockres%%)虚拟列,它允许识别行的物理地址:

SELECT Id, Date, %%Physloc%%
FROM [your_table]

通过这种方式,对于大型表,您可以获得比 ROW_NUMBER 更好的性能。

【讨论】:

  • 我试试看。桌子很大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-22
  • 2016-02-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多