使用MySQL动态创建日期期间

Tri*_*wat 7 php mysql database

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

在此输入图像描述

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

我可以在3月1日,2日和3日显示查询,但显示3月2日的0计数 在此输入图像描述

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

这是mySQL查询

SELECT  `fruitDate` ,  `fruitName` , COUNT( * ) 
FROM  `tbl_fruits` 
WHERE  `fruitName` =  "Grapes"
GROUP BY  `fruitDate
Run Code Online (Sandbox Code Playgroud)

更新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
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

Umb*_*lla 6

3月2日是您的表中不存在的数据,它会从中选择什么?也就是说,因为count()计算每个日期"Grapes" 存在的行数,并且3月2日"Grapes"没有行,count()没有数据要计算,没有任何东西可以告诉数据库插入缺失日期.

为了解决这个问题,我过去所做的是创建一个单独的表Calendar,它包含给定范围的每个日期的行.然后,您可以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`
Run Code Online (Sandbox Code Playgroud)

请注意,count(*)永远不会返回0,因为每个日期都会返回一行.要得到0,计算一个在找到0行时为NULL的字段,在这种情况下,我算一算fruitName

Calendar表可以很简单

CREATE TABLE tbl_Calendar (
  `Date` date NOT NULL PRIMARY KEY
)
Run Code Online (Sandbox Code Playgroud)

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

编辑

在您的编辑中,您似乎正在尝试联接到您的水果表以获取日期,但您在查询中有一些错误,请尝试替换类似的子查询来代替我的Calendar表:

SELECT cal.`Date`, 'Grapes' as `fruitName`, COUNT(f.`fruitName`)
FROM (SELECT `fruitDate` as `Date` FROM `tbl_fruits` GROUP BY `fruitDate`) cal 
LEFT JOIN `tbl_fruits` f ON cal.`Date` = f.`fruitDate`  
WHERE `fruitName` = "Grapes"
GROUP BY cal.`Date`
Run Code Online (Sandbox Code Playgroud)

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


Mos*_*cho 3

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

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
Run Code Online (Sandbox Code Playgroud)

根据日期范围的长度,您可以通过删除表(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
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)