获取数字周围的上限和下限值

时间:2014-11-27 19:49:56

标签: sql postgresql

给定一个数字,我想从这样的表中获得直接的较低和较高值:

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。

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