mysql - SQL:按时间间隔按列分组?

标签 mysql sql

我正在自己开发一个小项目,它是一个网站监控工具。 我有一个代理正在运行读取网页,它对网站状态代码、内容检查和响应时间使用react。

表格看起来像这样。

CREATE TABLE `data` (
  `id` int(11) NOT NULL,
  `check_id` int(11) NOT NULL,
  `content_string_used` varchar(20) NOT NULL,
  `content_check` enum('good','bad') NOT NULL,
  `http_code` int(11) NOT NULL,
  `total_time` varchar(5) NOT NULL,
  `namelookup_time` varchar(5) NOT NULL,
  `connect_time` varchar(5) NOT NULL,
  `pretransfer_time` varchar(5) NOT NULL,
  `starttransfer_time` varchar(5) NOT NULL,
  `url` varchar(50) NOT NULL,
  `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我想做的是选择特定检查的所有记录,例如

SELECT * FROM `data` WHERE  `check_id` = 173;

现在事情变得棘手了,我会尽力解释清楚。 行本身有一些重要的列。它是 content_check 和 http_code。

我想要做的是以这两行作为分隔符将所有行分组,然后选择从第一个好行到最后一个好行的开始时间。

示例...

SELECT id, check_id, content_check, http_code, time from data WHERE `check_id` = 173;

结果

(15, 173, 'bad', 0, '2018-03-11 15:43:11'),
(23, 173,'bad', 0, '2018-03-11 15:44:11'),
(35, 173,'good', 0, '2018-03-11 15:45:11'),
(49, 173,'good', 0, '2018-03-11 15:46:11'),
(67, 173,'bad', 0, '2018-03-11 15:47:11'),
(85, 173,'bad', 0, '2018-03-11 15:48:11'),
(105, 173,'bad', 0, '2018-03-11 15:49:11'),
(125, 173,'good', 0, '2018-03-11 15:50:11'),
(145, 173,'bad', 0, '2018-03-11 15:51:11'),
(165, 173,'bad', 0, '2018-03-11 15:52:11');

我喜欢这样的查询,它返回类似的内容,基本上总结了好/坏,并以时间间隔作为某种分隔符。

(15, 'bad', 0, '2018-03-11 15:43:11', '2018-03-11 15:44:11'),
(35, 'good', 0, '2018-03-11 15:45:11', '2018-03-11 15:46:11'),
(67, 'bad', 0, '2018-03-11 15:47:11', 2018-03-11 15:49:11),
(125, 'good', 0, '2018-03-11 15:50:11', '2018-03-11 15:50:11'),
(145, 'bad', 0, '2018-03-11 15:51:11','2018-03-11 15:52:11'),

请帮助或指出我正确的方向。

最佳答案

解决此类问题的一个技巧是使用一对变量来跟踪最新记录的 check_idhttp_code,再加上第三个变量来跟踪表示一个组编号,其值仅在 check_idhttp_code 与前面的记录不同的记录上递增。例如,给出以下设置:

CREATE TABLE `data` (
    `id` int(11) NOT NULL,
    `check_id` int(11) NOT NULL,
    `content_check` enum('good','bad') NOT NULL,
    `http_code` int(11) NOT NULL,
    `time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

insert into `data`
    (`id`, `check_id`, `content_check`, `http_code`, `time`)
values
    (15, 173, 'bad', 0, '2018-03-11 15:43:11'),
    (23, 173, 'bad', 0, '2018-03-11 15:44:11'),
    (35, 173, 'good', 0, '2018-03-11 15:45:11'),
    (49, 173, 'good', 0, '2018-03-11 15:46:11'),
    (67, 173, 'bad', 0, '2018-03-11 15:47:11'),
    (85, 173, 'bad', 0, '2018-03-11 15:48:11'),
    (105, 173, 'bad', 0, '2018-03-11 15:49:11'),
    (125, 173, 'good', 0, '2018-03-11 15:50:11'),
    (145, 173, 'bad', 0, '2018-03-11 15:51:11'),
    (165, 173, 'bad', 0, '2018-03-11 15:52:11');

set @lastContentCheck = '';
set @lastHttpCode = '';

我可以编写以下查询来分配如上所述的组编号:

select
    `id`,
    `check_id`,
    @groupNumber :=
        case
            when @lastContentCheck = `content_check` and @lastHttpCode = `http_code` then @groupNumber
            else @groupNumber + 1
        end as `GroupNumber`,
    @lastContentCheck := `content_check` as `content_check`,
    @lastHttpCode := `http_code` as `http_code`,
    `time`
from
    `data`,
    (select @groupNumber := 0) as `gn`
where
    `check_id` = 173
order by
    `time`

该查询的输出是:

id   check_id  GroupNumber  content_check  http_code  time
15   173       1            bad            0          2018-03-11 15:43:11
23   173       1            bad            0          2018-03-11 15:44:11
35   173       2            good           0          2018-03-11 15:45:11
49   173       2            good           0          2018-03-11 15:46:11
67   173       3            bad            0          2018-03-11 15:47:11
85   173       3            bad            0          2018-03-11 15:48:11
105  173       3            bad            0          2018-03-11 15:49:11
125  173       4            good           0          2018-03-11 15:50:11
145  173       5            bad            0          2018-03-11 15:51:11
165  173       5            bad            0          2018-03-11 15:52:11

此时,您只需在上面的查询周围包装另一个查询(按 GroupNumber 对其数据进行分组)即可获得所需的结果集。所以整个事情看起来像这样:

select
    min(`id`) as `id`,
    `check_id`,
    `content_check`,
    `http_code`,
    min(`time`) as `EarliestTime`,
    max(`time`) as `LatestTime`
from
    (
        select
            `id`,
            `check_id`,
            @groupNumber :=
                case
                    when @lastContentCheck = `content_check` and @lastHttpCode = `http_code` then @groupNumber
                    else @groupNumber + 1
                end as `GroupNumber`,
            @lastContentCheck := `content_check` as `content_check`,
            @lastHttpCode := `http_code` as `http_code`,
            `time`
        from
            `data`,
            (select @groupNumber := 0) as `gn`
        where
            `check_id` = 173
        order by
            `time`
    ) as `GroupedData`
group by
    `check_id`,
    `GroupNumber`,
    `content_check`,
    `http_code`
order by
    `GroupNumber`;

结果就是你想要的:

id   check_id  content_check  http_code  EarliestTime         LatestTime
15   173       bad            0          2018-03-11 15:43:11  2018-03-11 15:44:11
35   173       good           0          2018-03-11 15:45:11  2018-03-11 15:46:11
67   173       bad            0          2018-03-11 15:47:11  2018-03-11 15:49:11
125  173       good           0          2018-03-11 15:50:11  2018-03-11 15:50:11
145  173       bad            0          2018-03-11 15:51:11  2018-03-11 15:52:11

Demo on sqltest.net

关于mysql - SQL:按时间间隔按列分组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49237779/

相关文章:

php - 由于点符号,无法在查询中指定我的表名

c# - 如何在sql中将带有时区的varchar转换为datetime

mysql - 比较两个 MySQL 表并删除不再存在的行

php - 如何向 MySql 数据库中插入值? PHP v5.5,libmysql - mysqlnd 5.0.11-dev

Mysql死锁: what does 'try restarting transaction' mean and what exactly happens to the locked transactions

php - 生成 11,000,000 个唯一 ID 的最快方法

sql - 在数据库中存储吉他和弦

mysql - SQL,编辑表行中的字段,在开头和结尾输入一个字符。

php - 更改从 mysql 检索到的 php 中的日期格式

php - 我的 php 脚本中出现 fatal error