我有一些感官信息进入一张桌子。我已经找到了能够准确告诉我特定设备的值何时发生变化的查询。
我需要知道的是当时所有其他传感器的状态。诀窍是,时间戳不会相等。我可以从传感器1获得数据点,然后3分钟后,一个来自传感器2,然后是30秒后,另一个来自传感器1。
所以,这是我所说的一个例子:
--- data_table ---
sensor | state | stime
-------+-------+---------------------
1 | A | 2014-08-17 21:42:00
1 | A | 2014-08-17 21:43:00
2 | B | 2014-08-17 21:44:00
3 | C | 2014-08-17 21:45:00
2 | D | 2014-08-17 21:46:00
3 | C | 2014-08-17 21:47:00
1 | B | 2014-08-17 21:48:00
3 | A | 2014-08-17 21:49:00
2 | D | 2014-08-17 21:50:00
2 | A | 2014-08-17 21:51:00
现在,我知道将为我提供状态更改的查询。我已经把它弄下来了,而且它在一个视野中。那张桌子看起来像是:
--- state_changed_view ---
sensor | state | stime
-------+-------+---------------------
2 | D | 2014-08-17 21:46:00
1 | B | 2014-08-17 21:48:00
3 | A | 2014-08-17 21:49:00
2 | A | 2014-08-17 21:51:00
我想要的是JOIN,我可以获取'state_changed_view'的所有值,还可以获取视图中'sensor_timestamp'处其他相应传感器的值。
所以,理想情况下,我希望我的结果看起来像(或类似的东西):
sensor | state | stime | sensor | state | stime
-------+-------+---------------------+--------+-------+---------------------
2 | D | 2014-08-17 21:46:00 | 1 | A | 2014-08-17 21:43:00
2 | D | 2014-08-17 21:46:00 | 2 | D | 2014-08-17 21:46:00
2 | D | 2014-08-17 21:46:00 | 3 | C | 2014-08-17 21:45:00
1 | B | 2014-08-17 21:48:00 | 1 | B | 2014-08-17 21:48:00
1 | B | 2014-08-17 21:48:00 | 2 | D | 2014-08-17 21:46:00
1 | B | 2014-08-17 21:48:00 | 3 | C | 2014-08-17 21:47:00
3 | A | 2014-08-17 21:49:00 | 1 | B | 2014-08-17 21:48:00
3 | A | 2014-08-17 21:49:00 | 2 | D | 2014-08-17 21:46:00
3 | A | 2014-08-17 21:49:00 | 3 | A | 2014-08-17 21:49:00
2 | A | 2014-08-17 21:51:00 | 1 | B | 2014-08-17 21:48:00
2 | A | 2014-08-17 21:51:00 | 2 | A | 2014-08-17 21:51:00
2 | A | 2014-08-17 21:51:00 | 3 | A | 2014-08-17 21:49:00
正如您所看到的,对于state_changed_view
中存在的每一行,我需要每个传感器的'data_table'中的最新行。
我根本不知道如何根据特定的时间戳让SQL获取最新的行。
这是在PL / pgSQL系统上,因此任何与Postgres兼容的东西都很方便。
答案 0 :(得分:3)
要检索的小,给定传感器集(适用于Postgres 8.4 或更高版本):
SELECT c.sensor AS sensor_change
, d1.state AS state_1, d1.stime AS stime_1
, d2.state AS state_2, d2.stime AS stime_2
, d3.state AS state_3, d3.stime AS stime_3
FROM (
SELECT sensor, stime
, lag(state) OVER (PARTITION BY sensor ORDER BY stime)
<> state AS change
, max(CASE WHEN sensor = 1 THEN stime ELSE NULL END) OVER w AS last_1
, max(CASE WHEN sensor = 2 THEN stime ELSE NULL END) OVER w AS last_2
, max(CASE WHEN sensor = 3 THEN stime ELSE NULL END) OVER w AS last_3
FROM data d
WINDOW w AS (ORDER BY stime)
) c
JOIN data d1 ON d1.sensor = 1 AND d1.stime = c.last_1
JOIN data d2 ON d2.sensor = 2 AND d2.stime = c.last_2
JOIN data d3 ON d3.sensor = 3 AND d3.stime = c.last_3
WHERE c.change
ORDER BY c.stime;
完全不使用视图,直接在桌面上构建,速度更快。
这假设(sensor, stime)
上的UNIQUE INDEX是明确的。性能也在很大程度上取决于这样的指数。
与基于JOIN LATERAL
(Postgres 9.3+)的@Nick's solution相反,这会返回单行,其中包含州内每次更改的所有值。
既然你提到了PL / pgSQL,我希望这个(高度优化的)plpgsql函数能够更好地执行,因为它可以对表的单个顺序扫描进行处理:
CREATE OR REPLACE FUNCTION f_sensor_change()
RETURNS TABLE (sensor_change int -- adapt to actual data types!
, state_1 "char", stime_1 timestamp
, state_2 "char", stime_2 timestamp
, state_3 "char", stime_3 timestamp) AS
$func$
DECLARE
r data%rowtype;
BEGIN
FOR r IN
TABLE data ORDER BY stime
LOOP
CASE r.sensor
WHEN 1 THEN
IF r.state = state_1 THEN -- just save stime
stime_1 := r.stime;
ELSIF r.state <> state_1 THEN -- save all & RETURN
stime_1 := r.stime; state_1 := r.state;
sensor_change := 1; RETURN NEXT;
ELSE -- still NULL: init
stime_1 := r.stime; state_1 := r.state;
END IF;
WHEN 2 THEN
IF r.state = state_2 THEN
stime_2 := r.stime;
ELSIF r.state <> state_2 THEN
stime_2 := r.stime; state_2 := r.state;
sensor_change := 2; RETURN NEXT;
ELSE
stime_2 := r.stime; state_2 := r.state;
END IF;
WHEN 3 THEN
IF r.state = state_3 THEN
stime_3 := r.stime;
ELSIF r.state <> state_3 THEN
stime_3 := r.stime; state_3 := r.state;
sensor_change := 3; RETURN NEXT;
ELSE
stime_3 := r.stime; state_3 := r.state;
END IF;
ELSE -- do nothing, ignore other sensors
END CASE;
END LOOP;
END
$func$ LANGUAGE plpgsql;
呼叫:
SELECT * FROM f_sensor_change();
重复使用有意义。相关回答:
答案 1 :(得分:1)
有一些事情使得这不那么直截了当:
state_changed_view
行执行子查询,但子查询必须在视图中提及相应的stime
(以将其限制为早期记录)。普通子查询不允许依赖外部字段,但您可以使用lateral join完成此操作(至少从Postgres 9.3开始)。MAX(data_table.stime)
,还需要相应的data_table.state
。您可以使用另一个嵌套查询执行此操作以检索行的其余部分,但SELECT DISTINCT ON
为您提供了一次轻松获取整个内容的方法。最终结果如下:
SELECT *
FROM
state_changed_view,
LATERAL (
SELECT DISTINCT ON (sensor)
sensor,
state,
stime
FROM
data_table
WHERE
data_table.stime <= state_changed_view.stime
ORDER BY
sensor,
stime DESC
) a
答案 2 :(得分:0)
首先找到每个传感器和状态的最大时间,并使用子查询对传感器和状态进行分组,然后将其连接到视图
SELECT *
FROM
(SELECT sensor, state, MAX(stime) as stime
from data_table
group by sensor, state) a
join state_changed_view on 1=1