【问题标题】:GROUP BY column and clause in postgrespostgres 中的 GROUP BY 列和子句
【发布时间】:2016-08-14 11:03:45
【问题描述】:

我想按列值以及满足另一个条件时对表的列进行分组。比如下表:

事件:

id  session_id  flags        created_at  ...
--------------------------------------------
1   100         OTHER        ...
2   101         OTHER        ...
3   101         NEW_SESSION  ...
4   101         OTHER        ...
5   101         NEW_SESSION  ...  
6   100         OTHER        ...
7   102         OTHER        ...

我想要以下结果:

session_id  events_count first_event_id  last_event_id  
-------------------------------------------------------
100-0       2            1               6
101-0       1            2               2
101-1       2            3               4
101-2       1            5               5
102-0       1            7               7

基本思想是我想从事件中提取会话。它们按 session_id 分组。每当我有标志 NEW_SESSION 时,我也想要一个新会话。

查询是这样的:

SELECT ? as session_id
  , count(id) as events_count
  , MIN(id) as first_event_id
  , MAX(id) last_event_id
GROUP BY session_id
  -- , and whenever flags is NEW_SESSION
ORDER BY id

但我不知道如何按条件正确表达组。有什么想法吗?

【问题讨论】:

  • 101-0和101-1背后的逻辑是什么?
  • @JakubKania 101 是原始会话 id,012 是一个增量,以便我们可以“剪切”会话并仍然拥有唯一的会话 id。因为会话 101 有两个 NEW_SESSION 标志,所以我想将此会话分成 3 个块。
  • 我最终通过 CTE 中的窗口函数实现了这一点。第一个窗口有滞后,另一个窗口有总和,都 PARTITIONing on session_id
  • 您可能想发布一个答案供其他人查看。

标签: postgresql group-by amazon-redshift window-functions gaps-and-islands


【解决方案1】:

更新 2

在 cmets 中,我注意到您希望它们独一无二。然后我们可以使用一个变量:

SET @inc := 0;

(
  SELECT CONCAT(session_id, '-', !ABS(STRCMP(flags, 'NEW_SESSION'))) AS session_id
  , COUNT(id) AS events_count
  , MIN(id) AS first_event_id
  , MAX(id) last_event_id
  FROM events
  WHERE flags != 'NEW_SESSION'
  GROUP BY events.session_id, events.flags
  ORDER BY events.id
) UNION (
  SELECT CONCAT(session_id, '-', @inc := @inc + 1) AS session_id
  , COUNT(id) AS events_count
  , MIN(id) AS first_event_id
  , MAX(id) last_event_id
  FROM events
  WHERE flags = 'NEW_SESSION'
  GROUP by events.id
  ORDER BY events.id
);

更新

以下内容可防止对 NEW_SESSION 行进行分组:

(
  SELECT CONCAT(session_id, '-', !ABS(STRCMP(flags, 'NEW_SESSION'))) AS session_id
  , COUNT(id) AS events_count
  , MIN(id) AS first_event_id
  , MAX(id) last_event_id
  FROM events
  WHERE flags != 'NEW_SESSION'
  GROUP BY events.session_id, events.flags
  ORDER BY events.id
) UNION (
  SELECT CONCAT(session_id, '-1') AS session_id
  , COUNT(id) AS events_count
  , MIN(id) AS first_event_id
  , MAX(id) last_event_id
  FROM events
  WHERE flags = 'NEW_SESSION'
  GROUP BY id
  ORDER BY events.id
);

原答案

据我了解,您正在尝试按会话 ID 和 “是否是 NEW_SESSION”标志。如果是这样,那我就表达如下:

SELECT CONCAT(session_id, '-', !ABS(STRCMP(flags, 'NEW_SESSION'))) AS session_id
, COUNT(id) AS events_count
, MIN(id) AS first_event_id
, MAX(id) last_event_id
FROM events
GROUP BY events.session_id, events.flags
ORDER BY events.id;

【讨论】:

  • 可能有许多不同的NEW_SESSION 标志,从而产生尽可能多的新会话。我已经更新了我的问题以反映这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-09
  • 1970-01-01
  • 2012-04-20
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多