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

标签 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) 

有人可以帮忙吗?

最佳答案

您可以通过硬编码其中的 12 个月并与 users 进行 CROSS JOIN,然后与 bookings 进行 LEFT JOIN(我听其他人提到 LEFT 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) 之类的聚合函数,以确保它始终返回第一个预订日期或最后一个预订日期每月的日期(如果该月有 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

在加入之前尝试缩小记录范围

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

关于MySQL 查询 - 返回每个月过去 12 个月记录的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21081741/

相关文章:

java - 如何在java中检查新记录是否插入到数据库

mysql - 当分类向量存储在引号中时的 RSQLite 查询

php - 在文本区域为数据库中的每一行发布多封电子邮件

sql - 查询优化方法

sql - 使用 Hibernate 的标准和投影来选择多个不同的列

sql - 在oracle sql中连接没有外键关系的表并向结果添加一列?

MySQL 如果存在左外连接

mysql - 如何实现大规模更新查询,将 n 天添加到 DateTime 字段的日期部分?

sql - MSSQL 模式匹配 [1-999] 之间的所有数字

mysql - 解决MySQL不明确的列,不加前缀表名,不使用子查询