我有一张像这样的桌子:
CREATE TABLE mytable (
id INT(10) auto_increment PRIMARY KEY,
from DATE(10) NOT NULL,
before DATE(10) NULL,
reference_id INT(10) NOT NULL,
)
因此,存在引用另一个表(带有reference_id
)的行。这些引用具有适用的日期范围(from
/ before
)。 对于每个reference_id
,通常会有很多条目没有间隔:
id | from | before | reference_id
-------------------------------------------
1 | 2019-03-01 | 2019-03-05 | 5
5 | 2019-03-05 | 2019-03-09 | 5
8 | 2019-03-09 | NULL | 5
(它们之间可能有其他reference_id
的条目。)条目从上一个结束处开始。现在,我想找到所有在它们之间留有间隔的条目,其中from
比前面的before
晚。例如(在第2
行,第from
列中进行更改):
id | from | before | reference_id
-------------------------------------------
1 | 2019-03-01 | 2019-03-05 | 5
5 | 2019-03-06 | 2019-03-09 | 5
8 | 2019-03-09 | NULL | 5
第2行的from
比第1行的before
晚一天,这是一个差距。问题是:对于第3行和第1行,这是正确的,但不应将它们视为结果,因为它们之间还有另一行。
我想到的是这个
SELECT *
FROM mytable mt1
INNER JOIN mytable mt2 ON mt1.reference_id = mt2.reference_id AND mt1.id != mt2.id
WHERE mt1.before IS NOT NULL
AND mt1.from < mt2.from
AND DATE_ADD(mt1.before, INTERVAL 1 DAY) = mt2.from
AND NOT EXISTS(SELECT * FROM mytable mt3 WHERE mt3.id BETWEEN mt1.id AND mt2.id)
但是,此(EXISTS
)的运行速度非常慢。有更好的方法吗?
[edit]查询刚刚结束,尽管我确实希望得到一些结果,但没有得到任何结果。因此,它不仅速度缓慢而且不正确。[/ edit]
执行计划:
1,PRIMARY,mt1,ALL,"mytable_48d78c2b,mytable_261384ee,mytable_849034da",,,,3313021,Using where
1,PRIMARY,mt2,ref,"mytable_48d78c2b,mytable_849034da",mytable_849034da,4,db.mt1.reference_id,1,Using index condition; Using where
2,DEPENDENT SUBQUERY,mt3,index,PRIMARY,mytable_48d78c2b,3,,3313021,Using where; Using index
答案 0 :(得分:2)
(请注意,from
是列名的非常不好的选择,因为它是保留关键字。但是,它是有效的,所以我们就可以了。)
假设没有重叠,则可以使用lag函数查找上一行before
的{{1}}。从那里开始,如果容易检查是否存在间隙,是否lag(before, 1) over (partition by reference_id order by before) as previous_before
from > previous_before
select
`from`, before, `reference_id`
, `from` > lag(before, 1) over (partition by reference_id order by before) as has_gap
from mytable
的作用是查找上一行的lag
值,上一行由window函数的before
子句确定。如果order by
与以前的相同,则没有间隙。
此查询使您在行前留有空白,可以使用lead函数以相同的方式获取行后有空白的行。
请注意,MariaDB仅从10.2.2开始具有窗口功能。