我正在寻找一些东西,如下表:
| id | number |
| 1 | .7 |
| 2 | 1.25 |
| 3 | 1.01 |
| 4 | 3.0 |
Run Code Online (Sandbox Code Playgroud)
查询SELECT * FROM my_table WHERE
号码CLOSEST(1)
将返回第3行.我只关心数字.现在我有一个程序只是循环遍历每一行并进行比较,但我认为信息应该可以从b树索引获得,所以这可能是一个内置的,但我找不到任何文件表明它确实如此.
And*_*rus 21
我可能对语法有点偏僻,但是这个参数化查询(所有?原始问题的'1')应该快速运行,基本上是2个B-Tree查找[假设数字被索引].
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;
Run Code Online (Sandbox Code Playgroud)
对于具有~5e5行(带有索引number
)的表的查询计划如下所示:
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)
Run Code Online (Sandbox Code Playgroud)
第二个答案是正确的,但我在“UNION ALL”上遇到错误:
DBD::Pg::st execute failed: ERROR: syntax error at or near "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;
Run Code Online (Sandbox Code Playgroud)
诀窍是从内表中删除 AS 并仅在 UNION 上使用它。
你可以尝试这样的事情:
select *
from my_table
where abs(1 - number) = (select min(abs(1 - number)) from t)
Run Code Online (Sandbox Code Playgroud)
这与手动循环表没有太大的不同,但至少它允许数据库在"数据库空间"内进行循环,而不必在函数和数据库内部之间来回跳转.此外,将它全部推送到单个查询中可以让查询引擎知道您正在尝试做什么,然后它可以尝试以合理的方式执行此操作.
归档时间: |
|
查看次数: |
8625 次 |
最近记录: |