如何对连续范围进行分组(mysql 5.7)

Posted

技术标签:

【中文标题】如何对连续范围进行分组(mysql 5.7)【英文标题】:How do I group on continuous ranges (mysql 5.7) 【发布时间】:2018-06-06 23:05:30 【问题描述】:

我想返回网站关闭时的日期时间范围数组。

我使用的是 mysql 5.7。

down_time

created_at           user_id down
2017-12-15 14:50:21    1       1
2017-12-21 19:19:19    1       0
2017-12-25 22:41:14    1       1
2017-12-25 22:41:17    1       0
2017-12-25 23:11:22    1       0
2017-12-25 23:11:24    1       1
2017-12-25 23:31:24    1       1

此处在向下列 - 0(false) 表示向下,1(true) 表示向上。 我需要这样的视图/结果:

down                  up                     user_id 
2017-12-21 19:19:19   2017-12-25 22:41:14    1
2017-12-25 22:41:17   2017-12-25 23:11:24    1      

希望这个示例完全代表我的查询需求 - 我只需要停机时间范围。

如果可以使用 Laravel(5.5) SQL 查询辅助方法来实现,那就太好了(所以我可以轻松地附加查询选择器,如 ->where('user_id', Auth::user()->id)->whereBetween('created_at', [$range['from'], $range['to']]) ),但在这种情况下我并不挑剔 - 一个原始 MySQL (5.7.19 ) 查询也很棒。

【问题讨论】:

@Vashi 正如我所提到的,我想显示一个站点何时关闭以及何时再次恢复的日期时间范围。所以模式是——注意第一次出现 down(0)——忽略所有 ups(1) 。然后注意站点何时备份(1)的第一次出现 - 忽略所有 0'os 直到 1(up)并获取这两行的时间戳。之后忽略所有 1 直到第一个 0 再次....所以在示例中,如您所见,第一行和最后一行被忽略,然后连续出现两个 downs(0),其中只有第一个被挂号的。希望这不会太令人困惑。 明白了。 @Mkey - user_id 是什么。你想拥有每个 user_id 的列表吗? @BerndBuffen user_id 与站点相关,在此示例中,我们有一个用户/站点,但可以有不同的用户/站点。所以可以有不同的 user_id 并且选择器应该考虑到这一点,所以应该有一个动态的方式来改变 user_id 选择器。 我不确定,但您的 MySQL 版本是否支持 ROW_NUMBER() ? 【参考方案1】:

如果我理解正确,您可以在 MySQL 中这样做:

select user_id, min(created_at) as ca_0, created_at_1 as ca_1
from (select t.*,
             (select min(t2.created_at)
              from t t2
              where t2.user_id = t.user_id and t2.down = 1 and
                    t2.created_at > t.created_at
             ) as created_at_1
      from t
      where t.down = 0
     ) tt
group by user_id, created_at_1;

我不知道如何在 Laravel 中表达这一点。

【讨论】:

只是...太好了!你让它看起来很简单@Gordon @Gordon 我已经澄清了我的原始帖子(表名 = down_time)。我想在查询中添加一些 where down_time.user_id = $user_idBETWEEN 日期额外选择器,但我对 tt2 代表什么有点困惑? t 据我了解是我的表名“down_time”,t2 是? @Mkey 。 . . t2 是表别名。 t 的@GordonLinoff 表别名?【参考方案2】:

为那些希望在他们的 mysql 查询中实现日期时间范围和 user_id 选择器的人发布免费答案。这基本上是我的主要目标:

 $range = request('range');
        $range_from = $range['from'];
        $range_to = $range['to'];
        $user_id = Auth::user()->id;
        return DB::select("select user_id, min(created_at) as ca_0, created_at_1 as ca_1
from (select down_time.*,
             (select min(t2.created_at)
              from down_time t2
              where t2.user_id = $user_id and t2.down = 1 and
                    t2.created_at > down_time.created_at and 
                    t2.created_at between '$range_from' and '$range_to'
             ) as created_at_1
      from down_time
      where down_time.down = 0 and down_time.user_id = $user_id and 
      down_time.created_at between '$range_from' and '$range_to'
     ) tt
group by user_id, created_at_1;");

【讨论】:

以上是关于如何对连续范围进行分组(mysql 5.7)的主要内容,如果未能解决你的问题,请参考以下文章

如何在熊猫 DataFrame 中对连续值进行分组

如何对具有相同大小的连续数字进行分组

如何按特定日期范围(例如小时、日、月)对数据进行分组?

在 MySQL 5.7 中对“孤岛”进行分组

在 MySQL 中对重叠的数据范围进行分组

如何对输入类型范围进行分组并保持 100% 组合在一起的所有范围的最大值