Php 为日期范围中的登录者选择MySql行,返回每天小时数

Php 为日期范围中的登录者选择MySql行,返回每天小时数,php,mysql,sql,date,Php,Mysql,Sql,Date,我有一个头痛的SQL查询写,希望有人在互联网世界可以帮助我 我有一个mysql表,其中的值为when people log in and log out,我需要报告一个日期范围的数据,该日期范围给出一天中每小时登录的人数 所需输出示例: 2013-1-10 00:00 5 2013-1-10 01:00 13 ... for every hour of 2013-1-10 ending at 23:00... 2013-1-10 23:00 23 ...and then the same for

我有一个头痛的SQL查询写,希望有人在互联网世界可以帮助我

我有一个mysql表,其中的值为when people log in and log out,我需要报告一个日期范围的数据,该日期范围给出一天中每小时登录的人数

所需输出示例:

2013-1-10 00:00 5
2013-1-10 01:00 13
... for every hour of 2013-1-10 ending at 23:00...
2013-1-10 23:00 23
...and then the same for every date in the range...
2013-1-11 00:00 4
2013-1-11 01:00 6
我可以编写查询以按日期对所有内容进行分组,并根据时间登录获取每小时的计数,问题是,如果用户登录或超过一小时,他们的计数将不会在第二个小时显示,因为我按日期格式(时间登录,'%H')进行分组

查询示例如下:

SELECT mac, 
DATE_FORMAT(time_login, '%H') AS hour_logged_in,
DATE_FORMAT(time_logout, '%H') AS hour_logged_out,
DATE_FORMAT(time_login, '%Y-%m-%d') as date,
count(*) as dealcounts 
FROM sessions 
WHERE (
    time_logout IS NOT NULL 
     ) 
AND (
    DATE_FORMAT(time_login, '%Y-%m-%d') BETWEEN 
    DATE_FORMAT('2013-1-1', '%Y-%m-%d') AND DATE_FORMAT('2013-1-18', '%Y-%m-%d')) 
GROUP BY hour_logged_in
有人知道我如何完成每天每小时登录的行数吗

我在这里设置了一个SQLFIDLE:使用上面的查询

额外积分:无人登录时小时的空值:-)

很高兴向任何能帮忙的人支付一些啤酒和咖啡!!!
谢谢

我认为下面的mysql代码与您想要的很接近

注释

  • 它不是优雅的,除非它是优雅的方式,一个主要的黑客可以被认为是优雅的。乍一看可能会导致中度至重度肠/脑痉挛,因为它实在太难看了

  • 我猜,它需要增加索引,以便实际使用

  • 注意,我将sessions表的名称更改为sessions\u示例。如果你执行这个,我不想破坏你的会话表

  • 最后,在一个名为hours\u expanded的新表中查找结果

  • 它需要更多的测试。我现在已经筋疲力尽了,所以我正在提交潜力报告 解决方案我认为一般的方法是正确的,代码似乎是正确的,但是请验证

  • 我通过将登录计数按小时延长到当前小时(NOW())来处理主动登录记录。如果有人可以在不注销的情况下注销,并且总是将其放在会话表中,那么您可能需要做一些不同的事情。即,为标记为活动的记录提供一个最大截止时间

  • 一般方法

    基本上,当我阅读这个问题时,我知道我的首选方法是将所有涉及的小时数“扩展”到实际的表行中。我发现在这样的情况下,这样做更适合于测试和理解,即使它不一定是一个出色的执行者。当我在想如何做到这一点时,我发现了一篇博文(参见罗兰·鲍曼和凯·沃伊特的文章),这篇博文真的,真的帮助我实现了我想要的行扩展。我习惯用CTE在MSSQL中做这种事情,所以我需要它来帮助我找到一种在MySQL中生成任意数量行的方法

    下面是:

    /* Following test data from provided sql fiddle */
    
    /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
    /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
    /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
    /*!40101 SET NAMES utf8 */;
    
    /*changed name of sessions table to sessions_example, so as not to interfere with any prior sessions table*/
    DROP TABLE IF EXISTS sessions_example;
    CREATE TABLE `sessions_example` (
      `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
      `user_id` int(11) NOT NULL,
      `network_id` int(11) NOT NULL,
      `mac` varchar(17) NOT NULL,
      `time_login` datetime NOT NULL,
      `time_logout` datetime DEFAULT NULL,
      `data_in` bigint(20) DEFAULT NULL,
      `data_out` bigint(20) DEFAULT NULL,
      `sessionid` varchar(20) NOT NULL,
      `user_ip` varchar(20) DEFAULT NULL,
      `external_ip` varchar(20) DEFAULT NULL,
      `opfield1` varchar(255) DEFAULT NULL,
      `opfield2` varchar(255) DEFAULT NULL,
      `opfield3` varchar(255) DEFAULT NULL,
      `txtfield4` text,
      PRIMARY KEY (`id`),
      UNIQUE KEY `id` (`id`),
      KEY `sessionid` (`sessionid`),
      KEY `time_login` (`time_login`),
      KEY `time_logout` (`time_logout`),
      KEY `ap_id` (`network_id`),
      KEY `user_id` (`user_id`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=1009253406 ;
    
    INSERT INTO `sessions_example` (`id`, `user_id`, `network_id`, `mac`, `time_login`, `time_logout`, `data_in`, `data_out`, `sessionid`, `user_ip`, `external_ip`, `opfield1`, `opfield2`, `opfield3`, `txtfield4`) VALUES
    (1009250911, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 15:45:05', '2013-01-07 16:55:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250912, 0, 254, '00-88-65-D9-B1-8E', '2013-01-07 15:50:04', '2013-01-07 19:11:58', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250914, 0, 254, 'D0-23-DB-17-DC-FA', '2013-01-07 16:20:04', '2013-01-07 17:35:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250915, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 16:25:01', '2013-01-07 16:50:04', NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250917, 0, 254, 'E0-B9-BA-F0-45-83', '2013-01-07 16:45:05', '2013-01-07 19:11:58', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250919, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 16:55:05', '2013-01-07 17:12:30', NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250920, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 17:12:30', '2013-01-07 17:15:06', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250921, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 17:15:06', '2013-01-07 19:11:59', NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250926, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 19:11:59', '2013-01-07 20:30:04', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250927, 0, 254, '00-1B-9E-75-3E-DA', '2013-01-07 19:11:59', '2013-01-07 20:45:04', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250929, 0, 254, '00-88-65-D9-B1-8E', '2013-01-07 20:35:04', '2013-01-07 22:15:04', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250930, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 20:50:04', '2013-01-07 22:25:04', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250931, 0, 254, '00-26-C7-CD-10-9C', '2013-01-07 21:10:04', NULL, NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250933, 0, 254, '00-1B-9E-75-3E-DA', '2013-01-07 21:30:04', '2013-01-08 00:20:04', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250934, 0, 254, '00-88-65-D9-B1-8E', '2013-01-07 23:30:04', '2013-01-08 00:05:04', NULL, NULL, 'active', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250935, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-07 23:50:04', '2013-01-08 00:50:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250936, 0, 254, '00-88-65-D9-B1-8E', '2013-01-08 00:05:04', '2013-01-08 02:20:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250940, 0, 254, '00-26-C7-CD-10-9C', '2013-01-08 01:10:05', '2013-01-08 02:10:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250941, 0, 254, '5C-0A-5B-5E-5D-C3', '2013-01-08 01:25:05', '2013-01-08 02:25:06', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250942, 0, 254, '00-88-65-D9-B1-8E', '2013-01-08 03:00:06', '2013-01-08 05:45:07', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009250943, 0, 254, '10-40-F3-6E-D0-FA', '2013-01-08 03:05:07', '2013-01-08 04:45:06', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251100, 0, 254, '28-CF-DA-D9-30-66', '2013-01-08 03:20:06', '2013-01-08 05:10:06', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251101, 0, 253, '00-26-AB-00-E0-1F', '2013-01-08 03:45:03', '2013-01-11 05:15:12', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251102, 0, 253, '8C-A9-82-85-EF-72', '2013-01-08 03:45:03', '2013-01-11 05:25:15', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251103, 0, 253, 'F0-CB-A1-43-A8-4D', '2013-01-08 04:05:03', '2013-01-11 05:15:09', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251104, 0, 254, '00-1B-9E-75-3E-DA', '2013-01-08 04:10:07', '2013-01-08 05:10:07', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251105, 0, 254, 'F8-7B-7A-AC-EA-D6', '2013-01-08 04:20:06', '2013-01-08 06:35:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251106, 0, 253, '90-18-7C-A9-0B-2B', '2013-01-08 04:30:03', '2013-01-11 05:15:14', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251107, 0, 253, '30-F7-C5-C5-9F-61', '2013-01-08 04:30:03', '2013-01-11 05:15:15', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251108, 0, 253, '70-DE-E2-32-F8-66', '2013-01-08 04:30:03', '2013-01-11 09:55:15', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251109, 0, 254, '00-26-C7-CD-10-9C', '2013-01-08 04:55:07', '2013-01-08 06:00:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251110, 0, 254, '5C-0A-5B-A7-54-20', '2013-01-08 05:15:07', '2013-01-08 06:15:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251111, 0, 253, '78-A3-E4-E7-0F-1C', '2013-01-08 05:20:03', '2013-01-11 05:15:06', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251112, 0, 254, '00-1B-9E-75-3E-DA', '2013-01-08 05:35:08', '2013-01-08 06:45:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251113, 0, 253, '00-1F-F3-FA-01-43', '2013-01-08 06:35:04', '2013-01-11 05:15:14', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251114, 0, 253, 'D8-B3-77-7A-C3-F2', '2013-01-08 06:40:03', '2013-01-11 05:15:13', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL),
    (1009251128, 0, 254, '00-88-65-D9-B1-8E', '2013-01-08 16:25:08', '2013-01-08 17:40:05', NULL, NULL, 'passive', NULL, NULL, NULL, NULL, NULL, NULL);
    
    /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
    /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
    /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
    
    /* end of provided sql fiddle data */
    
    #Here is where we set up a table to hold expansion of all hours in rage as unix timestamp values.
    DROP TABLE IF EXISTS hours_expanded;
    CREATE TABLE hours_expanded
    (
         id int auto_increment,
         hour_as_unix_ts int,
         full_datetime datetime NULL,
         hour_as_time time NULL,
         count_logged_in int DEFAULT 0,
         PRIMARY KEY (id)
    );
    
    #get min/max hours
    SELECT @min_in := floor(unix_timestamp(min(time_login))/3600), 
        @max_out := floor(unix_timestamp(NOW())/3600)
    FROM sessions_example;
    
    #total number of rows that we will need in the `hours_expanded` table
    
    SELECT @hours_in_sessions:= @max_out - @min_in + 1;
    
    #dial up packet length for the string based row-generation solution (see tip of the hat)
    SET @old_max_packet = @@max_allowed_packet;
    SET GLOBAL max_allowed_packet = 1073741824;
    
    #Next, we will create a long UNION ALL string that will create one row per hour needed.
    #For the following concat based approach major tip of the hat to
    #http://datacharmer.blogspot.com/2007/12/data-from-nothing-solution-to-pop-quiz.html
    #and Roland Bouman who is mentioned there as proposing this solution to generating rows.
    SET @one_row_per_hour = (SELECT concat("INSERT INTO hours_expanded (hour_as_unix_ts) ",(repeat(concat(@s:="select 1 ","union all "),@hours_in_sessions)),"select 1;"));
    
    #dial packet length back down
    SET GLOBAL max_allowed_packet = @old_max_packet;
    
    #make that a prepared statement via the string and execute
    prepare q from @one_row_per_hour;
    execute q;
    
    #set hour_as_unix_ts column to actual UNIX TIMESTAMP hour value and full_datetime to show datetime for that hour
    UPDATE hours_expanded SET hour_as_unix_ts = (SELECT @min_in * 3600 + 3600 *( id - 1)),
        full_datetime = FROM_UNIXTIME(hour_as_unix_ts),
        hour_as_time = time(full_datetime);
    
    #get the counts and update the hours table
    UPDATE hours_expanded h
    INNER JOIN
    (
        SELECT h.hour_as_unix_ts, COUNT(*) as the_count
        FROM hours_expanded h
        INNER JOIN sessions_example
        WHERE h.hour_as_unix_ts >= floor(unix_timestamp(time_login)/3600)*3600 and h.hour_as_unix_ts <= floor(unix_timestamp(ifnull(time_logout,now()))/3600)* 3600
        GROUP by h.hour_as_unix_ts 
    ) t on h.hour_as_unix_ts = t.hour_as_unix_ts SET h.count_logged_in = t.the_count;
    
    #null out any hours that have a count of 0
    UPDATE hours_expanded SET full_datetime = NULL, hour_as_time = NULL WHERE count_logged_in = 0;
    
    #Final Select with desired output (reformat full_datetime and hour_as_time as desired)
    SELECT full_datetime, hour_as_time, count_logged_in FROM hours_expanded WHERE full_datetime IS NOT NULL
    
    /*以下测试数据来自提供的sql FIDLE*/
    /*!40101 SET@OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT*/;
    /*!40101 SET@OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS*/;
    /*!40101设置@OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION*/;
    /*!40101集合名称utf8*/;
    /*将sessions表的名称更改为sessions_示例,以避免干扰任何先前的sessions表*/
    如果存在,则删除表\u示例;
    创建表'sessions\u example`(
    `id`bigint(20)无符号非空自动增量,
    `用户_id`int(11)不为空,
    `网络id`int(11)不为空,
    `mac`varchar(17)不为空,
    `time_login`datetime不为空,
    `time_logout`datetime默认值为空,
    `“bigint(20)中的数据_默认为空,
    `data_out`bigint(20)默认为空,
    `sessionid`varchar(20)不为空,
    `user_ip`varchar(20)默认为空,
    `外部_ip`varchar(20)默认为空,
    `opfield1`varchar(255)默认为空,
    `opfield2`varchar(255)默认为空,
    `opfield3`varchar(255)默认为空,
    `txtfield4`文本,
    主键(`id`),
    唯一键'id'('id'),
    键`sessionid`(`sessionid`),
    输入'time\u login'('time\u login'),
    键“time\u logout”(“time\u logout”),
    键'ap\u id'('network\u id'),
    键“用户id”(“用户id”)
    )ENGINE=InnoDB默认字符集=latin1自动增量=1009253406;
    在“会话”示例中插入(`id`、`user\`id`、`network\`id`、`mac`、`time\`login`、`time\`logout`、`data\`in`、`data\`out`、`sessionid`、`user\`ip`、`opfield1`、`opfield2`、`opfield3`、`TXTFELD4`)值
    (1009250911,0254,'F8-7B-7A-AC-EA-D6',2013-01-07 15:45:05',2013-01-07 16:55:05',空,空,空,被动,空,空,空,空,
    (1009250912,0254,'00-88-65-D9-B1-8E','2013-01-07 15:50:04','2013-01-07 19:11:58',空,空,空,'被动式',空,空,空,空,空,空,
    (1009250914,0254,'D0-23-DB-17-DC-FA',2013-01-07 16:20:04',2013-01-07 17:35:05',空,空,空,被动,空,空,空,空,
    (1009250915,0254,'F8-7B-7A-AC-EA-D6','2013-01-07 16:25:01','2013-01-07 16:50:04',空,空,空,'active',空,空,空,空,空,
    (1009250917,0254,'E0-B9-BA-F0-45-83',2013-01-07 16:45:05',2013-01-07 19:11:58',空,空,空,被动,空,空,空,空,
    (1009250919,0254,'F8-7B-7A-AC-EA-D6','2013-01-07 16:55:05','2013-01-07 17:12:30',空,空,空,'active',空,空,空,空,空,
    (1009250920,0254,'F8-7B-7A-AC-EA-D6',2013-01-07 17:12:30',2013-01-07 17:15:06',空,空,空,被动,空,空,空,空,
    (1009250921,0254,'F8-7B-7A-AC-EA-D6','2013-01-07 17:15:06','2013-01-07 19:11:59',空,空,'active',空,空,空,空,空,空,
    (1009250926,0254,'F8-7B-7A-AC-EA-D6','2013-01-07 19:11:59','2013-01-07 20:30:04',空,空,空,'被动式',空,空,空,空,空,空,
    (1009250927,0254,'00-1B-9E-75-3E-DA',2013-01-07 19:11:59',2013-01-07 20:45:04',空,空,空,“被动”,空,空,空,空,空,
    (1009250929,0254,'00-88-65-D9-B1-8E','2013-01-07 20:35:04','2013-01-07 22:15:04',空,空,'passi