查找“之间没有任何内容”的相关行

时间:2019-03-22 09:02:18

标签: sql mariadb

我有一张像这样的桌子:

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

1 个答案:

答案 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开始具有窗口功能。