【问题标题】:How to get a conditional calculation that I want with SQL如何使用 SQL 获得我想要的条件计算
【发布时间】:2021-12-26 01:00:30
【问题描述】:

我有一个超过 50 万行和列的表格,如下所示;

  user_id | event_date |  event_name  | version|
===============================================
  1543435 | 18092021   |  first_open  |  113    
  5476523 | 18092021   | session_start|  111 
  7418529 | 18092021   |  first_open  |  112 
  1754821 | 18092021   | first_open   |  113 
  9820011 | 18092021   | session_start|  114 
  4568714 | 18092021   | session_start|  120

Event_name 和 first_open 的用户表示用户是第一次安装并打开应用程序,而 session_start 表示用户之前安装并打开过,不是第一次。

user_id 对于每个用户都是唯一的,并且不会因每次登录而改变。

我们正在处理只有版本 113 的用户。

我需要找出在 18 日 (18.09.2021) 安装应用程序并在 1 日 (19.09.2021) 和 3 日 (21.09.2021) 再次打开的用户比例。

路线图:

  • 第 1 步:查找 event date=18092021 和 event_name=first_open 的唯一 user_id 并获取其计数
  • 第 2 步:查找 event date=19092021 和 event_name=session_start 的匹配计数,这也与第 1 步中的 user_ids 匹配
  • 第 3 步:查找 event date=21092021 和 event_name=session_start 的匹配计数,这也与第 1 步中的 user_ids 匹配
  • 第 4 步:将第 2 步中的计数除以第 1 步中的计数将得到第 1 天的留存率
  • 第 5 步:将第 3 步中的计数除以第 1 步中的计数将得到第 3 天的留存率

经过一周的研究和头脑风暴,我写了下面的查询:

SELECT 
(SELECT COUNT(DISTINCT our_data.user_id)
FROM our_data WHERE our_data.event_date = '20210918' 
AND our_data.event_name ='first_open' 
AND our_data.version = '113') 
AS DAY_ZERO,

(SELECT COUNT(DISTINCT dayone.user_id) 
FROM our_data
LEFT JOIN our_data AS dayone 
ON our_data.user_id = dayone.user_id)
WHERE our_data.event_date = '20210918' 
AND dayone.event_date = our_data.event_date +1
AND our_data.event_name ='first_open' 
AND dayone.event_name ='session_start' 
AND our_data.version = '113' 
AND dayone.version = '113')
AS DAY_ONE,

(SELECT COUNT(DISTINCT our_data.user_id)
FROM our_data
LEFT JOIN our_data as daythree
ON our_data.user_id = daythree.user_id 
WHERE our_data.event_date = '20210918' 
AND daythree.event_date = our_data.event_date +3
AND our_data.event_name ='first_open' 
AND daythree.event_name ='session_start' 
AND our_data.version = '113' 
AND daythree.version = '113')
AS DAY_THREE

这个查询给了我这些结果:

  DAY_ZERO | DAY_ONE |  DAY_THREE |
========================================
  14879    |   7850  |     949    |   

在这些结果中,我无法在同一个查询中执行任何操作。我需要达到 Day_ONE/DAY_ZERO= DAY 1 RETENTION 和 DAY_THREE/DAY_ZERO= DAY3 RETENTION。我需要在同一个表中的其他第一天执行这些操作,因此我必须在单个查询中执行此操作。 你觉得我能做到吗?

【问题讨论】:

  • 我已经删除了冲突的 RDBMS 标签。只需标记您真正使用的那个。

标签: sql data-analysis


【解决方案1】:

我目前没有可用的 sql 数据库,但我认为,解决方案应该是这样的:

select 
    DAY_ONE/DAY_ZERO   as DAY_1_RETENTION,
    DAY_THREE/DAY_ZERO as DAY_3_RETENTION
from (... your query ...)

【讨论】:

  • 我现在试过了,但我收到了每个 DAY_ZERO、DAY_ONE 和 DAY_THREE 的“无效列名”警告。
【解决方案2】:

我会在评论中发布此内容,但查询对于评论来说似乎有点太长了。 简而言之,最佳答案在一定程度上取决于您实际使用的 SQL 风格(T-SQL?PL/SQL?PL/pgSQL?),但通用方法是相同的。

您已经在子查询中计算了所需的值。 我重新使用了这些子查询,但不是将行值,而是将它们制成具有唯一列名的表。

现在您有三张桌子,每张桌子有一排。交叉加入这些以获得具有三个不同列的“单行”......并对列进行所需的计算

select 
  DAY_ONE.cnt1/DAY_ZERO.cnt0   as DAY_1_RETENTION,
  DAY_THREE.cnt3/DAY_ZERO.cnt0 as DAY_3_RETENTION
FROM (SELECT COUNT(DISTINCT our_data.user_id) AS cnt0
      FROM our_data WHERE our_data.event_date = '20210918' 
      AND our_data.event_name ='first_open' 
      AND our_data.version = '113') 
     AS DAY_ZERO,

     (SELECT COUNT(DISTINCT dayone.user_id) cnt1
      FROM our_data
      LEFT JOIN our_data AS dayone 
      ON our_data.user_id = dayone.user_id)
      WHERE our_data.event_date = '20210918' 
      AND dayone.event_date = our_data.event_date +1
      AND our_data.event_name ='first_open' 
      AND dayone.event_name ='session_start' 
      AND our_data.version = '113' 
      AND dayone.version = '113')
     AS DAY_ONE,

     (SELECT COUNT(DISTINCT our_data.user_id) cnt3
      FROM our_data
      LEFT JOIN our_data as daythree
      ON our_data.user_id = daythree.user_id 
      WHERE our_data.event_date = '20210918' 
      AND daythree.event_date = our_data.event_date +3
      AND our_data.event_name ='first_open' 
      AND daythree.event_name ='session_start' 
      AND our_data.version = '113' 
      AND daythree.version = '113')
      AS DAY_THREE

【讨论】:

  • 它就像一个魅力!非常感谢您的宝贵时间。
猜你喜欢
  • 2020-02-11
  • 1970-01-01
  • 2016-07-29
  • 2023-01-10
  • 1970-01-01
  • 2021-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多