2

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

id | dateCreated | numOfUsers

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

我的行包含过去 4 个月的数据,但是丢失了很多天,我想使用 SQL 找出丢失的天数,有什么想法可以编写这个查询吗?

我怀疑您通过某种方式获取日期列表并将这些与数据库中的值进行比较来解决此问题。

我知道您可以使用 PHP 或其他使用多个查询的编程语言来执行此操作,但是如果可能的话,我想在数据库级别执行此操作。

提前致谢

4

6 回答 6

2

对于 PostgreSQL 来说,使用 generate_series() 函数动态生成“日期列表”非常容易:

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; 
于 2011-10-17T14:47:03.970 回答
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

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

于 2011-10-17T14:38:43.740 回答
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 而不是在第二个比较表中添加一天来返回缺失日期范围中的最后一个日期。

于 2013-01-10T16:51:05.140 回答
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)
于 2011-10-17T14:24:35.737 回答
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
;
于 2011-10-17T15:21:02.283 回答
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. 处理报告期开始时缺失的日期(配对中没有 Date1)
6. 处理报告期结束时缺失的日期(成对中没有 Date2)

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

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


如果您不相信,我建议您尝试不同的选项,并亲自看看索引日期表与其他选项相比有多快。

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

于 2011-10-17T14:20:10.010 回答