给定一个数字,我想从这样的表中获得直接的较低和较高值:
4.420
4.570
5.120
5.620
6.120
6.370
7.120
7.370
7.870
8.120
8.370
例如,如果我使用6.20作为参数,则查询应返回6.12和6.37。
我这样做是因为我想计算金融期权是否为金钱。
我正在使用PostgreSQL 9.3。
答案 0 :(得分:2)
with all_numbers as (
select nr,
lag(nr,1,nr) over (order by nr) as prev_value,
lead(nr,1,nr) over (order by nr) as next_value
from numbers
)
select *
from all_numbers
where 6.20 between prev_value and next_value;
为了完整起见,我正在玩另一种解决方案:
select *
from numbers
where nr >= (select max(nr) from numbers where nr < 6.20)
and nr <= (select min(nr) from numbers where nr > 6.20);
令我惊讶的是,这实际上比带有nr
列上的索引的窗口函数的版本更快:0.2秒与2.7万行的表上的2.7秒。
以下是执行计划:
另一种可能的解决方案是安装btree_gist扩展名,然后使用&#34; distance&#34;随附的运算符:<->
由于<->
是一个值(两个参数之间的距离),您需要定义一个足够低的阈值:
select nr
from numbers
where nr <-> 6.20 < 0.05;
或使用order by nr <-> 6.20 limit 1
。
我的测试表上花了大约1秒钟
这个版本在我的测试台上花了大约1秒钟。
答案 1 :(得分:1)
select * from
(
SELECT col, lag(col) OVER (ORDER BY col) before_value, lead(col) OVER (ORDER BY col) after_value
FROM foo order by col
) A
WHERE 6.20 between before_value and after_value limit 1;
答案 2 :(得分:1)
索引位于nr
,这将是最快:
(SELECT nr FROM tbl WHERE nr < 6.20 ORDER BY nr DESC LIMIT 1)
UNION ALL
(SELECT nr FROM tbl WHERE nr > 6.20 ORDER BY nr LIMIT 1);
需要括号。
以最便宜的计划从索引中取出两个元组。
更短,稍慢:
SELECT max(nr) AS nr FROM t WHERE nr < 6.20
UNION ALL
SELECT min(nr) AS nr FROM t WHERE nr > 6.20;
请注意,GIN或GiST索引不会有所帮助。默认的B树索引和它一样快(并且非常快)。
SQL Fiddle 比较目前发布的所有查询。
sqlfiddle.com上的执行时间不可靠。在您自己的数据库中测试以获得可靠的数字。很简单。我从EXPLAIN ANALYZE
得到了这些数字,最好的是5个来自临时表,有10万行(如小提琴)10年前的硬件:
a_horse 1 -- 766 ms (!!) Houari -- 0.463 ms a_horse 2 -- 0.165 ms erwin 2 -- 0.130 ms erwin 1 -- 0.108 ms