【问题标题】:mysql: count number of values in each groupmysql:计算每组中的值数
【发布时间】:2016-11-30 11:23:53
【问题描述】:

我有一个问题:

SELECT 
    count(session_id_open) as opens,
    count(session_id_visit) as visits,
    date_intervals_open,
    group_concat(date_intervals_visit)
FROM
    bla
GROUP BY date_intervals_open

我得到下表。我需要的是按百分比查找出现在 group_concat 中的每个值的出现次数。所以,基本上,我需要计算每组(data_intervals_open)中值的数量(date_intervals_visit)

opens   visits  date_intervals_open group_concat        
213    5        day (12-16)             evening (17-21),evening (17-21),day (12-16),day (12-16),day (12-16)
113    0        evening (17-21)         NULL
11     0        late evening (22-00)    NULL
396    12       morning (5-11)          morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11),morning (5-11)
9      0        night (1-4)              NULL

这大约是我需要得到的表。在 First record night 中有 40 次,因为“晚上 (17-21)”出现了两次,所有出现的次数为 5。2/5*100=40

opens   visits  date_intervals_open evening(17-21)  day(12-16)  morning (5-11)  
213    5        day (12-16)             40          60        0
113    0        evening (17-21)         NULL        NULL      NULL
11     0        late evening (22-00)    NULL        NULL     NULL
396    12       morning (5-11)          0        0     100
9      0        night (1-4)             NULL

PS:我使用 group_concat 只是为了可视化我在那里的价值。我不必使用它,因为之后解析它需要额外的努力。

【问题讨论】:

  • 请提供SHOW CREATE TABLE bla和几行样本数据。就好像您在执行count(session_id_visit) 时依赖于NULL。这看起来很奇怪。

标签: mysql group-by pivot-table


【解决方案1】:

您基本上需要一个支点,并进行一些进一步的计算。我的回答的基础来自pivoting records in MySQL 上的以下优秀 SO 主题。我假设您有固定数量的date_intervals_visit 值,因为这些值似乎涵盖了一整天,因此我使用具有固定计数的条件计数方法。我将在示例代码中添加 2 个类别,您可以将其扩展为涵盖所有 date_intervals_visit 值。

SELECT 
    count(session_id_open) as opens,
    count(session_id_visit) as visits,
    date_intervals_open,
    round(sum(if(date_intervals_visit='morning (5-11)',1,0)) / count(session_id_visit) * 100,2) as `morning (5-11)`,
    round(sum(if(date_intervals_visit='day (12-16)',1,0)) / count(session_id_visit) * 100,2) as `day (12-16)`
FROM
    bla
GROUP BY date_intervals_open

如果date_intervals_open值可能有0次访问,那么你需要在表达式中检查0:

if(count(session_id_visit)=0, 0, <above formula>)

【讨论】:

  • 啊,不错的偶数。 15000。很好的回答和支持。
  • 现在走出去,保护每个mysql问题:p
【解决方案2】:
SELECT 
    count(session_id_open) as opens,
    @visits := count(session_id_visit) as visits,
    date_intervals_open,
    ROUND(100 * SUM(date_intervals_visit = 'evening(17-21)') / @visits) AS 'evening(17-21)',
    ROUND(100 * SUM(date_intervals_visit = 'day (12-16)') / @visits) AS 'day (12-16)',
    ROUND(100 * SUM(date_intervals_visit = 'morning (5-11)') / @visits)'morning (5-11)',
FROM
    bla
GROUP BY date_intervals_open

【讨论】:

    【解决方案3】:

    使用这样的函数:

    CREATE FUNCTION [dbo].[fn_SplitString](
        @InputStr   varchar(Max),
        @Seperator  varchar(10))
    RETURNS @OutStrings TABLE (ItemNo int identity(1,1), Item varchar(256))
    
    AS
    BEGIN
    
        DECLARE @Str varchar(2000),
                @Poz int, @cnt int
    
        --DECLARE @OutStrings TABLE (Item varchar(2000))
    
        SELECT @Poz = CHARINDEX (@Seperator, @InputStr), @cnt = 0
        WHILE @Poz > 0 AND @cnt <= 10000
        BEGIN
            SELECT @Str = SubString(@InputStr, 1, @Poz - 1)
            INSERT INTO @OutStrings(Item) VALUES(@Str)
    
            SELECT @InputStr = Right(@Inputstr, Len(@InputStr) - (len(@Str) + len(@Seperator)))
            SELECT @Poz = CHARINDEX (@Seperator, @InputStr), @cnt = @cnt + 1
        END
        IF @InputStr <> ''
        BEGIN
            INSERT INTO @OutStrings(Item) VALUES(@InputStr)
        END
    
        RETURN
    END
    

    通过以下方式:

    SELECT  opens,
            visits,
            date_intervals_open,
            [evening(17-21)]/[All]*100 AS [evening(17-21)],
            [day(12-16)]/[All]*100 AS [day(12-16)],
            [morning (5-11)]/[All]*100 AS [morning (5-11)]
    FROM
        (   
        SELECT 
            count(session_id_open) as opens,
            count(session_id_visit) as visits,
            date_intervals_open,
            (SELECT COUNT(Item) FROM [dbo].[fn_SplitString](LTRIM(RTRIM(group_concat(date_intervals_visit))), ',') WHERE item  = 'evening(17-21)') AS [evening(17-21)],
            (SELECT COUNT(Item) FROM [dbo].[fn_SplitString](LTRIM(RTRIM(group_concat(date_intervals_visit))), ',') WHERE item = 'day(12-16)') AS [day(12-16)],
            (SELECT COUNT(Item) FROM [dbo].[fn_SplitString](LTRIM(RTRIM(group_concat(date_intervals_visit))), ',') WHERE item = 'morning (5-11)') AS [morning (5-11)],
            (SELECT COUNT(Item) FROM [dbo].[fn_SplitString](LTRIM(RTRIM(group_concat(date_intervals_visit))), ',')) AS [All]
        FROM
            bla
        GROUP BY date_intervals_open
        )blabla
    

    【讨论】:

    • 这是 ms sql,而问题是关于 MySQL。
    • 请先测试一下。它使用 mySQL 支持的基本 SQL。
    • 没有更简单的方法吗?我的意思是没有必要做 group_concat 然后拆分字符串是有一个函数可以再次在组内计数。
    • 你必须为 MySQL 完全重写这个。 MS SQL 和 MySQL 的存储过程语法和支持的函数大不相同。
    猜你喜欢
    • 2020-04-05
    • 2015-09-11
    • 2021-10-10
    • 2016-09-02
    • 2015-03-26
    • 2017-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多