Sql 是否有postgres最近的接线员?

Sql 是否有postgres最近的接线员?,sql,postgresql,Sql,Postgresql,我在找一些东西,比如: | id | number | | 1 | .7 | | 2 | 1.25 | | 3 | 1.01 | | 4 | 3.0 | 查询从my_表中选择*,NumberCloseSt1将返回第3行。我只关心数字。现在,我有一个过程,它只是在每一行上循环并进行比较,但我认为信息应该可以从b树索引中获得,因此这可能是一个内置的,但我找不到任何文档表明它可以。您可以尝试以下方法: select * from my_table where abs(1

我在找一些东西,比如:

| id | number |
|  1 |     .7 |
|  2 |   1.25 |
|  3 |   1.01 |
|  4 |    3.0 |

查询从my_表中选择*,NumberCloseSt1将返回第3行。我只关心数字。现在,我有一个过程,它只是在每一行上循环并进行比较,但我认为信息应该可以从b树索引中获得,因此这可能是一个内置的,但我找不到任何文档表明它可以。您可以尝试以下方法:

select *
from my_table
where abs(1 - number) = (select min(abs(1 - number)) from t)
psql => explain select * from (
        (SELECT id, number FROM t WHERE number >= 1 order by number limit 1) 
        union all
        (select id, number from t where number < 1 order by number desc limit 1)
) as make_postgresql_happy 
order by abs (1 - number) 
limit 1;
                                                  QUERY PLAN
--------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.24..0.24 rows=1 width=12)
   ->  Sort  (cost=0.24..0.24 rows=2 width=12)
         Sort Key: (abs((1::double precision - public.t.number)))
         ->  Result  (cost=0.00..0.23 rows=2 width=12)
               ->  Append  (cost=0.00..0.22 rows=2 width=12)
                     ->  Limit  (cost=0.00..0.06 rows=1 width=12)
                           ->  Index Scan using idx_t on t  (cost=0.00..15046.74 rows=255683 width=12)
                                 Index Cond: (number >= 1::double precision)
                     ->  Limit  (cost=0.00..0.14 rows=1 width=12)
                           ->  Index Scan Backward using idx_t on t  (cost=0.00..9053.67 rows=66136 width=12)
                                 Index Cond: (number < 1::double precision)
(11 rows)

这与在表中手动循环没有多大区别,但至少它允许数据库在数据库空间中执行循环,而不必在函数和数据库内部之间来回跳转。此外,将所有内容放入一个查询中,可以让查询引擎知道您正在尝试执行的操作,然后它可以尝试以合理的方式执行该操作。

我可能对语法有点不了解,但这个参数化查询始终是一个问题?以“1”为例,原始问题应该运行得很快,基本上是2个B树查找[假设数字已索引]

SELECT * FROM
(
  (SELECT id, number FROM t WHERE number >= ? ORDER BY number LIMIT 1) AS above
  UNION ALL
  (SELECT id, number FROM t WHERE number < ? ORDER BY number DESC LIMIT 1) as below
) 
ORDER BY abs(?-number) LIMIT 1;

第二个答案是正确的,但我在UNION ALL上遇到了错误:

DBD::Pg::st execute失败:错误:UNION处或附近出现语法错误

我用以下代码修复了它:

SELECT * FROM
  (
    (SELECT * FROM table WHERE num >= ? ORDER BY num LIMIT 1)
        UNION ALL
    (SELECT * FROM table WHERE num < ?  ORDER BY num DESC LIMIT 1)
  ) as foo
ORDER BY abs(?-num) LIMIT 1;

诀窍是从内部表中删除AS,并仅在UNION上使用它。

如果您希望在组中查找最接近的值,则此代码非常有用。在这里,我根据我的列val接近我的目标值0.5的程度,将我的表tb按列_you_wish_to_group_by分割


这是一个正确的查询,与我当前使用的查询类似,但我认为索引对它没有帮助。我的问题是,我正在查询的表有数亿行,并且需要很长很长的时间。@quodlibetor:您是否尝试在abs1编号上创建索引以加速该查询?例如,对此查询运行解释返回postgres必须对281610907722行进行顺序扫描。。。这很烦人。@a_马_没有名字:谢谢!这将有助于我的常见情况,但一般来说,搜索的数字可以是任意的。如果最接近的参数始终为1,则索引会有所帮助。如果是武断的,问题就更难了。这看起来很有希望。我将建立我的索引,看看这是否有帮助。谢谢对我来说,这是在t上进行两次序列扫描,而不是至少一次。@mu太短了:您在将索引添加到数字后进行了分析吗?PG应该足够聪明,可以对ORDER BY/LIMIT进行索引扫描,但我想你永远不会知道。我只是做了一次分析以确定,我仍然得到两次扫描。OTOH,我的测试表中没有一百万行,所以优化器可以使用扫描,因为扫描一个小表很便宜。我认为是小表的大小欺骗了我。我填充了1e5行,现在它正在进行索引扫描。干得好。如果您想查看,我可以将解释输出添加到您的答案中,这样可以避免构建自己的测试数据堆。
SELECT *
FROM (
  SELECT
    ROW_NUMBER() OVER (PARTITION BY t.column_you_wish_to_group_by ORDER BY abs(t.val - 0.5) ASC) AS r,
    t.*
  FROM
    tb t) x 
WHERE x.r = 1;