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

问题描述 投票:0回答:2

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

我的桌子看起来像这样。

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
sql postgresql
2个回答
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;

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。基本上,横向将让您在参考您正在选择的行时在桌面上进行子选择。

© www.soinside.com 2019 - 2024. All rights reserved.