生成日期范围的数据,包括数据中不存在的日期

时间:2011-07-26 13:23:01

标签: mysql sql datetime date-range

这是我的表结构和数据:

CREATE TABLE event (
    EventID INT(11) NOT NULL AUTO_INCREMENT,
    EventDate DATETIME DEFAULT NULL,
    Description VARCHAR(50) DEFAULT NULL,
    PRIMARY KEY (EventID)
);

INSERT INTO event (EventID, EventDate, Description) VALUES
    (1, '2011-01-01 00:00:00', 'Event 1'),
    (2, '2011-03-01 00:00:00', 'Event 2'),
    (3, '2011-06-01 00:00:00', 'Event 3'),
    (4, '2011-09-01 00:00:00', 'Event 4');

这个查询和输出:

SELECT *
FROM EVENT
WHERE EventDate BETWEEN '2011-02-01' AND '2011-03-31'
+---------+---------------------+-------------+
| EventID | EventDate           | Description |
+---------+---------------------+-------------+
|       2 | 2011-03-01 00:00:00 | Event 2     |
+---------+---------------------+-------------+
1 row in set (0.00 sec)

我希望在结果中注入空日期,如下所示:

+---------+---------------------+-------------+
| EventID | EventDate           | Description |
+---------+---------------------+-------------+
| NULL    | 2011-02-01 00:00:00 |  NULL       |
| NULL    | 2011-02-02 00:00:00 |  NULL       |
| NULL    | 2011-02-03 00:00:00 |  NULL       |
∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨
∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧
| NULL    | 2011-02-28 00:00:00 |  NULL       |
|       2 | 2011-03-01 00:00:00 |  Event 2    |
| NULL    | 2011-03-02 00:00:00 |  NULL       |
∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨∨
∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧∧
| NULL    | 2011-03-31 00:00:00 |  NULL       |
+---------+---------------------+-------------+

输出应包含59行:2月28日,3月31日。

我想避免任何硬编码;相反,我需要一个非常灵活的解决方案,使自己适应指定的日期。

3 个答案:

答案 0 :(得分:2)

辅助日历表运行良好。最简单的日历表是​​一列日期。

create table calendar (
    cal_date date primary key
);

您可以使用电子表格或SQL填充它。其上的外部联接将引入数据中不存在的日期。使用GRANT和REVOKE限制权限,并使用任何必要的方法来确保您期望在那里的日期实际存在于那里。我在我的服务器上运行每日报告,确保有'n'行,并验证最早和最晚的日期。

在某些平台上,您可以动态生成一系列日期,并直接或在CTE中使用。 PostgreSQL具有相应的功能;我不知道MySQL是否会这样做。但是,如果你想自己动手,他们就不难写。

答案 1 :(得分:1)

也许你需要一个数据透视表,看看那个

数据透视表架构

name:pivot columns:{i:datatype int}

填充

创建foo表

架构foo

名字:foo column:value datatype varchar

insert into foo
values('0'),
values('1'),
values('2'),
values('3'),
values('4'),
values('5'),
values('6'),
values('7'),
values('8'),
values('9');

- insert 100 values
insert into pivot
select concat(a.value, a.value)
from foo a, foo b

- insert 1000 values
insert into pivot
select concat(a.value, b.value, c.value)
from foo a, foo b, foo c

您的查询

SELECT 
 Event.EventId,
 case when EventDate is null then DATE_ADD(periods.periodstart, INTERVAL auxtable.i DAY)
 else EventDate  end,
 Description

FROM
(
  select id, min(EventDate ) periodstart, max(EventDate) periodend,

  DATEDIFF(max(EventDate),min(EventDate )) as days
  FROM EVEN
  WHERE EventDate BETWEEN '2011-02-01' AND '2011-03-31'
) periods

inner join     

(
  select *
  from pivot
  where i >= 0 and i < 31 //max one month change with your needs
)auxtable
on auxtable.i < periods.days

left join Event
on Event.EventDate = DATE_ADD(periods.periodstart, INTERVAL auxtable.i DAY)

答案 2 :(得分:0)

我很确定在纯SQL中这是不可能的,所以你的选择是:

  • 使用存储过程/函数
  • 在应用代码中执行此操作,这似乎非常简单