如何使用SQL从另一个表中的值中有效地定位一个表中的值

时间:2015-04-16 15:21:18

标签: postgresql join

我在Postgresql中遇到一个问题,我发现在标题中很难描述:我有两个表,每个表包含一系列非常相似但不相同的值。假设我有一个值,如0,10,20,30,......在一个,1,5,6,9,10,12,19,25,26 ......,在第二个(这些是毫秒) 。对于第二个的每个值,我想在第一个值中找到立即更低和更高的值。因此,对于值12,它会给我10和20.我这样做:

SELECT s.*, MAX(v1."millisec") AS low_v,  MIN(v2."millisec") AS high_v
FROM "signals" AS s, "tracks" AS v1, "tracks" AS v2 
WHERE   v1."millisec" <= s."d_time"  
    AND v2."millisec" > s."d_time" 
GROUP BY s."d_time", s."field2";     -- this is just an example

并且它有效...但是一旦我处理了数千行,即使索引在s上,它也非常慢。“d_time”和v.millisec。所以,我认为必须有一个更好的方法,但我找不到一个。谁能帮助我?

3 个答案:

答案 0 :(得分:0)

尝试:

select s.*, 
      (select millisec 
         from tracks t 
        where t.millisec <= s.d_time 
        order by t.millisec desc 
        limit 1
      ) as low_v,

      (select millisec 
         from tracks t 
        where t.millisec > s.d_time 
        order by t.millisec asc  
        limit 1
      ) as high_v
 from signals s;
  • 请确保您拥有track.millisec;
  • 的索引
  • 如果你刚刚创建了 索引,您需要分析表格以利用它。

答案 1 :(得分:0)

寻找前一个和下一个值的天真(平凡)方式。

   -- the data (this could have been part of the original question)
CREATE TABLE table_one (id SERIAL NOT NULL PRIMARY KEY
        , msec INTEGER NOT NULL -- index maight help
        );

CREATE TABLE table_two (id SERIAL NOT NULL PRIMARY KEY
        , msec INTEGER NOT NULL -- index maight help
        );

INSERT INTO table_one(msec) VALUES (0), ( 10), ( 20), ( 30);
INSERT INTO table_two(msec) VALUES (1), ( 5), ( 6), ( 9), ( 10), ( 12), ( 19), ( 25), ( 26);

  -- The query: find lower/higher values in table one
  -- , but but with no values between "us" and "them".
  --
SELECT this.msec AS this
        , prev.msec AS prev
        , next.msec AS next
FROM table_two this
LEFT JOIN table_one prev ON prev.msec < this.msec AND NOT EXISTS (SELECT 1 FROM table_one nx WHERE nx.msec < this.msec AND nx.msec > prev.msec)
LEFT JOIN table_one next ON next.msec > this.msec AND NOT EXISTS (SELECT 1 FROM table_one nx WHERE nx.msec > this.msec AND nx.msec < next.msec)
        ;

结果:

CREATE TABLE
CREATE TABLE
INSERT 0 4
INSERT 0 9
 this | prev | next 
------+------+------
    1 |    0 |   10
    5 |    0 |   10
    6 |    0 |   10
    9 |    0 |   10
   10 |    0 |   20
   12 |   10 |   20
   19 |   10 |   20
   25 |   20 |   30
   26 |   20 |   30
(9 rows)

答案 2 :(得分:0)

试试这个:

select * from signals s,
 (select millisec low_value,
     lead(millisec) over (order by millisec) high_value from tracks) intervals 
where s.d_time between low_value and high_value-1

对于此类问题,“窗口函数”非常理想,请参阅:http://www.postgresql.org/docs/9.1/static/tutorial-window.html