MySQL 根据上一行和下一行选择行

标签 mysql sql

假设我有一张如下所示的表格:

          mytable
category |      begintime
---------|----------------------
cat1     | 2016-09-25 15:00:00
cat2     | 2016-09-25 16:00:00
cat1     | 2016-09-25 17:30:00
cat3     | 2016-09-25 19:00:00
cat1     | 2016-09-25 20:00:00
  :                 :

请注意,它没有 ID 号,begintime 列是我的主键。

最后,我想选择由某个类别包围的所有行,即选择上一行的类别为 @catBefore 且类别为的所有行下一行是@catAfter

例如,我想要的是这样的:

SELECT * FROM mytable WHERE previousRow.category = 'cat1' AND nextRow.category = 'cat1'

结果

    SELECT * FROM ...
category |      begintime
---------|----------------------
cat2     | 2016-09-25 16:00:00
cat3     | 2016-09-25 19:00:00
  :                 :

这里的previousRownextRow似乎无法定义。

想法

我已经尝试了一些方法,但还没有任何结果。我的想法之一是首先选择上一个和下一个类别作为新列,例如:

SELECT mytable.*, 
       previousRow.category AS prevCat, 
       nextRow.category AS nextCat 
FROM mytable, [stuff-I-don't-know]

结果

     SELECT mytable.* ...
category |      begintime       | prevCat | nextCat
---------|----------------------|---------|---------
cat1     | 2016-09-25 15:00:00  | null    | cat2
cat2     | 2016-09-25 16:00:00  | cat1    | cat1
cat1     | 2016-09-25 17:30:00  | cat2    | cat3
cat3     | 2016-09-25 19:00:00  | cat1    | cat1
cat1     | 2016-09-25 20:00:00  | cat3    | ...
  :                 :

然后使用 WHERE 子句进行过滤。

这个想法是否可行,或者可以通过其他方式实现吗?

最佳答案

一种方法使用相关子查询。如果您确实有主键声明,那么从性能角度来看,这应该没问题:

select t.*
from (select t.*,
             (select t2.category
              from mytable t2
              where t2.begintime < t.begintime
              order by begintime desc
              limit 1
             ) as prev_category,        
             (select t2.category
              from mytable t2
              where t2.begintime > t.begintime
              order by begintime asc
              limit 1
             ) as next_category
  from mytable t
 ) t
where prev_category = @cat1 and next_category = @cat2;

编辑:

您可以使用变量来做到这一点:

select t.*
from (select t.*,
             (@pn := (case when (@pcy := @pn) = NULL then -1 -- never gets here 
                           when (@pn := category) = NULL then -1 -- never gets here
                           else @pcy
                      end)
                   ) as next_category
      from (select t.*,
                   (@pc := (case when (@pcx := @pc) = NULL then -1 -- never gets here 
                                 when (@pc := category) = NULL then -1 -- never gets here
                                 else @pcx
                            end)
                   ) as prev_category
            from t cross join
                 (select @pc := '') params
            order by t.begintime
           ) t cross join
           (select @pn := '') params
      order by t.begintime desc
     ) t
where prev_category = @cat1 and next_category = @cat2; 

关于MySQL 根据上一行和下一行选择行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39688517/

相关文章:

sql - 将 PostgreSQL 子查询语句转换为 Sequelize 查询

asp.net - Mysql中int(10)的最大大小是多少

mysql - 在 MySQL 中运行查询触发器时出错

sql - 在 postgres 表中添加检查,其中数据已经不正确

sql - 如何检查表是否存在

mysql - 如何在父表上创建同时约束子表的约束?

mysql - 错误 NULL DEFAULT NULL Laravel 使用 MariaDB 迁移

PHPMailer 意外启动垃圾邮件

mysql - MySQL 中的动态变量名称

MySQL查询返回包含空格的行