most active time of day based on start and end time

后端 未结 7 1709
悲哀的现实
悲哀的现实 2021-02-08 06:53

I\'m logging statistics of the gamers in my community. For both their online and in-game states I\'m registering when they \"begin\" and when they \"end\". In order to show the

7条回答
  •  没有蜡笔的小新
    2021-02-08 07:20

    This query is for oracle, but you can get idea from it:

    SELECT
        H, M, 
        COUNT(BEGIN)
    FROM
        -- temporary table that should return numbers from 0 to 1439
        -- each number represents minute of the day, for example 0 represents 0:00, 100 represents 1:40, etc.
        -- in oracle you can use CONNECT BY clause which is designated to do recursive queries
        (SELECT LEVEL - 1 DAYMIN, FLOOR((LEVEL - 1) / 60) H, MOD((LEVEL - 1), 60) M FROM dual CONNECT BY LEVEL <= 1440) T LEFT JOIN
    
        -- join stats to each row from T by converting discarding date and converting time to minute of a day
        STATS S ON 60 * TO_NUMBER(TO_CHAR(S.BEGIN, 'HH24')) + TO_NUMBER(TO_CHAR(S.BEGIN, 'MI')) <= T.DAYMIN AND
                   60 * TO_NUMBER(TO_CHAR(S.END, 'HH24'))   + TO_NUMBER(TO_CHAR(S.END, 'MI'))   >  T.DAYMIN
    
    GROUP BY H, M
    HAVING COUNT(BEGIN) > 0
    ORDER BY H, M
    
    GROUP BY H, M
    HAVING COUNT(BEGIN) > 0
    ORDER BY H, M
    

    Fiddle: http://sqlfiddle.com/#!4/e5e31/9

    The idea is to have some temp table or view with one row for time point, and left join to it. In my example there is one row for every minute in day. In mysql you can use variables to create such view on-the-fly.

    MySQL version:

    SELECT
        FLOOR(T.DAYMIN / 60), -- hour
        MOD(T.DAYMIN, 60), -- minute
        -- T.DAYMIN, -- minute of the day
        COUNT(S.BEGIN) -- count not null stats
    FROM
        -- temporary table that should return numbers from 0 to 1439
        -- each number represents minute of the day, for example 0 represents 0:00, 100 represents 1:40, etc.
        -- in mysql you must have some table which has at least 1440 rows; 
        -- I use (INFORMATION_SCHEMA.COLLATIONSxINFORMATION_SCHEMA.COLLATIONS) for that purpose - it should be
        -- in every database
        (
            SELECT 
                @counter := @counter + 1 AS DAYMIN
            FROM
                INFORMATION_SCHEMA.COLLATIONS A CROSS JOIN
                INFORMATION_SCHEMA.COLLATIONS B CROSS JOIN
                (SELECT @counter := -1) C
            LIMIT 1440
        ) T LEFT JOIN
    
        -- join stats to each row from T by converting discarding date and converting time to minute of a day
        STATS S ON (
            (60 * DATE_FORMAT(S.BEGIN, '%H')) + (1 * DATE_FORMAT(S.BEGIN, '%i')) <= T.DAYMIN AND
            (60 * DATE_FORMAT(S.END, '%H'))   + (1 * DATE_FORMAT(S.END, '%i'))   >  T.DAYMIN
        )
    
    GROUP BY T.DAYMIN
    HAVING COUNT(S.BEGIN) > 0 -- filter empty counters
    ORDER BY T.DAYMIN
    

    Fiddle: http://sqlfiddle.com/#!2/de01c/1

提交回复
热议问题