简体   繁体   English

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

[英]SQL: Group by column with time interval?

i am working on a little project on my own, its kinda a website monitor tool. 我自己一个人在做一个小项目,有点像一个网站监控工具。 I have an agent running reading webpages, its reacting on website status codes, content checks and response time. 我有一个正在运行的代理程序正在阅读网页,它对网站状态代码,内容检查和响应时间做出反应。

The table looks like this. 该表如下所示。

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;

What i am trying to do is to select all records for a specific check, example 我想做的是选择所有记录进行特定检查,例如

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

Now here is where it gets tricky and ill try to explain as good as possible. 现在这是棘手的问题,请尝试尽力而为。 The rows themselves have some columns that are important. 行本身具有一些重要的列。 Its the content_check and the http_code. 它是content_check和http_code。

What i want to do is to group up all the rows with these two rows as separators and then select the start time from the first good one to the last good one. 我想要做的是将这两行作为分隔符将所有行分组,然后选择从第一个好行到最后一个好行的开始时间。

Example... 例...

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

result 结果

(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');

id love a query that returns this to something like, basically sums up the good/bad with the time intervals as a delimiter of some sort. id喜欢一个将其返回为类似查询的查询,基本上将时间间隔的好/坏相加为某种定界符。

(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'),

Please help or point me in the right direction. 请帮助或指出正确的方向。

One trick that will work for something like this is to use a pair of variables to keep track of the most recent record's check_id and http_code , plus a third variable to represent a group number whose value is incremented only on records whose check_id or http_code differ from those of the preceding record. 一招,将这样的事情的工作是用一对变量保持最新记录的轨道check_idhttp_code ,加上第三个变量来表示其值仅在其记录递增组号check_idhttp_code从不同先前记录的那些。 For instance, given the following setup: 例如,给定以下设置:

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 = '';

I can write the following query that will assign the group numbers as described above: 我可以编写以下查询,以如上所述分配组号:

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`

The output of this query is: 该查询的输出为:

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

At this point you can get the result set you want by simply wrapping another query around the one above that groups its data by the GroupNumber . 这时,您可以通过将另一个查询包装在上面的查询中来获得所需的结果集,该查询将其数据按GroupNumber So the whole thing would look like this: 所以整个事情看起来像这样:

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`;

And the result is as you wanted: 结果如您所愿:

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 sqltest.net上的演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM