我写了一个查询来计算具有某些条件的项目数量。但查询看起来很复杂,需要很长时间才能运行。有没有更好的方法来获得相同的结果?
我的桌子看起来像这样。
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
您可以使用窗口功能执行所需操作。我认为逻辑是:
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;
通常,当您可以使用窗口功能时,在现代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。基本上,横向将让您在参考您正在选择的行时在桌面上进行子选择。