我写了一个查询来计算某些条件下的物品数量。但是查询看起来很复杂,需要很长时间才能运行。有没有更好的方法来获得相同的结果?
我的桌子看起来像这样。
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
答案 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中,应使用LATERAL
。 LATERAL
小节允许您引用父子句中的列。因此,尝试以下操作:
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。基本上,横向只允许您在表上进行子选择,同时引用要为其进行子选择的行。