在 ROW_NUMBER() 上过滤会改变结果

Filtering on ROW_NUMBER() is changing the results

我确实实现了自己的 OData 服务,该服务采用 SQL 语句并使用 ROW_NUMBER() 应用顶部/跳过过滤器。到目前为止测试的大多数语句都运行良好,除了涉及 2 级 Left Join 的语句。出于某种我无法解释的原因,当我在行号列上应用 where 子句时,sql 返回的数据正在发生变化。

为了可读性(和测试),我删除了大部分 sql 以仅保留有问题的部分。基本上,您有一个患者 table,可能有 0 到 N 个诊断,而诊断可能有 0 到 N 个治疗:

SELECT RowNumber, PatientID, DiagnosticID, TreatmentID 
FROM 
(
    SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS RowNumber
         , *
    FROM PATIENTS
    LEFT JOIN DIAGNOSTICS ON DIAGNOSTICS.PatientID = PATIENTS.PatientID
    LEFT JOIN TREATMENTS ON TREATMENTS.DiagnosticID = DIAGNOSTICS.DiagnosticID
) AS Wrapper
--WHERE RowNumber BETWEEN 1 AND 10
--If I uncomment the line above, I'll get 10 lines that differs from the first 10 line of this query

这是我从上面的语句得到的结果。左边的结果显示没有 WHERE 子句的前 10 行,而右边的结果显示有 WHERE 子句的结果。

郑重声明,我使用的是 SQL Server 2008 R2 SP3。我的应用程序是在 C# 中,但问题也出现在 SQL 服务器中,所以我认为这种情况不涉及 .NET。

编辑

关于 ORDER BY (SELECT NULL),我不久前从这个 SO question 中获取了该代码。但是,仅当对语句进行排序时,null 的顺序才有效...在我的例子中,我忘记了添加 order by 子句,所以这就是我进行随机排序的原因。

我先问一句:你为​​什么期望它是一样的?或者更确切地说,你为什么期望它有什么特别之处?您没有强加排序,因此查询优化器可以自由使用任何最有效的执行运算符(根据其成本方案)。当您添加 WHERE 子句时,计划将发生变化并且结果的自然排序将有所不同。例如,在添加连接或子查询时也会发生这种情况。

如果您希望结果以特定顺序返回,您需要实际使用 ROW_NUMBER() window 函数的 ORDER BY 子句。我不确定你为什么要通过 SELECT NULL 订购,但我可以向你保证这就是问题所在。