MySQL根据上一行和下一行选择行
假设我有一张像这样的桌子:MySQL根据上一行和下一行选择行,mysql,sql,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 :
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 mytable.*,
previousRow.category AS prevCat,
nextRow.category AS nextCat
FROM mytable, [stuff-I-don't-know]
导致
SELECT * FROM ...
category | begintime
---------|----------------------
cat2 | 2016-09-25 16:00:00
cat3 | 2016-09-25 19:00:00
: :
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 | ...
: :
上一行和下一行似乎无法定义
意念
我试过一些东西,但还没有成功。我的一个想法是首先选择上一个类别和下一个类别作为新列,因此类似于:
SELECT * FROM mytable WHERE previousRow.category = 'cat1' AND nextRow.category = 'cat1'
SELECT mytable.*,
previousRow.category AS prevCat,
nextRow.category AS nextCat
FROM mytable, [stuff-I-don't-know]
导致
SELECT * FROM ...
category | begintime
---------|----------------------
cat2 | 2016-09-25 16:00:00
cat3 | 2016-09-25 19:00:00
: :
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
t1.category,
t1.begintime
FROM myTable t1 -- current
INNER JOIN myTable t2 ON 1=1 -- prev
AND t2.begintime < t1.begintime
INNER JOIN myTable t3 ON 1=1 -- next
AND t3.begintime > t1.begintime
LEFT JOIN myTable t4 ON 1=1 -- between current and prev
AND t4.begintime < t1.begintime
AND t4.begintime > t2.begintime
LEFT JOIN myTable t5 ON 1=1 -- between current and next
AND t5.begintime > t1.begintime
AND t5.begintime < t3.begintime
WHERE 1=1
AND t2.category = 'cat1' -- prev cat
AND t3.category = 'cat1' -- next cat
AND t4.begintime IS NULL -- nothing between current and prev
AND t5.begintime IS NULL -- nothing between current and next
;
在子查询中添加限制1,否则将抛出错误子查询返回多个rowI,我也将对此进行注释。然而,它的执行速度不是很快,但这可能是因为我的桌子相当大。它已经运行了几分钟,但没有返回任何内容。我可以很容易地将它限制在前1000行左右,看看它是否真的有效吗?@konewka。是的,您可以向外部查询添加限制以查看其工作方式。你真的有开始时间的索引吗?@Abhishekginai。谢谢。欢迎戈登:你想查询整个表来进行上一个和下一个分类和筛选吗?假设你的前四行来自cat1。。。如果您正在查找prev和next等于cat1,则应仅返回第二条记录,或者也应返回第三条记录?@FelyppOliveira如果是这样,则第二条和第三条记录的前面和后面都有“cat1”,因此应返回。很遗憾,Edit没有返回任何信息。它执行了,但没有结果我尝试了它,并针对您的样本数据,得到了预期的结果。您将运行哪个上一个和下一个类别?如果您的数据在上一个和下一个之间没有任何类别,则预期结果是一个空集。。。查询可能运行良好。。。我认为您的筛选器/数据不应与任何内容匹配。。。你能提取其他样本数据吗?啊,是的,我明白了,它现在也在我的表上工作,一定是复制时出错了。然而,在1000个条目表上计算查询大约需要7秒,而Gordon Linoff的查询需要约0.11秒。我也试过在我原来的16000个条目表上运行它,但它已经运行了5分钟,没有结果,你认为查询可以改进吗?我说过它很慢。。。我认为这是可以改进的,但我现在做不到。。。请随意接受任何其他答案。。。如果我提高了性能,我将稍后编辑我的帖子。