如何在 SQL Server 中编写查询以查找最近的值

Mon*_*RPG 17 sql-server sql-server-2014

假设我在表中有以下整数值

32
11
15
123
55
54
23
43
44
44
56
23
Run Code Online (Sandbox Code Playgroud)

好了,名单可以继续了;没关系。现在我想查询这个表,我想返回一定数量的closest records. 假设我想将 10 个最接近的记录匹配返回到数字 32。我可以有效地实现这一目标吗?

它在 SQL Server 2014 中。

Mar*_*ith 22

假设该列被索引,以下应该是相当有效的。

两次查找 10 行,然后返回一种(最多)20 行。

WITH CTE
     AS ((SELECT TOP 10 *
          FROM   YourTable
          WHERE  YourCol > 32
          ORDER  BY YourCol ASC)
         UNION ALL
         (SELECT TOP 10 *
          FROM   YourTable
          WHERE  YourCol <= 32
          ORDER  BY YourCol DESC))
SELECT TOP 10 *
FROM   CTE
ORDER  BY ABS(YourCol - 32) ASC 
Run Code Online (Sandbox Code Playgroud)

(即可能类似于下面的内容)

在此处输入图片说明

或者另一种可能性(将排序的行数减少到最大 10)

WITH A
     AS (SELECT TOP 10 *,
                       YourCol - 32 AS Diff
         FROM   YourTable
         WHERE  YourCol > 32
         ORDER  BY Diff ASC, YourCol ASC),
     B
     AS (SELECT TOP 10 *,
                       32 - YourCol AS Diff
         FROM   YourTable
         WHERE  YourCol <= 32
         ORDER  BY YourCol DESC),
     AB
     AS (SELECT *
         FROM   A
         UNION ALL
         SELECT *
         FROM   B)
SELECT TOP 10 *
FROM   AB
ORDER  BY Diff ASC
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

注意:上面的执行计划是针对简单表定义的

CREATE TABLE [dbo].[YourTable](
    [YourCol] [int] NOT NULL CONSTRAINT [SomeIndex] PRIMARY KEY CLUSTERED 
)
Run Code Online (Sandbox Code Playgroud)

从技术上讲,底部分支上的 Sort 也不需要,因为它也是由 Diff 排序的,并且可以合并两个排序的结果。但我没能得到那个计划。

查询具有ORDER BY Diff ASC, YourCol ASC而不仅仅是ORDER BY YourCol ASC,因为那是最终消除计划顶部分支中的 Sort 的原因。我需要添加辅助列(即使它永远不会改变结果,因为YourCol对于具有相同 Diff 的所有值都是相同的),因此它会通过合并连接(连接)而不添加排序。

SQL Server 似乎能够推断出 X 上按升序查找的索引将提供按 X + Y 排序的行,并且不需要排序。但它无法推断以降序遍历索引会以与 YX 相同的顺序(甚至只是一元减去 X)传送行。计划的两个分支都使用索引来避免排序,但是TOP 10底部分支中的 则按顺序排序Diff(即使它们已经按该顺序排列)以使它们按所需的合并顺序排列。

对于其他查询/表定义,仅使用一种分支来获取合并计划可能会更棘手或不可能 - 因为它依赖于查找 SQL Server 的排序表达式:

  1. 接受索引查找将提供指定的顺序,因此在顶部之前不需要排序。
  2. 很高兴在合并操作中使用,因此在合并之后不需要排序 TOP