【问题标题】:点击流数据的 SQL 聚合函数
【发布时间】:2022-01-10 17:33:41
【问题描述】:

我有一组点击流数据(即用户 ID、开始和结束日期/时间、有效使用时长、每个会话的总时长)。

我需要检索给定月份的唯一每日数据,按 user_id、日期和 webOrMobile 排序。

到目前为止,以 2019 年 1 月为例:

SELECT DISTINCT id, CONVERT(DATE, START_DTTM) AS date, WEB_VS_MOBILE_DISPLAY AS webOrMobile, ACTIVE_DURATION_SECONDS 
FROM ClickStream
WHERE START_DTTM LIKE '2019-01-%'
ORDER BY id, START_DTTM, WEB_VS_MOBILE_DISPLAY

导致:

    id          date        webOrMobile  ACTIVE_DURATION_SECONDS
    
    Z000013917  2019-01-07  Web        245
    Z000013917  2019-01-10  Web        128
    Z000013917  2019-01-29  Web        261
    Z000013917  2019-01-31  Web        1246
    Z0000140154 2019-01-18  Mobile     212
    Z0000140154 2019-01-22  Mobile     18
    Z0000140154 2019-01-23  Mobile     201
    Z0000158605 2019-01-11  Web        67
    Z0000158605 2019-01-11  Web        587
    Z0000158605 2019-01-11  Web        681
    Z0000158605 2019-01-11  Web        1123
    Z0000158605 2019-01-13  Web        2896
    Z0000158605 2019-01-14  Web        20

我的问题是日期为 2019-01-11 的行,除了持续时间之外,它们是相同的。如何将这些行组合成一行,其中包含各个持续时间的总和?所以像:

     id          date        webOrMobile  ACTIVE_DURATION_SECONDS
        
        Z000013917  2019-01-07  Web        245
        Z000013917  2019-01-10  Web        128
        Z000013917  2019-01-29  Web        261
        Z000013917  2019-01-31  Web        1246
        Z0000140154 2019-01-18  Mobile     212
        Z0000140154 2019-01-22  Mobile     18
        Z0000140154 2019-01-23  Mobile     201
        Z0000158605 2019-01-11  Web        2458
        Z0000158605 2019-01-13  Web        2896
        Z0000158605 2019-01-14  Web        20

现在每一行都有一个唯一的 id/date/webOrMobile。

编辑:我也试过了

SELECT pat_did, CONVERT(DATE, START_DTTM), WEB_VS_MOBILE_DISPLAY, SUM(MYC_ACTIVE_DURATION_SECONDS) FROM ClickStream
WHERE START_DTTM LIKE '2019-01-%'
GROUP BY pat_did, START_DTTM, WEB_VS_MOBILE_DISPLAY

导致:

    id          date        webOrMobile  ACTIVE_DURATION_SECONDS

    Z000013917  2019-01-07  Web          4900
    Z000013917  2019-01-10  Web          1536
    Z000013917  2019-01-29  Web          3915
    Z000013917  2019-01-31  Web          11214
    Z0000140154 2019-01-18  Mobile       3392
    Z0000140154 2019-01-22  Mobile       54
    Z0000140154 2019-01-23  Mobile       1407
    Z0000158605 2019-01-11  Web          24706
    Z0000158605 2019-01-11  Web          5283
    Z0000158605 2019-01-11  Web          12258
    Z0000158605 2019-01-11  Web          469
    Z0000158605 2019-01-13  Web          112944
    Z0000158605 2019-01-14  Web          5746

行没有合并,但持续时间值现在太高了,例如 112944 等于 31 小时,这是不可能的。

【问题讨论】:

    标签: sql aggregate-functions


    【解决方案1】:

    任何未出现在 GROUP BY 中的列只能出现在 SELECT 的聚合函数中。而且您不会同时使用 GROUP BY 和 DISTINCT。事实上,你很少应该使用 DISTINCT。

    类似

    SELECT id, 
           CONVERT(DATE, START_DTTM) AS date, 
           WEB_VS_MOBILE_DISPLAY AS webOrMobile, 
           SUM(ACTIVE_DURATION_SECONDS) ACTIVE_DURATION_SECONDS  
    FROM ClickStream
    WHERE START_DTTM LIKE '2019-01-%'
    GROUP BY ID, START_DTTM, WEB_VS_MOBILE_DISPLAY 
    ORDER BY id, START_DTTM, WEB_VS_MOBILE_DISPLAY
    

    【讨论】:

    • @David Browne 我试过了,但我仍然得到相同数量的行,而且 Active_Duration_Seconds 高得不可思议,例如 Z0000158605 2019-01-11 Web 469 Z0000158605 2019-01-13 Web 112944 Z0000158605 2019-01 -14 Web 5746 我认为这会以某种方式汇总每一行数据,包括非唯一的数据,所以这似乎不起作用。
    • 然后用 RDBMS 标记您的问题并添加足够的示例数据来重现问题。
    • 已添加,谢谢建议
    • @jyew,如果您在输出中执行此操作,则需要在 group by 中转换为日期。我认为你更大的问题是你的“不同”正在摆脱重复的行。在尝试求和之前,您需要删除这些重复项。
    • 另外,在获得不同的值之前不要进行迄今为止的演员阵容,否则你会失去恰好相同的持续时间。
    【解决方案2】:

    我觉得您遇到了重复行和日期转换的问题:

    with data as (
        SELECT DISTINCT
            ID, START_DTTM, cast(START_DTTM as date) as "date",
            WEB_VS_MOBILE_DISPLAY as webOrMobile,
            ACTIVE_DURATION_SECONDS as duration
       FROM ClickStream
       WHERE START_DTTM LIKE '2019-01-%'
    )
    select ID as id, "date", webOrMobile, sum(duration) as duration
    from data
    group by id, "date", webOrMobile
    order by id, "date", webOrMobile;
    

    如果需要在没有 CTE/派生表等的情况下执行此操作,那么您可以在这些方面使用一些技巧:

    select ID, cast(START_DTTM as date), WEB_VS_MOBILE_DISPLAY as webOrMobile,
        sum(distinct
            datediff(second, cast(START_DTTM as date), START_DTTM) *
              cast(100000000 as bigint) + ACTIVE_DURATION_SECONDS
        ) % 100000000 as duration
    from ClickStream
    group by ID, cast(START_DTTM as date), WEB_VS_MOBILE_DISPLAY;
    

    您基本上必须将日期信息作为数值(将求和)打包成带有持续时间的高位数字,以便每个组合可以保持唯一,然后通过剥离低位数字来解包。

    https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=23b55e85d42c78e16bab406135fa3291

    【讨论】:

    • 非常感谢!这给了我想要的结果。我明白为什么您为投射日期添加了一个额外的字段以防止丢失数据。出于好奇,有没有办法在不使用临时第二张表的情况下获得这个结果?
    • 如果您可以假设组中没有两行将共享持续时间,那么听起来您可以使用sum(distinct ACTIVE_DURATION_SECONDS)。我认为那将是一个坏主意。否则我认为没有。
    • @jyew,我想到了一种可行的方法。一般来说,如果没有非常令人信服的理由走这条路,它会被认为是一种黑客行为。
    猜你喜欢
    • 1970-01-01
    • 2017-05-10
    • 2013-08-14
    • 2020-10-05
    • 1970-01-01
    • 2010-09-08
    • 2016-10-03
    • 1970-01-01
    相关资源
    最近更新 更多