Mysql 间隙检测-确定跳过/错过的日期

Mysql 间隙检测-确定跳过/错过的日期,mysql,sql,datetime,gaps-and-islands,Mysql,Sql,Datetime,Gaps And Islands,我有一个数据库表,其中有ID和日期范围的记录 有些ID的导入日期最初为“日期到”列。我只对月份感兴趣,像2018-06-01 00:00:00这样的日期代表2018年的一个月。我对天和时间不感兴趣,因为我不能使用00,所以设置了01天 2019-01-01的起始日期和2019-01-01的截止日期代表一个月 2018-09-01日期从和2018-11-01日期到表示从9月1日到11月31日的时间间隔 所以我想要的是得到ID-s,其中有间隔、错过的月份或间隔的月份。如何使用sql解决此问题?从哪种

我有一个数据库表,其中有ID和日期范围的记录

有些ID的导入日期最初为“日期到”列。我只对月份感兴趣,像2018-06-01 00:00:00这样的日期代表2018年的一个月。我对天和时间不感兴趣,因为我不能使用00,所以设置了01天

2019-01-01的起始日期和2019-01-01的截止日期代表一个月

2018-09-01日期从和2018-11-01日期到表示从9月1日到11月31日的时间间隔


所以我想要的是得到ID-s,其中有间隔、错过的月份或间隔的月份。如何使用sql解决此问题?从哪种方式开始?

如果您不使用8.0,可以创建一个工作表来保存数据:

 CREATE TABLE _gap_cal (
      ID int not null,
      date_to date not null,
      rid int not null auto_increment,
      date_from date null,
      PRIMARY KEY (ID,rid)
 ) ENGINE=MYISAM;
然后按如下方式填充数据:

INSERT _gap_cal(ID,date_from,date_to,rid)
SELECT ID,COALESCE(date_from,'1900-01-01'),date_to,NULL
FROM your_data_table
ORDER BY ID,date_to;
出于测试目的,我只需直接插入一些数据:

INSERT _gap_cal(ID,date_from,date_to,rid)
VALUES (6545,'1900-01-01','2018-06-01',NULL),
  (6545,'2018-09-01','2018-11-01',NULL),
  (6545,'2019-01-01','2019-01-01',NULL),
  (2421,'2019-04-01','2019-06-01',NULL),
  (2421,'2019-07-01','2019-07-01',NULL),
  (2421,'2019-09-01','2019-11-01',NULL);

SELECT * FROM _gap_cal;
以下查询将为您提供带间隙的ID和日期范围:

SELECT c.ID,c.date_from,c.date_to, p.date_from as previous_date_from
FROM _gap_cal p
INNER JOIN _gap_cal c
ON p.ID=c.ID
AND p.rid=c.rid-1
AND TIMESTAMPADD(MONTH,1, p.date_to)<>c.date_from
ORDER BY c.ID,c.date_from;

如果未使用8.0,则可以创建一个工作表来保存数据:

 CREATE TABLE _gap_cal (
      ID int not null,
      date_to date not null,
      rid int not null auto_increment,
      date_from date null,
      PRIMARY KEY (ID,rid)
 ) ENGINE=MYISAM;
然后按如下方式填充数据:

INSERT _gap_cal(ID,date_from,date_to,rid)
SELECT ID,COALESCE(date_from,'1900-01-01'),date_to,NULL
FROM your_data_table
ORDER BY ID,date_to;
出于测试目的,我只需直接插入一些数据:

INSERT _gap_cal(ID,date_from,date_to,rid)
VALUES (6545,'1900-01-01','2018-06-01',NULL),
  (6545,'2018-09-01','2018-11-01',NULL),
  (6545,'2019-01-01','2019-01-01',NULL),
  (2421,'2019-04-01','2019-06-01',NULL),
  (2421,'2019-07-01','2019-07-01',NULL),
  (2421,'2019-09-01','2019-11-01',NULL);

SELECT * FROM _gap_cal;
以下查询将为您提供带间隙的ID和日期范围:

SELECT c.ID,c.date_from,c.date_to, p.date_from as previous_date_from
FROM _gap_cal p
INNER JOIN _gap_cal c
ON p.ID=c.ID
AND p.rid=c.rid-1
AND TIMESTAMPADD(MONTH,1, p.date_to)<>c.date_from
ORDER BY c.ID,c.date_from;

在MySQL5.x中,您可以非常缓慢地使用相关查询来确定差距。查询的大致轮廓:

SELECT *
FROM (
    SELECT id, start_date, start_date - INTERVAL 1 MONTH AS prev_end_date_exp, (
        SELECT end_date
        FROM yourdata AS x
        WHERE id = t.id AND end_date < t.start_date
        ORDER BY end_date DESC
        LIMIT 1
    ) AS prev_end_date_act
    FROM yourdata AS t
) AS sq
WHERE prev_end_date_exp <> prev_end_date_act

这将为您提供一个行列表,其中包含其自身与前一行之间的间隔以及范围,而不是日期列表。

在MySQL 5.x中,您可以非常缓慢地使用相关查询来识别间隔。查询的大致轮廓:

SELECT *
FROM (
    SELECT id, start_date, start_date - INTERVAL 1 MONTH AS prev_end_date_exp, (
        SELECT end_date
        FROM yourdata AS x
        WHERE id = t.id AND end_date < t.start_date
        ORDER BY end_date DESC
        LIMIT 1
    ) AS prev_end_date_act
    FROM yourdata AS t
) AS sq
WHERE prev_end_date_exp <> prev_end_date_act


这将为您提供一个行列表,其中包含其自身与前一行之间的间隔以及范围,而不是日期列表。

首先需要一个日历表。从日历表到主表进行左联接,以找出日历月中没有匹配项的行。@对不起,我将提供一个在线示例。您使用的是mysql 8.0还是bellow?查询可能会有很大的不同。我使用的mysql 5.7版本,我会尝试你的答案:你需要一个日历表来开始。从日历表到主表进行左联接,以找出日历月中没有匹配项的行。@对不起,我将提供一个在线示例。您使用的是mysql 8.0还是bellow?我使用的是mysql 5.7版本,我会尝试你的答案:你能解释一下你的sql查询吗?通过您的查询,我得到了一些有间隙的记录,如果我使用@Salman查询,我会得到另一个有间隙的记录,但为什么?此查询可以识别这样的间隙,但无法识别这样的间隙,因此我注意到,此查询显示的间隔和日期是原来的两倍。您能解释一下您的sql查询吗?通过你的查询,我得到了一些有间隙的记录,如果我使用@Salman查询,我会得到另一个有间隙的记录,但是为什么?这个查询可以识别像这样的间隙,但不能识别像这样的间隙,所以我注意到,这个查询显示的间隔和日期是原来的两倍。使用你的查询,我得到的结果比使用PeterHe查询的结果要多,但现在这将显示所有有间隙的记录?我如何确定?返回的所有记录都有间隙您的查询无法识别这样的间隙:但是可以识别是的,我注意到这个相关查询显示了间隔之间的间隙,PeterHe查询显示了相互覆盖的间隔之间的日期使用您的查询我得到了比使用PeterHe查询更多的结果,但现在这将显示所有有间隙的记录?我如何确定?返回的所有记录都有间隙您的查询无法识别这样的间隙:但是可以识别是的,我注意到这个相关查询显示了间隔之间的间隙,而PeterHe查询显示了相互覆盖的间隔之间的日期