PostgreSQL:根据日期识别 return 访问者 - 连接或 window 函数?
PostgreSQL: Identifying return visitors based on date - joins or window functions?
我希望在 7 天内 window 识别网站的 return 访问者。下面包含一个数据样本和尝试解决问题:
visitor_id(integer)
session_id(integer)
event_sequence(integer)
d_date(date)
样本原始数据:
+-----------+-------------+----------------+-------------+
| visitor_id| session_id | event_sequence | d_date |
+-----------+-------------+----------------+-------------+
| 1 | 1 | 1 | 2017-01-01 |
| 1 | 1 | 2 | 2017-01-01 |
| 1 | 1 | 3 | 2017-01-01 |
| 1 | 2 | 1 | 2017-01-05 |
| 1 | 2 | 2 | 2017-01-05 |
| 1 | 3 | 1 | 2017-01-20 |
| 1 | 4 | 1 | 2017-01-25 |
| 2 | 1 | 1 | 2017-01-02 |
| 2 | 1 | 2 | 2017-01-02 |
| 2 | 2 | 1 | 2017-01-02 |
| 2 | 2 | 2 | 2017-01-02 |
| 2 | 2 | 3 | 2017-01-02 |
| 2 | 3 | 1 | 2017-01-18 |
+-----------+-------------+----------------+-------------+
我想知道,对于每个访问者会话,访问者是否在访问日期的后续 7 天内 returns(有另一个会话)。最终,table 在 visitor_id
、session_id
级别将是唯一的,并且包含一个标志,用于指示访问者是否在随后的 7 天内 return 访问过。
以下是我希望输出的样子:
+-----------+-------------+-----------------+-------------+
| visitor_id| session_id | returned_7_days | d_date |
+-----------+-------------+-----------------+-------------+
| 1 | 1 | 1 | 2017-01-01 |
| 1 | 2 | 0 | 2017-01-05 |
| 1 | 3 | 1 | 2017-01-20 |
| 1 | 4 | 0 | 2017-01-25 |
| 2 | 1 | 1 | 2017-01-02 |
| 2 | 2 | 0 | 2017-01-02 |
| 2 | 3 | 0 | 2017-01-18 |
+-----------+-------------+-----------------+-------------+
解决此问题的一种方法是将每个 visitor_id
-session_id
组合连接到相应的 visitor_id
,如下所示:
SELECT t2.visitor_id, t2.session_id, t2.d_date, t1.start_date
FROM table t2
INNER JOIN (
SELECT visitor_id, session_id, min(d_date) as start_date
FROM table t1
GROUP BY visitor_id, session_id
) t1
ON t1.visitor_id = t2.visitor_id
returns,对于每个 visitor_id
-session_id
组合,对应于该 visitor_id
的所有其他会话的日期。从那里,我可以比较 d_date
是否在 start_date
的 7 天内。然而,这似乎不是解决问题的有效方法,尤其是当有数百万个独特的 visitor_id
组合时,每个组合都与数十个 session_id
-event_sequence
组合交叉。
有没有更好的办法解决这个我没想到的问题?
首先,我用 DISTINCT
删除 event_sequence
(假设所有事件都在同一天),然后我使用 window 函数 lead
并进行比较下次访问的日期:
SELECT visitor_id,
session_id,
COALESCE(
lead(d_date) OVER w - d_date,
10
) < 7 AS revisited,
d_date
FROM (SELECT DISTINCT visitor_id,
session_id,
d_date
FROM "table"
) t
WINDOW w AS (PARTITION BY visitor_id
ORDER BY d_date
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
)
ORDER BY visitor_id, session_id;
┌────────────┬────────────┬───────────┬────────────┐
│ visitor_id │ session_id │ revisited │ d_date │
├────────────┼────────────┼───────────┼────────────┤
│ 1 │ 1 │ t │ 2017-01-01 │
│ 1 │ 2 │ f │ 2017-01-05 │
│ 1 │ 3 │ t │ 2017-01-20 │
│ 1 │ 4 │ f │ 2017-01-25 │
│ 2 │ 1 │ t │ 2017-01-02 │
│ 2 │ 2 │ f │ 2017-01-02 │
│ 2 │ 3 │ f │ 2017-01-18 │
└────────────┴────────────┴───────────┴────────────┘
(7 rows)
我希望在 7 天内 window 识别网站的 return 访问者。下面包含一个数据样本和尝试解决问题:
visitor_id(integer)
session_id(integer)
event_sequence(integer)
d_date(date)
样本原始数据:
+-----------+-------------+----------------+-------------+
| visitor_id| session_id | event_sequence | d_date |
+-----------+-------------+----------------+-------------+
| 1 | 1 | 1 | 2017-01-01 |
| 1 | 1 | 2 | 2017-01-01 |
| 1 | 1 | 3 | 2017-01-01 |
| 1 | 2 | 1 | 2017-01-05 |
| 1 | 2 | 2 | 2017-01-05 |
| 1 | 3 | 1 | 2017-01-20 |
| 1 | 4 | 1 | 2017-01-25 |
| 2 | 1 | 1 | 2017-01-02 |
| 2 | 1 | 2 | 2017-01-02 |
| 2 | 2 | 1 | 2017-01-02 |
| 2 | 2 | 2 | 2017-01-02 |
| 2 | 2 | 3 | 2017-01-02 |
| 2 | 3 | 1 | 2017-01-18 |
+-----------+-------------+----------------+-------------+
我想知道,对于每个访问者会话,访问者是否在访问日期的后续 7 天内 returns(有另一个会话)。最终,table 在 visitor_id
、session_id
级别将是唯一的,并且包含一个标志,用于指示访问者是否在随后的 7 天内 return 访问过。
以下是我希望输出的样子:
+-----------+-------------+-----------------+-------------+
| visitor_id| session_id | returned_7_days | d_date |
+-----------+-------------+-----------------+-------------+
| 1 | 1 | 1 | 2017-01-01 |
| 1 | 2 | 0 | 2017-01-05 |
| 1 | 3 | 1 | 2017-01-20 |
| 1 | 4 | 0 | 2017-01-25 |
| 2 | 1 | 1 | 2017-01-02 |
| 2 | 2 | 0 | 2017-01-02 |
| 2 | 3 | 0 | 2017-01-18 |
+-----------+-------------+-----------------+-------------+
解决此问题的一种方法是将每个 visitor_id
-session_id
组合连接到相应的 visitor_id
,如下所示:
SELECT t2.visitor_id, t2.session_id, t2.d_date, t1.start_date
FROM table t2
INNER JOIN (
SELECT visitor_id, session_id, min(d_date) as start_date
FROM table t1
GROUP BY visitor_id, session_id
) t1
ON t1.visitor_id = t2.visitor_id
returns,对于每个 visitor_id
-session_id
组合,对应于该 visitor_id
的所有其他会话的日期。从那里,我可以比较 d_date
是否在 start_date
的 7 天内。然而,这似乎不是解决问题的有效方法,尤其是当有数百万个独特的 visitor_id
组合时,每个组合都与数十个 session_id
-event_sequence
组合交叉。
有没有更好的办法解决这个我没想到的问题?
首先,我用 DISTINCT
删除 event_sequence
(假设所有事件都在同一天),然后我使用 window 函数 lead
并进行比较下次访问的日期:
SELECT visitor_id,
session_id,
COALESCE(
lead(d_date) OVER w - d_date,
10
) < 7 AS revisited,
d_date
FROM (SELECT DISTINCT visitor_id,
session_id,
d_date
FROM "table"
) t
WINDOW w AS (PARTITION BY visitor_id
ORDER BY d_date
ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
)
ORDER BY visitor_id, session_id;
┌────────────┬────────────┬───────────┬────────────┐
│ visitor_id │ session_id │ revisited │ d_date │
├────────────┼────────────┼───────────┼────────────┤
│ 1 │ 1 │ t │ 2017-01-01 │
│ 1 │ 2 │ f │ 2017-01-05 │
│ 1 │ 3 │ t │ 2017-01-20 │
│ 1 │ 4 │ f │ 2017-01-25 │
│ 2 │ 1 │ t │ 2017-01-02 │
│ 2 │ 2 │ f │ 2017-01-02 │
│ 2 │ 3 │ f │ 2017-01-18 │
└────────────┴────────────┴───────────┴────────────┘
(7 rows)