【问题标题】:How to find missing rows (dates) in a mysql table?如何在 mysql 表中查找丢失的行(日期)?
【发布时间】:2011-07-28 05:16:23
【问题描述】:

我已经尝试了几个类似这样的主题:How to find missing data rows using SQL? 这里,但我无法在我的情况下使用它。

我在 MySQL 中有一个名为 posts 的表,我每天都在其中保存用户日记。有时用户会忘记写一天的帖子,我想让他们稍后再提交。 所以数据库结构是这样的:

date           userid
2011-10-01     1
2011-10-02     1
(missing)
2011-10-04     1
2011-10-05     1
(missing)
2011-10-07     1

所以我想在这个缺失行的表格中向用户显示一个缺失日期的下拉列表,以便他可以选择他想要提交帖子的日期。

我该怎么做? 谢谢。

【问题讨论】:

    标签: mysql gaps-and-islands


    【解决方案1】:

    查找缺失日期的最简单方法是使用日历表。我已经发布了code to create and populate a calendar table for PostgreSQL;你应该能够毫无困难地适应它。

    有了日历表,您的查询就非常简单且易于理解。要查找 2011 年 10 月的缺失日期,您可以使用这些方法。 (猜测你的“帖子”表。)

    select c.cal_date
    from calendar c
    left join posts p on (c.cal_date = p.date)
    where p.date is null
      and c.cal_date between '2011-10-01' and '2011-10-31'
      and p.userid = 1
    order by c.cal_date
    

    【讨论】:

      【解决方案2】:

      如果您有日期表,这些类型的查询最容易解决。 在您的数据库中,一次性运行此批次以创建填充的日期表。

      DROP PROCEDURE IF EXISTS FillDateTable;
      
      delimiter //
      CREATE PROCEDURE FillDateTable()
          LANGUAGE SQL
          NOT DETERMINISTIC
          CONTAINS SQL
          SQL SECURITY DEFINER
          COMMENT ''
      BEGIN
        drop table if exists datetable;
        create table datetable (thedate datetime primary key, isweekday smallint);
      
        SET @x := date('2000-01-01');
        REPEAT 
          insert into datetable (thedate, isweekday) SELECT @x, case when dayofweek(@x) in (1,7) then 0 else 1 end;
          SET @x := date_add(@x, interval 1 day);
          UNTIL @x >= '2030-12-31' END REPEAT;
      END//
      delimiter ;
      
      CALL FillDateTable;
      

      然后你可以使用常规的左连接

      SELECT thedate
      FROM datetable
      LEFT JOIN posts on posts.date = datetable.thedate
      WHERE posts.date IS NULL
      

      当然,您不希望所有“缺失”日期从 2000 年到 2030 年。将其限制为帖子表中的 MIN 和 MAX 日期(对于用户),即

      SELECT thedate
      FROM datetable
      INNER JOIN (select min(date) postStart, max(date) postEnd
                  FROM posts
                  where userid=123) p on datetable.thedate BETWEEN p.postStart and p.postEnd
      LEFT JOIN posts on posts.date = datetable.thedate
      WHERE posts.date IS NULL
      

      【讨论】:

      • @Sallar / 性能相当不错。 10,000 个日期的空间.. 可以忽略不计。大约100kb? 1MB? (疯狂的猜测),但肯定一点也不大。
      • 从 2000 年到 2101 年生成,大约需要 1.5Mb
      【解决方案3】:

      您可以每次(一天结束)自动输入一个空帖子,其中包含空标题、空内容但实际日期。然后,如果用户想要添加前一天的帖子,则显示所有标题和内容为空的帖子并更新他选择的帖子。

      这不应该是空间问题,如果他们写的比他们错过的多。例如,如果他们写了 4 天却错过了 1 天。

      此外,您将运行一个脚本并删除具有空标题、空内容和日期早于 X 天的条目。如果他们 X 天没有添加丢失的帖子,他们可能永远不会添加。

      如果我的解决方案琐碎/过于抽象,我深表歉意。

      【讨论】:

      • 感谢您的回复。我有想过,但是有 2000 多个用户,他们可能有很多遗漏的项目。我不喜欢我的表中有那么多空行:(
      【解决方案4】:
      select  
          t0.date,
          t1.date1
          if(t1.date1 is null, date_add(t0.date, interval 1 day), '') missing_date
      from
      (select date from posts group by date) t0
      left join
      (select date_add(date, interval 1 day) date1 from posts group by date) t1
      on t0.date = t1.date1
      order by t0.date asc
      

      您可以通过这种方式找到丢失的日期。请注意,您需要删除最后一行,您可以选择适合您的方式来实现。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多