5

我有一个包含两列的表,例如:

CREATE TABLE actions (
  action_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  "action" text NOT NULL
);

以及其中的以下数据:

        action_time         | action 
----------------------------+--------
 2016-12-30 14:12:33.353269 | a
 2016-12-30 14:12:38.536818 | b
 2016-12-30 14:12:43.305001 | a
 2016-12-30 14:12:49.432981 | a
 2016-12-30 14:12:53.536397 | b
 2016-12-30 14:12:57.449101 | b
 2016-12-30 14:13:01.592785 | a
 2016-12-30 14:13:06.192907 | b
 2016-12-30 14:13:11.249181 | b
 2016-12-30 14:13:13.690897 | b
(10 rows)

您可以假设action_time列中没有重复值。

如何计算从最后一个动作开始连续执行的相同动作的数量?

连续相同动作的数量没有限制,任何动作都可以是最后一个。此外,对各种不同的操作没有限制:我只使用了两个来简化示例数据。

对于这个示例数据,我希望结果为 3。这是因为最后一个操作是“b”,并且它连续发生了 3 次。

我认为可以结合窗口函数和WITH RECURSIVE子句来实现解决方案,但我不知道该怎么做。

4

4 回答 4

1

我在经典的间隙和孤岛解决方案中添加了一些变化。
请注意 ROW_NUMBER 函数如何使用降序 ORDER BY。

select  count(*)

from   (select  

            action
           ,row_number() over (                    order by action_time desc) as rn
           ,row_number() over (partition by action order by action_time desc) as rn_action

        from    mytab
        ) t

group by action
        ,rn - rn_action

having   min(rn) = 1
于 2016-12-30T20:21:39.770 回答
1

改进的解决方案

select  count(*)

from   (select  

            action
           ,row_number() over (                    order by action_time desc) as rn
           ,row_number() over (partition by action order by action_time desc) as rn_action

        from    mytab
        ) t

where   rn = rn_action
于 2016-12-31T08:44:28.957 回答
1

这应该这样做。

SELECT COUNT(*)
FROM actions
WHERE action_time > (
SELECT action_time
  FROM actions 
  WHERE action <> (SELECT action FROM actions ORDER BY action_time DESC LIMIT 1) 
ORDER BY action_time DESC LIMIT 1);

最里面的查询

SELECT action FROM actions ORDER BY action_time DESC LIMIT 1

确定最后一个动作。

查询

SELECT action_time
  FROM actions 
  WHERE action <> (SELECT action FROM actions ORDER BY action_time DESC LIMIT 1) 
ORDER BY action_time DESC LIMIT 1

查找具有不同操作的最后一行。

最外面的查询查找该行之后的所有行。

于 2016-12-30T20:26:05.003 回答
0

想到这:

select count(*)
from t cross join
     (select t2.action
      from t t2
      order by action_time desc
      limit 1
     ) last
where t.action_time >= (select max(t2.action_time)
                        from t t2
                        where t2.action <> last.action
                       );

这应该能够利用(action_time, action).

于 2016-12-30T20:22:45.683 回答