SQL:从数据库中获取所有缺少的日期记录

时间:2011-10-17 14:15:19

标签: php sql database gaps-and-islands

我有一个具有以下结构的数据库表

id | dateCreated | numOfUsers

典型行为1,'2011-10-13 12:00:00',4

我的行包含过去4个月的数据,但是缺少了几天,我想找出使用​​SQL的缺失日期,我是如何编写此查询的?

我怀疑你通过某种方式获取日期列表并将它们与数据库中的值进行比较。

我知道你可以使用PHP或其他使用多个查询的编程语言来做到这一点但是如果可能的话我想在数据库级别上这样做。

提前致谢

6 个答案:

答案 0 :(得分:2)

对于使用generate_series()函数生成“日期列表”的PostgreSQL非常容易:

with all_dates as (
   select cast((current_date - interval '4' month) as date) + i as the_date
   from generate_series(0, extract(day from current_date - (current_date - interval '4' month))::int) as i
) 
select ad.the_date, 
       y.id,
       y.numOfUsers
from all_dates t
  left join your_table y ON y.dateCreated = t.the_date; 

答案 1 :(得分:1)

AFAIK没有一个声明可以实现这个适用于所有数据库...对于Oracle,你可以这样做(MyTable是你要检查丢失日期的数据库表):

SELECT * FROM
(
SELECT A.MinD + MyList.L TheDate FROM
(SELECT  MIN (dateCreated ) MinD FROM MyTable) A,
(SELECT LEVEL - 1 L FROM DUAL CONNECT BY LEVEL <= (SELECT  Max (dateCreated ) - MIN (dateCreated ) + 1 FROM MyTable)) MyList
) D WHERE D.TheDate NOT IN ( SELECT dateCreated FROM MyTable T)

答案 2 :(得分:1)

假设MySQL,您可以使用变量在查询结果中的每一行中携带状态:

SELECT @last := 'date you want to start with';

SELECT id, dateCreated, DATE_DIFF(dateCreated, @last) AS diff, @last := dateCreated
FROM yourtable
ORDER BY dateCreated ASC
HAVING diff > 1

请注意,这不会返回实际缺失的天数,但会在缺失日期之后返回行,以及缺失天数。

答案 3 :(得分:1)

有一种方法可以在没有日期表,开始和结束日期或任何其他形式的迭代的情况下完成。

select DATEADD(day,1,left.dateCreated) as MissingDates
from dbo.MyTable as left
left outer join dbo.MyTable as right on DATEADD(day,1,left.dateCreated) = right.entry_time
where right.dateCreated is null

这将返回一列缺失日期的开始日期。然后,您还可以创建另一列,通过减去1而不是将一天添加到第二个比较表来返回缺失日期范围中的最后一个日期。

答案 4 :(得分:0)

正如您所述,最简单的方法(在我看来)是从所有日期的表开始。你必须自己创造,并假设你已经完成,这里有几个选项...

SELECT
  *
FROM
  calendar    -- Your manually created table of dates
LEFT JOIN
  yourTable
    ON yourTable.DateField = calendar.DateField
WHERE
  yourTable.DateField IS NULL
  AND calendar.DateField >= @reportFirstDate
  AND calendar.DateField <= @reportLastdate

或者...

SELECT
  *
FROM
  calendar    -- Your manually created table of dates
WHERE
  NOT EXISTS (SELECT * FROM yourTable WHERE yourTable.DateField = calendar.DateField)
  AND calendar.DateField >= @reportFirstDate
  AND calendar.DateField <= @reportLastdate

修改

尽管维护此日期列表感觉“不整洁”,但它对此类查询具有巨大的性能优势。

使用日期表,您可以查看两个索引并检查一个索引中存在的内容,而不是另一个索引。

没有日期表,你有一个更复杂的方法...
1.记下表中的每条记录 2.自我加入表格中的下一条记录 3.如果它们是连续日期,则丢弃它们(保持记录之间有间隙)
4.对于每一对,循环,填写缺少的日期
5.处理报告期开始时缺少的日期(成对中没有日期1)
6.处理报告期末失踪的日期(成对中没有日期2)

使用日期创建临时表可能实际上更快,直接进行,然后再次删除表。如果是这样的话,你为什么不维护日期表呢?

  1. 只有一张100年的桌子,忘了它
  2. 使用非常快速的代码来使所有代码中的日期保持最新

  3. 如果您不相信,我建议您试用不同的选项,并亲自了解索引日期表与其他选项的比较速度。

    (更不用说多短,可读和可维护)

答案 5 :(得分:0)

MySQL的:

假设我们有表yourTable和日期字段d

set @day = 0;

select v.y as `month`, v.m as `month`, v.d as `day`
from 
(
   select y_m.y, Y_m.m, dd.d
   from
   (
     select distinct year(d) y, month(d) m, DAY(LAST_DAY(yourTable.d)) max_days from yourTable
   ) y_m,
   (
   select  @day := @day+1 as `d`
   from
     information_schema.tables
   limit 32
   ) dd
   where y_m.max_days >= dd.d
) v
left join
   yourTable on (year(yourTable.d) = v.y and month(yourTable.d) = v.m and day(yourTable.d) = v.d)
where yourTable.d is null
;