MySQL按日期分组和计数,包括缺少的日期
之前,我做了以下工作,从报告表中获取每日计数MySQL按日期分组和计数,包括缺少的日期,mysql,date,mysql5,Mysql,Date,Mysql5,之前,我做了以下工作,从报告表中获取每日计数 SELECT COUNT(*) AS count_all, tracked_on FROM `reports` WHERE (domain_id = 939 AND tracked_on >= '2014-01-01' AND tracked_on <= '2014-12-31') GROUP BY tracked_on ORDER BY tracked_on ASC; 然而,我希望用0来填充缺失的日期 差不多 我的另一次尝
SELECT COUNT(*) AS count_all, tracked_on
FROM `reports`
WHERE (domain_id = 939 AND tracked_on >= '2014-01-01' AND tracked_on <= '2014-12-31')
GROUP BY tracked_on
ORDER BY tracked_on ASC;
然而,我希望用0来填充缺失的日期 差不多
我的另一次尝试是:
select count(*), all_dates.Date as the_date, domain_id
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
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) as a
cross join (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) as b
cross join (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) as c
) all_dates
inner JOIN reports r
on all_dates.Date = r.tracked_on
where all_dates.Date between '2014-01-01' and '2014-12-31' AND domain_id = 939 GROUP BY the_date order by the_date ASC ;
结果:
count(*) the_date domain_id
38 2014-09-03 939
8 2014-09-04 939
上述查询的最小数据:子查询的
所有日期
仅从当前日期(curdate()
)开始回溯。如果要包括将来的日期,请将子查询的第一行更改为类似以下内容:
select '2015-01-01' - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
您需要一个
外部联接
在开始和结束之间每天到达,因为如果您使用内部联接
,则输出将仅限于联接的日期(即报告表中的日期)
此外,当您使用外部联接时
必须注意where子句中的条件不会导致隐式内部联接
;例如,和domain_id=1如果在where子句中使用,将抑制不满足该条件的任何行,但当用作联接条件时,它仅限制报表表的行
SELECT
COUNT(r.domain_id)
, all_dates.Date AS the_date
, domain_id
FROM (
SELECT DATE_ADD(curdate(), INTERVAL 2 MONTH) - INTERVAL (a.a + (10 * b.a) ) DAY as Date
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) as a
CROSS JOIN (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) as b
) all_dates
LEFT OUTER JOIN reports r
ON all_dates.Date = r.tracked_on
AND domain_id = 1
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
the_date
ORDER BY
the_date ASC;
通过使用DATE\u ADD()
将起点推向未来,我还更改了all_dates派生表,并减小了它的大小。这两个都是选项,可以根据需要进行调整
要获得每一行的域id(如您的问题所示),您需要使用以下内容:;注意,您可以使用特定于MySQL的IFNULL()
,但我使用了更通用的SQL的COALESCE()
。然而,这里所示的@parameter的使用是特定于MySQL的
SET @domain := 1;
SELECT
COUNT(r.domain_id)
, all_dates.Date AS the_date
, coalesce(domain_id,@domain) AS domain_id
FROM (
SELECT DATE_ADD(curdate(), INTERVAL 2 month) - INTERVAL (a.a + (10 * b.a) ) DAY as Date
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) as a
CROSS JOIN (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) as b
) all_dates
LEFT JOIN reports r
ON all_dates.Date = r.tracked_on
AND domain_id = @domain
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
the_date
ORDER BY
the_date ASC;
如果你愿意,考虑下面简单的两步行动:1。如果您还没有这样做,请提供适当的DDL(和/或SQLFIDLE),以便我们可以更轻松地复制问题。2.如果您还没有这样做,请提供与步骤1中提供的信息相对应的所需结果集。当然,这是包含行的最小表。这只是一个建议,您不必遵循它。太棒了!这就行了:)有可能把一组日子也按周和月分组吗?与我们所有“天”的情况类似,我可以拥有一年中的所有周。很高兴你的回答是这样的-请花一秒钟点击勾号-这表明答案已被接受。可以使用较大的时间单位,如周、月、年,但对于这些时间单位,我们通常使用日期范围(从/到日期对)。
select '2015-01-01' - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
SELECT
COUNT(r.domain_id)
, all_dates.Date AS the_date
, domain_id
FROM (
SELECT DATE_ADD(curdate(), INTERVAL 2 MONTH) - INTERVAL (a.a + (10 * b.a) ) DAY as Date
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) as a
CROSS JOIN (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) as b
) all_dates
LEFT OUTER JOIN reports r
ON all_dates.Date = r.tracked_on
AND domain_id = 1
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
the_date
ORDER BY
the_date ASC;
SET @domain := 1;
SELECT
COUNT(r.domain_id)
, all_dates.Date AS the_date
, coalesce(domain_id,@domain) AS domain_id
FROM (
SELECT DATE_ADD(curdate(), INTERVAL 2 month) - INTERVAL (a.a + (10 * b.a) ) DAY as Date
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) as a
CROSS JOIN (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) as b
) all_dates
LEFT JOIN reports r
ON all_dates.Date = r.tracked_on
AND domain_id = @domain
WHERE all_dates.Date BETWEEN '2014-09-01' AND '2014-09-30'
GROUP BY
the_date
ORDER BY
the_date ASC;