【问题标题】:MySQL pivot-like operation to get breakdown of percentage of total events per day per event typeMySQL 类似枢轴的操作,以获取每种事件类型每天总事件百分比的细分
【发布时间】:2020-09-22 03:14:49
【问题描述】:

有一个事件表

created_at DATETIME
event_type STRING 
# Some other columns with data about the event

我想要做的是能够得到每个event_type每天事件总数的百分比。

因此,我将事件分组以获得每个事件每天的计数:

# Lazily used date_bucket in GROUP BY since it's valid MySQL.
# Is that bad since it's not standard SQL?
#
SELECT 
    DATE(created_at) as date_bucket, 
    event_type, 
    COUNT(*) as number
FROM 
    example_table 
GROUP BY
    date_bucket, event_type

如果我们有行

# Columns (date_bucket, event_type, number)
#
('2020-06-02', 'exampleG1', 5)
('2020-06-02', 'exampleG2', 10)
('2020-06-02', 'exampleG3', 20)
('2020-06-03', 'exampleG1', 10)

我希望能够得到与

相当的处理方式
# Columns (date_bucket, exampleG1, exampleG2, exampleG3)
#
('2020-06-02', 15/35, 10/35, 20/35)
('2020-06-03', 10/10, 0, 0)

我事先不知道不同的 event_type 值,并且并非所有组值都可能在所有日子都存在,在这种情况下,该类型的值在那天应该是 0。

我正在考虑进行某种枢轴操作,但似乎 MySQL 不支持枢轴,所以我有点不知所措。

如果我提前知道有效事件类型的集合,我想我可以对可能的类型进行一些讨厌的详细查询,但集合是可变的。

有没有优雅的方法来实现这一点?

【问题讨论】:

    标签: mysql sql group-by pivot dynamic-pivot


    【解决方案1】:

    我事先不知道不同的 event_type 值

    您要求的是动态 SQL。也就是说,从另一个列出不同 event_type 值的查询动态构建查询字符串,然后执行它。在 MySQL 中,这是使用准备好的语句来实现的。

    这是怎么做的:

    select @sql := group_concat(distinct
        'sum(case when event_type = ''', 
        event_type, ''' then number else 0 end)/sum(number) as `ratio_', 
        event_type, '`'
    ) 
    from example_table;
    
    set @sql = concat(
        'select date(created_at) date_bucket, ', 
        @sql, 
        ' from example_table group by date(created_at) order by date_bucket'
    );
    
    -- debug
    select @sql;
    
    -- execute
    prepare stmt from @sql;
    execute stmt;
    deallocate prepare stmt; 
    

    对于您的示例数据,这会产生以下查询:

    select 
        date(created_at) date_bucket, 
        sum(case when event_type = 'exampleG1' then number else 0 end)/sum(number) as `ratio_exampleG1`,
        sum(case when event_type = 'exampleG2' then number else 0 end)/sum(number) as `ratio_exampleG2`,
        sum(case when event_type = 'exampleG3' then number else 0 end)/sum(number) as `ratio_exampleG3` 
    from example_table 
    group by date(created_at) 
    order by date_bucket
    

    结果如下:

    日期桶 | ratio_exampleG1 | ratio_exampleG2 | ratio_exampleG3 :------------ | --------------: | --------------: | --------------: 2020-06-02 | 0.1429 | 0.2857 | 0.5714 2020-06-03 | 1.0000 | 0.0000 | 0.0000

    Demo on DB Fiddle

    【讨论】:

    • 啊,之前没有真正使用过prepared statements。我去学习一下!谢谢!
    猜你喜欢
    • 2020-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 2013-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多