2014-01-12 50 views
0

我想要过去12个月的预订日期计数,但对于没有预订的月份,我需要得到空值或0.我的查询下面跳过了几个月没有预订,MySQL查询 - 每个月的过去12个月的记录返回值

SELECT bs.date,CONCAT(MONTHNAME(bs.date),' ', YEAR(bs.date)) as 'Month',count(*) AS Bookings, CONCAT(us.firstName,' ', us.lastName) as 'Name' from bookings bs RIGHT JOIN users us ON bs.clientID = us.recNo 
     WHERE bs.managerID = 6 AND bs.clientID = 1900 
     AND date > DATE_SUB(CURDATE(), INTERVAL 11 MONTH) AND date <= CURDATE() GROUP BY YEAR(date), month(date) 

有人可以帮忙吗?

回答

0

您可以通过硬编码做到这一点12个月在那里和CROSS JOIN与users然后左加入bookings(我听到别人提到,左加入比右加快快)。 所以查询下面

SELECT bs.date, 
     CONCAT(MONTHNAME(hardcoded.date),' ', YEAR(hardcoded.date)) as 'Month', 
     count(bs.date) AS Bookings, 
     CONCAT(us.firstName,' ', us.lastName) as 'Name' 
from 
(SELECT CURDATE() as date UNION 
SELECT CURDATE()-INTERVAL 1 MONTH UNION 
SELECT CURDATE()-INTERVAL 2 MONTH UNION 
SELECT CURDATE()-INTERVAL 3 MONTH UNION 
SELECT CURDATE()-INTERVAL 4 MONTH UNION 
SELECT CURDATE()-INTERVAL 5 MONTH UNION 
SELECT CURDATE()-INTERVAL 6 MONTH UNION 
SELECT CURDATE()-INTERVAL 7 MONTH UNION 
SELECT CURDATE()-INTERVAL 8 MONTH UNION 
SELECT CURDATE()-INTERVAL 9 MONTH UNION 
SELECT CURDATE()-INTERVAL 10 MONTH UNION 
SELECT CURDATE()-INTERVAL 11 MONTH 
)as hardcoded 
CROSS JOIN users us 
LEFT JOIN bookings bs ON (MONTH(bs.date) = MONTH(hardcoded.date) 
         AND YEAR(bs.date) = YEAR(hardcoded.date)) 
         AND bs.clientID = us.recNo 
WHERE ((bs.managerID = 6 AND bs.clientID = 1900) 
     OR 
     (bs.managerID IS NULL AND bs.clientID IS NULL)) 
AND hardcoded.date > DATE_SUB(CURDATE(), INTERVAL 11 MONTH) AND hardcoded.date <= CURDATE() 
GROUP BY Month,Name 
ORDER BY hardcoded.date 

看到这个(sqlFiddle
注:因为有一个WHERE条件检查经理ID和clientID的过滤出我们想要的结果,但我们也想返回值为空意味着它的行我们硬编码的月份没有预订。这就是为什么有OR (bs.managerID IS NULL AND bs.clientID IS NULL)
此外,当前GROUP BY是非标准的,因为它不是将选择的第一个字段分组所以现在如果您在一个月内有2个或更多预订,它只是返回一个不知道哪个日期的日期一个看起来很奇怪,你可能想要选择hardcoded.date而不是GROUP BY,这样你就有了ANSI标准的GROUP BY。或者,对于select中的第一个字段,最好使用MIN()或MAX()到MIN(bs.date)或MAX(bs.date)的集合函数,以确保它始终返回第一个预订日期或最后一个预订如果该月份有2次或更多预订,则每月的日期不会在GROUP BY中列出。

我不知道,如果CROSS JOIN被杀死你的应用程序或没有,但你可以试试这个 它没有CROSS JOIN,但保留您的权利JOIN

SELECT bs.date, 
CONCAT(MONTHNAME(hardcoded.date),' ', YEAR(hardcoded.date)) as 'Month', 
count(bs.date) AS Bookings, 
CONCAT(us.firstName,' ', us.lastName) as 'Name' 
from 
(SELECT CURDATE() as date UNION 
SELECT CURDATE()-INTERVAL 1 MONTH UNION 
SELECT CURDATE()-INTERVAL 2 MONTH UNION 
SELECT CURDATE()-INTERVAL 3 MONTH UNION 
SELECT CURDATE()-INTERVAL 4 MONTH UNION 
SELECT CURDATE()-INTERVAL 5 MONTH UNION 
SELECT CURDATE()-INTERVAL 6 MONTH UNION 
SELECT CURDATE()-INTERVAL 7 MONTH UNION 
SELECT CURDATE()-INTERVAL 8 MONTH UNION 
SELECT CURDATE()-INTERVAL 9 MONTH UNION 
SELECT CURDATE()-INTERVAL 10 MONTH UNION 
SELECT CURDATE()-INTERVAL 11 MONTH 
)as hardcoded 
LEFT JOIN bookings bs ON (MONTH(bs.date) = MONTH(hardcoded.date) 
AND YEAR(bs.date) = YEAR(hardcoded.date)) 
RIGHT JOIN users us ON (bs.clientID = us.recNo OR bs.clientID IS NULL) 
WHERE ((bs.managerID = 6 AND bs.clientID = 1900) 
OR 
(bs.managerID IS NULL AND bs.clientID IS NULL)) 
AND hardcoded.date > DATE_SUB(CURDATE(), INTERVAL 11 MONTH) AND hardcoded.date <= CURDATE() 
GROUP BY Month,Name 
ORDER BY hardcoded.date 

试图加入之前缩小记录

SELECT MIN(bs.date) as FirstBookingDate, 
CONCAT(MONTHNAME(hardcoded.date),' ', YEAR(hardcoded.date)) as 'Month', 
count(bs.date) AS Bookings, 
CONCAT(us.firstName,' ', us.lastName) as 'Name' 
from 
(SELECT CURDATE() as date UNION 
SELECT CURDATE()-INTERVAL 1 MONTH UNION 
SELECT CURDATE()-INTERVAL 2 MONTH UNION 
SELECT CURDATE()-INTERVAL 3 MONTH UNION 
SELECT CURDATE()-INTERVAL 4 MONTH UNION 
SELECT CURDATE()-INTERVAL 5 MONTH UNION 
SELECT CURDATE()-INTERVAL 6 MONTH UNION 
SELECT CURDATE()-INTERVAL 7 MONTH UNION 
SELECT CURDATE()-INTERVAL 8 MONTH UNION 
SELECT CURDATE()-INTERVAL 9 MONTH UNION 
SELECT CURDATE()-INTERVAL 10 MONTH UNION 
SELECT CURDATE()-INTERVAL 11 MONTH 
)as hardcoded 
CROSS JOIN (SELECT * FROM users WHERE recNo = 1900) us 
LEFT JOIN (SELECT * FROM bookings WHERE managerID = 6 AND clientID = 1900 
      AND date BETWEEN CURDATE()-INTERVAL 11 MONTH AND CURDATE()) bs 
ON (MONTH(bs.date) = MONTH(hardcoded.date) 
AND YEAR(bs.date) = YEAR(hardcoded.date)) 
GROUP BY Month,Name 
ORDER BY hardcoded.date 
+0

它在小提琴中运行良好,但查询没有返回任何东西在phpmyadmin,事实上它会被击中,直到我手动杀死应用程序。任何想法? – Deepa

+0

你的用户表有多大? –

+0

不确定CROSS JOIN是否正在查杀您,具体取决于您的用户表的大小。但我只是在没有CROSS JOIN的情况下用底部的另一个查询更新了我的答案(但保留了您的右连接) –

0

我对MySQL的语法不是很熟悉,但是我首先创建一个只有月和年整数列的临时表,并为过去一年的每个月插入一条记录。使用DATESUB和递减计数器的简单WHILE循环可能就足够了。 然后,将您的预订/用户查询左侧加入临时表,就像现在一样。这应该会导致没有预订的月份仍显示在输出中。 我不相信你只能在一个SELECT语句中把它关闭。

0

您可以使用子查询的是,因为它证明了在这个SQL Fiddle

select y, n, concat(monthname(makedate(y, n*29)), ' ', y) yearmonth FROM 
(select n,y FROM 
(select 1 as n from dual 
Union All 
select 2 as n from dual 
Union All 
select 3 as n from dual 
Union All 
select 4 as n from dual 
Union All 
select 5 as n from dual 
Union All 
select 6 as n from dual 
Union All 
select 7 as n from dual 
Union All 
select 8 as n from dual 
Union All 
select 9 as n from dual 
Union All 
select 10 as n from dual 
Union All 
select 11 as n from dual 
Union All 
select 12 as n from dual) as months 
inner join (select distinct year(dt) y from test) as years on 1=1) AS ym 
left join test on month(dt) = n and year(dt) = y 
group by n, y order by y, n 

应用上面查询到您的语句:

select y, n, concat(monthname(makedate(y, n*29)), ' ', y) yearmonth FROM 
(select n,y FROM 
(select 1 as n from dual 
Union All 
select 2 as n from dual 
Union All 
select 3 as n from dual 
Union All 
select 4 as n from dual 
Union All 
select 5 as n from dual 
Union All 
select 6 as n from dual 
Union All 
select 7 as n from dual 
Union All 
select 8 as n from dual 
Union All 
select 9 as n from dual 
Union All 
select 10 as n from dual 
Union All 
select 11 as n from dual 
Union All 
select 12 as n from dual) as months 
inner join (select distinct year(dt) y 
from bookings 
where date > DATE_SUB(CURDATE(), INTERVAL 11 MONTH) AND date <= CURDATE()) as years on 1=1) AS ym 
left join (
SELECT MONTH(bs.date) AS mth, YEAR(bs.date) as yr, count(*) AS Bookings, 
CONCAT(us.firstName,' ', us.lastName) as 'Name' 
from bookings bs RIGHT JOIN users us ON bs.clientID = us.recNo 
WHERE bs.managerID = 6 AND bs.clientID = 1900 
AND date > DATE_SUB(CURDATE(), INTERVAL 11 MONTH) AND date <= CURDATE() 
GROUP BY MONTH(bs.date), YEAR(bs.date)) as test on mth = n and yr = y 
group by n, y order by y, n