【问题标题】:Calculating SQL Server ROW_NUMBER() OVER() for a derived table为派生表计算 SQL Server ROW_NUMBER() OVER()
【发布时间】:2013-09-28 11:58:52
【问题描述】:

在其他一些数据库(例如 DB2 或带有 ROWNUM 的 Oracle)中,我可以在排名函数的 OVER() 子句中省略 ORDER BY 子句。例如:

ROW_NUMBER() OVER()

这在与有序派生表一起使用时特别有用,例如:

SELECT t.*, ROW_NUMBER() OVER()
FROM (
    SELECT ...
    ORDER BY
) t

如何在 SQL Server 中进行模拟?我发现有人使用thistrick,但这是错误的,因为它对于派生表中的顺序的行为是不确定的:

-- This order here ---------------------vvvvvvvv
SELECT t.*, ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM (
    SELECT TOP 100 PERCENT ...
    -- vvvvv ----redefines this order here
    ORDER BY
) t

一个具体的例子(可以在SQLFiddle上看到):

SELECT v, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN
FROM (
  SELECT TOP 100 PERCENT 1 UNION ALL
  SELECT TOP 100 PERCENT 2 UNION ALL
  SELECT TOP 100 PERCENT 3 UNION ALL
  SELECT TOP 100 PERCENT 4
  -- This descending order is not maintained in the outer query
  ORDER BY 1 DESC
) t(v)

此外,在我的情况下,我无法重用派生表中的任何表达式来重现 ORDER BY 子句,因为派生表可能不可用,因为它可能由某些外部逻辑提供。

那我该怎么做呢?我能做到吗?

【问题讨论】:

  • SELECT NULL 怎么样?它还会给出无效的结果吗?
  • @491243:是的。好吧,结果显然是“有效的”,但我想知道空 OVER() 的行为是否真的定义明确,或者这是否在 DB2 上巧合......我将准备一个 SQL Fiddle 来说明这个
  • 您需要将 row_number 放在内部查询中,所以如果您无法修改,我认为您不走运。
  • @Laurence:有两个问题。 1)我不一定有权访问内部查询,2)内部查询可能包含DISTINCT,如果添加ROW_NUMBER()会改变内部查询的语义。
  • 嗯,我也是认为的。但我想知道 ;-)

标签: sql sql-server tsql window-functions ranking-functions


【解决方案1】:

Row_Number() OVER (ORDER BY (SELECT 1)) 技巧应该被视为避免更改基础数据顺序的一种方式。这只是一种避免导致服务器执行额外且不需要的排序的方法(它可能仍会执行排序,但与按列排序相比,它会花费尽可能少的费用)。

SQL 服务器中的所有查询绝对必须在最外层的查询中有一个ORDER BY 子句,以保证以可靠的方式对结果进行排序。

关系型数据库中不存在“保留原顺序”的概念。必须始终将表和查询视为无序,除非在最外层查询中指定了 ORDER BY 子句。

您可以尝试相同的无序查询 100,000 次并始终以相同的顺序接收它,因此相信您可以依赖所述的顺序。但这将是一个错误,因为有一天,某些事情会发生变化,并且不会按照您期望的顺序进行。一个例子是当数据库升级到新版本的 SQL Server 时——这会导致许多查询更改其顺序。但它不必有那么大的变化。像添加或删除索引这样的小事都可能导致差异。还有更多:安装服务包。对表进行分区。创建包含相关表的索引视图。达到选择扫描而不是搜索的临界点。以此类推。

除非您说“服务器,ORDER BY”,否则不要依赖结果进行排序。

【讨论】:

  • 我不完全同意你的评价。以 Oracle 的ROWNUM 为例。在某种程度上,它保证在每一行上产生实际的行号是相当神奇的。这使它成为一个非常不相关的伪列,因为它可以在“语义具有挑战性”的情况下访问,例如WHERE 子句。一个类似的“奇怪”Oracle 特性是FOR UPDATE SKIP LOCKED,它与 SQL 子句语义相反。但无论如何,SQL 并不是 100% 关系型的,所以我认为可能有一种类似的、可靠的方式来访问 SQL Server 中给定表引用的具体、物化元组顺序。
  • 不幸的是,Lukas,我不知道如何获得“原始餐桌顺序”。 Oracle 确实提供了一些有用的功能真是太好了,所以我可能夸大了所有关系数据库的情况。不过,我确实相信我已经为 SQL Server 做好了准备(当然,如有必要,我随时准备进行更正)。
  • 如果您需要原始表格顺序,请使用表格中指定顺序的列,然后按该顺序进行排序。在 SQL Server 中,如果您按聚集索引或非聚集索引排序并且只选择该索引中的列,则它不会执行排序操作。因此,它与“自然”顺序相同(即没有额外的处理工作)。
  • Erik,是的,恐怕您已经为 SQL Server 做好了准备 :-) 我注意到在对此类 SQL 功能强加清晰的语义方面是多么严格,这可能是很好,主要是。 @siride:我想你可能没有完全理解我的问题。
猜你喜欢
  • 2011-12-10
  • 1970-01-01
  • 2016-01-09
  • 2018-10-16
  • 2019-04-13
  • 2021-08-20
  • 1970-01-01
  • 2012-01-31
  • 1970-01-01
相关资源
最近更新 更多