MySQL Query - 每个月过去12个月记录的返回值

时间:2014-01-12 23:39:41

标签: mysql sql

我正在尝试超过12个月的预订日期计数,但是对于没有预订的月份,我需要获得Null或0.我的查询会跳过没有预订的月份,

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) 

有人可以帮忙吗?

3 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分: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

答案 2 :(得分:0)

你可以通过硬编码那里的12个月和CROSS JOIN与users然后LEFT JOIN与bookings(我听到其他人提到LEFT JOIN比RIGHT 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
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条件来检查managerID和clientID来过滤掉我们想要的结果,但是我们也希望返回具有空值的行,这意味着它是我们没有预订的硬编码月份。这就是OR (bs.managerID IS NULL AND bs.clientID IS NULL)的原因 此外,当前的GROUP BY是非标准的,因为它不会对选择bs.date的第一个字段进行分组,所以如果您在一个月内有2个或更多预订,它只会返回一个不知道哪个似乎是哪个日期的日期奇怪的是,您可能希望选择hardcoded.date而选择GROUP BY,以便您拥有ANSI标准的适当GROUP BY。或者更好的是使用MIN()或MAX()到MIN(bs.date)或MAX(bs.date)等聚合函数作为select中的第一个字段,以确保它始终返回第一个预订日期或最后一个预订如果该月有2个或更多预订,则每个月的日期,以便您不会将其列在GROUP BY中。

我不知道CROSS JOIN是否会杀死你的应用,但你可以试试这个 它没有CROSS JOIN但保留了你的RIGHT 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

尝试在JOINING之前缩小记录范围

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