使用MySQL动态创建日期期间

时间:2012-03-04 05:10:42

标签: php mysql database

我试图从3月1日到3日的日期获得葡萄计数。

enter image description here

你会注意到3月2日 - 没有插入葡萄..

我可以在3月1日,2日和3日显示查询,但显示3月2日的0计数 enter image description here

在上图中,只显示有葡萄的日期..

这是mySQL查询

SELECT  `fruitDate` ,  `fruitName` , COUNT( * ) 
FROM  `tbl_fruits` 
WHERE  `fruitName` =  "Grapes"
GROUP BY  `fruitDate

更新2:

使用此查询:

SELECT f.fruitDate, f.fruitName, f1.count FROM tbl_fruits f
    LEFT JOIN (SELECT fruitDate, COUNT(*) as count from tbl_fruits d WHERE d.fruitName='Grapes' GROUP BY d.fruitDate) as f1 ON (f.fruitDate = f1.fruitDate) 
    GROUP BY f.fruitDate

我得到了这个结果..但它显示了不同的水果......我的查询有问题吗?

enter image description here

2 个答案:

答案 0 :(得分:6)

3月2日是您的表中不存在的数据,它会从中选择什么?也就是说,由于count()计算每个日期“Grapes”的存在的行数,并且3月2日“Grapes”没有行,{{1}没有数据可以统计,没有任何东西可以告诉数据库插入缺少的日期。

为了解决这个问题,我过去所做的是创建一个单独的表Calendar,它包含给定范围的每个日期的行。然后,您可以count()到此表,以确保为每个日期选择一行。它可能看起来像这样:

JOIN

请注意,SELECT cal.`Date`, 'Grapes' as `fruitName`, COUNT(f.`fruitName`) FROM `tbl_Calendar` cal LEFT JOIN `tbl_fruits` f ON cal.`Date` = f.`fruitDate` WHERE `fruitName` = "Grapes" AND '2012-03-01' <= cal.`Date` AND cal.`Date` <= '2012-03-03' GROUP BY cal.`Date` 永远不会返回0,因为每个日期都会返回一行。要获得0,请计算在找到0行时为NULL的字段,在这种情况下,我计算count(*)

Calendar表可以像

一样简单
fruitName

从选定的开始日期到结束日期,您将使用简单的PHP循环填充。您可能会发现添加其他列以缓存诸如星期几或假期等内容的好处,但此任务不需要这样做。

修改

在你的编辑中,你似乎试图加入你的水果表来获取日期,但你的查询中有一些错误,而是尝试用类似的子查询代替我的Calendar表:

CREATE TABLE tbl_Calendar (
  `Date` date NOT NULL PRIMARY KEY
)

但请注意,虽然这将填补其他一些水果没有遗漏的葡萄缺失日期,但它不会填写所有水果缺少的日期。

答案 1 :(得分:2)

请记住,创建一个不需要创建表的日期范围有一个动态(有点难看)的解决方案:

select aDate from (
  select @maxDate - interval (a.a+(10*b.a)+(100*c.a)+(1000*d.a)) day aDate from
  (select 0 as a union all select 1 union all select 2 union all select 3
   union all select 4 union all select 5 union all select 6 union all
   select 7 union all select 8 union all select 9) a, /*10 day range*/
  (select 0 as a union all select 1 union all select 2 union all select 3
   union all select 4 union all select 5 union all select 6 union all
   select 7 union all select 8 union all select 9) b, /*100 day range*/
  (select 0 as a union all select 1 union all select 2 union all select 3
   union all select 4 union all select 5 union all select 6 union all
   select 7 union all select 8 union all select 9) c, /*1000 day range*/
  (select 0 as a union all select 1 union all select 2 union all select 3
   union all select 4 union all select 5 union all select 6 union all
   select 7 union all select 8 union all select 9) d, /*10000 day range*/
  (select @minDate := '2001-01-01', @maxDate := '2002-02-02') e
) f
where aDate between @minDate and @maxDate

根据日期范围的长度,您可以通过删除表格(d,c,b和a)并从中删除它们来减少动态生成结果的数量(10000天意味着超过27年的记录,每个代表一天)上层公式。通过设置@minDate@maxDate变量,您可以指定要过滤结果的日期。

修改

我看到你还在寻找解决方案。试试这个:

select c.date, f.fruitName, count(f.fruitName = 'Grapes')
from tbl_calendar c
left join tbl_fruits f
on c.date = f.fruitDate and f.fruitName = 'Grapes'
group by c.date, f.fruitName

如果您还想从创建的表中过滤额外日期,请使用以下查询:

select c.date, f.fruitName, count(f.fruitName = 'Grapes')
from tbl_calendar c
left join tbl_fruits f
on c.date = f.fruitDate and f.fruitName = 'Grapes'
group by c.date, f.fruitName
having c.date between
  (select min(fruitDate) from tbl_fruits) and
  (select max(fruitDate) from tbl_fruits)