如何从一个表中选择子序列对

时间:2018-04-24 09:25:54

标签: sql postgresql sqlite

我有一张包含多个传感器数据的表格。传感器上发生特殊事件时添加行。传感器具有始终增长的事件序列号,并且不能小于先前事件的序列号,但不能保证它以恒定值增长。它可能是1, 2, 5,6, 11,...的序列。每行包含传感器ID,事件序列号,事件发生时的时间戳和一些数据。我想为按时间戳排序的每个传感器获得成对的后续事件。

包含一些虚拟数据的表结构示例:

CREATE TABLE event (
  sensor_id  INT,
  event_seq INT,
  ts        INT,
  data      TEXT,
  CONSTRAINT event_pk PRIMARY KEY (sensor_id, event_seq)
);

INSERT INTO event (sensor_id, event_seq, ts, data) VALUES
  (1, 1, 1, '1st sensor 1st event'),
  (1, 2, 2, '1st sensor 2nd event'),
  (2, 1, 2, '2nd sensor 1st event'),
  (2, 2, 3, '2nd sensor 2nd event'),
  (1, 3, 3, '1st sensor 3rd event'),
  (1, 4, 4, '1st sensor 4th event'),
  (2, 3, 5, '2nd sensor 3rd event'),
  (1, 5, 5, '1st sensor 5th event'),
  (2, 4, 6, '2nd sensor 4th event'),
  (2, 5, 7, '2nd sensor 5th event'),
  (1, 6, 7, '1st sensor 6th event');

目前,我使用的是SQLite DB。我提出了以下问题:

SELECT
  a.data,
  a.ts,
  b.data,
  b.ts
FROM event AS a
  JOIN event AS b ON a.sensor_id = b.sensor_id AND a.event_seq < b.event_seq
GROUP BY a.sensor_id, a.event_seq
HAVING min(b.event_seq)
ORDER BY a.ts, b.ts

它实际上提供了我需要的结果(SQL Fiddle):

|                 data | ts |                 data | ts |
|----------------------|----|----------------------|----|
| 1st sensor 1st event |  1 | 1st sensor 2nd event |  2 |
| 1st sensor 2nd event |  2 | 1st sensor 3rd event |  3 |
| 2nd sensor 1st event |  2 | 2nd sensor 2nd event |  3 |
| 1st sensor 3rd event |  3 | 1st sensor 4th event |  4 |
| 2nd sensor 2nd event |  3 | 2nd sensor 3rd event |  5 |
| 1st sensor 4th event |  4 | 1st sensor 5th event |  5 |
| 2nd sensor 3rd event |  5 | 2nd sensor 4th event |  6 |
| 1st sensor 5th event |  5 | 1st sensor 6th event |  7 |
| 2nd sensor 4th event |  6 | 2nd sensor 5th event |  7 |

但我在min中使用HAVING函数而没有任何返回布尔值的表达式。它可以工作,但根据文档它应该是布尔表达式,所以我不知道我是否遗漏了某些东西,或者这是错误或其他什么。 更重要的是,它有可能,我需要在一天切换到PostgreSQL,而这个查询实际上是Postgres上的错误argument of HAVING must be type boolean, not type integer Position: 177

所以我的问题是如何编写这个查询,以便它适用于SQLite和Postgres。 另外,有关索引的任何建议来加速查询吗?

2 个答案:

答案 0 :(得分:0)

(我对Stackoverflow的第一个评论,温柔:-)

以下查询是实现相同目标的另一种方式。我不确定(根本没有)它是否更快。在PostgreSQL上你肯定会使用窗口函数LEAD或LAG,它应该表现得更好。

SELECT
  a.data,
  a.ts,
  b2.data,
  b2.ts
FROM event AS a
  JOIN (select b.sensor_id, b.data, b.ts 
    from event AS b 
    where a.sensor_id = b.sensor_id
    AND a.event_seq < b.event_seq
    order by event_seq DESC
    limit 1 ) b2
on b2.sensor_id = a.sensor_id

答案 1 :(得分:0)

如果我理解正确,你可以在平等条件下使用JOIN

SELECT a.data, a.ts, b.data, b.ts
FROM event a JOIN
     event b
     ON a.sensor_id = b.sensor_id AND a.event_seq = b.event_seq - 1
ORDER BY a.ts, b.ts;