有没有更好的方法来查询某个持续时间内在行前是否满足条件?

时间:2019-04-10 18:05:17

标签: sql postgresql

我写了一个查询来计算某些条件下的物品数量。但是查询看起来很复杂,需要很长时间才能运行。有没有更好的方法来获得相同的结果?

我的桌子看起来像这样。

timestamp      uid     action      item   state
------------------------------------------------
  2010          1      switch      null      on
  2100          1        move         A    null    
  2300          1        move         A    null
  2700          1        move         B    null
  2013          2      switch      null     off
  2213          2        move         C    null
  2513          2        move         A    null
  2200          3      switch      null     off
  2350          3        move         A    null
  2513          3      switch      null      on
  2700          3        move         A    null

基本上,我想获取每个项目的编号,条件是状态在一段时间之前和一段时间内处于启用状态。

我的查询是

WITH action_move (
  SELECT timestamp, uid, item
  FROM table
  WHERE action=move AND item IS NOT NULL
)
SELECT item, count(*)
FROM action_move
WHERE EXISTS (
  SELECT timestamp
  FROM table
  WHERE 
    uid=action_move.uid
    action=switch 
    AND state=on 
    AND (action_move.timestamp - timestamp) < 1000
)
GROUP BY item;

我的结果

item    count
-------------
  A        3
  B        1
  C        0

2 个答案:

答案 0 :(得分:0)

您可以使用窗口功能执行所需的操作。我认为逻辑是:

select item, count(*)
from (select t.*,
             max(timestamp) filter (where state = 'on') over (order by timestamp) as prev_on
      from t
     ) t
where item is not null prev_on >= timestamp - 1000
group by item;

答案 1 :(得分:0)

通常可以使用窗口函数时,在现代Postgres中,应使用LATERALLATERAL小节允许您引用父子句中的列。因此,尝试以下操作:

SELECT item, sum(counts.count) AS count 
FROM table t1,
LATERAL (
  SELECT count(*)
  FROM table t2
  WHERE t1.uid = t2.uid
    AND t2.action=switch 
    AND t2.state=on 
    AND (t1.timestamp - t2.timestamp) < 1000
    ) counts
WHERE action=move AND item IS NOT NULL
GROUP BY item;

我不确定是否已完全复制了此内容。如果您具有要聚合的特定事件的过滤器,则可能不需要在外部子句中使用GROUP BY。基本上,横向只允许您在表上进行子选择,同时引用要为其进行子选择的行。