12

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

ROW_NUMBER() OVER()

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

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

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

-- 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子句,因为派生表可能不可用,因为它可能是由某些外部逻辑提供的。

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

4

1 回答 1

10

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

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

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

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

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

于 2013-09-23T17:48:24.257 回答