我正在寻找一种方法来检索过去12个月内所有空缺的订阅。由于并非每个空缺都会在每个月都有订阅,因此有些行必须返回0,但现在它不在结果集中。如何添加缺失的行?
我使用的表格如下:
CREATE TABLE `calendar_months` (
`month_id` int(8) DEFAULT NULL,
`en_abbr` varchar(255) NOT NULL,
`en_long` varchar(255) NOT NULL,
`nl_abbr` varchar(255) NOT NULL,
`nl_long` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `calendar_months` (`month_id`, `en_abbr`, `en_long`, `nl_abbr`, `nl_long`) VALUES
(1, 'jan', 'January', 'jan', 'Januari'),
(2, 'feb', 'February', 'feb', 'Februari'),
(3, 'mar', 'March', 'mrt', 'Maart'),
(4, 'apr', 'April', 'apr', 'April'),
(5, 'may', 'May', 'mei', 'Mei'),
(6, 'jun', 'June', 'jun', 'Juni'),
(7, 'jul', 'July', 'jul', 'Juli'),
(8, 'aug', 'August', 'aug', 'Augustus'),
(9, 'sep', 'September', 'sep', 'September'),
(10, 'oct', 'October', 'okt', 'Oktober'),
(11, 'nov', 'November', 'nov', 'November'),
(12, 'dec', 'December', 'dec', 'December');
CREATE TABLE `vacancies` (
`vacancy_id` int(11) NOT NULL,
`org_id` int(11) NOT NULL,
`name` varchar(255) NOT NULL COMMENT 'title',
`description` varchar(255) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`is_deleted` tinyint(4) NOT NULL DEFAULT '0',
`status` int(11) NOT NULL DEFAULT '0'COMMENT
) ;
CREATE TABLE `vacancy_subscriptions` (
`subscription_id` int(11) NOT NULL,
`vacancy_id` int(11) DEFAULT NULL,
`user_id` int(10) DEFAULT NULL,
`subscription_date` datetime NOT NULL,
`message` text
)
我使用以下查询:
SELECT
CONCAT(cm.nl_long, ' ', YEAR(v.create_time)) as label, YEAR(v.create_time) as vacyear, MONTH(v.create_time) as vacmonth, COUNT(*) as totalsubscriptions
FROM `calendar_months` as cm
LEFT JOIN `vacancies` as v on cm.month_id = month(v.create_time)
LEFT JOIN `vacancy_subscriptions` as vs on v.vacancy_id = vs.vacancy_id
WHERE
(v.create_time >= (DATE_ADD(NOW(),INTERVAL -12 MONTH)))
AND v.is_deleted = 0
AND v.org_id = 1
GROUP BY vacyear, vacmonth
ORDER BY vacyear ASC, vacmonth ASC
这给了我正在寻找的结果。
+---------------+---------+----------+--------------------+
| label | vacyear | vacmonth | totalsubscriptions |
+---------------+---------+----------+--------------------+
| Oktober 2017 | 2017 | 10 | 5 |
| November 2017 | 2017 | 11 | 1 |
| December 2017 | 2017 | 12 | 13 |
| Maart 2018 | 2018 | 3 | 4 |
| April 2018 | 2018 | 4 | 5 |
+---------------+---------+----------+--------------------+
但是如何在过去的12个月中添加没有订阅的月份,最后一列只是“0”?像这样:
+----------------+---------+----------+--------------------+
| label | vacyear | vacmonth | totalsubscriptions |
+----------------+---------+----------+--------------------+
| Mei 2017 | 2017 | 5 | 0 |
| Juni 2017 | 2017 | 6 | 0 |
| Juli 2017 | 2017 | 7 | 0 |
| Augustus 2017 | 2017 | 8 | 0 |
| September 2017 | 2017 | 9 | 0 |
| Oktober 2017 | 2017 | 10 | 5 |
| November 2017 | 2017 | 11 | 1 |
| December 2017 | 2017 | 12 | 13 |
| Januari 2018 | 2018 | 1 | 0 |
| Februari 2018 | 2018 | 2 | 0 |
| Maart 2018 | 2018 | 3 | 4 |
| April 2018 | 2018 | 4 | 5 |
+----------------+---------+----------+--------------------+
更新:我创建了一个包含一些数据的SQL小提琴! http://www.sqlfiddle.com/#!9/75db76
你的逻辑被打破了。您的日历表需要包括月份和年份 - 以及月份的第一个日期(为方便起见)。
然后你可以这样做:
SELECT CONCAT(cm.nl_long, ' ', cm.year) as label, COUNT(*) as totalsubscriptions
FROM calendar_months cm LEFT JOIN
vacancies v
ON cm.month_id = month(v.create_time) AND
cm.year = year(v.create_time) AND
v.is_deleted = 0 AND
v.org_id = 1 LEFT JOIN
`vacancy_subscriptions` vs
on v.vacancy_id = vs.vacancy_id
WHERE cm.month_start_date >= DATE_ADD(NOW(), INTERVAL -12 MONTH))
GROUP BY label
ORDER BY MIN(cm.month_start_date);
笔记:
ON
子句中(对于LEFT JOIN
。GROUP BY
需要在第一个表中的字段上。NOW()
- 您将获得13个月的数据,包括部分第一个月和最后几个月。在on子句中移动与左连接表相关的where条件
SELECT
CONCAT(cm.nl_long, ' ', YEAR(v.create_time)) as label, YEAR(v.create_time) as vacyear, ifnull(MONTH(v.create_time),0) as vacmonth, ifnull(COUNT(*),0) as totalsubscriptions
FROM `calendar_months` as cm
LEFT JOIN `vacancies` as v on cm.month_id = month(v.create_time)
AND (v.create_time >= (DATE_ADD(NOW(),INTERVAL -12 MONTH)))
AND v.is_deleted = 0
AND v.org_id = 1
LEFT JOIN `vacancy_subscriptions` as vs on v.vacancy_id = vs.vacancy_id
GROUP BY vacyear, vacmonth, label
ORDER BY vacyear ASC, vacmonth ASC
否则where条件作为内部联接工作,如果值不匹配则不返回行
事实上你没有一年中的所有这一年你可以在联盟上使用交叉联接来获得这个值
SELECT
CONCAT(cm.nl_long, ' ', y.my_year) as label, YEAR(v.create_time) as vacyear
, ifnull(MONTH(v.create_time), 0) as vacmonth, ifnull(COUNT(*),0) as totalsubscriptions
FROM `calendar_months` as cm
CROSS JOIN (
select 2018 my_year
from dual
union
select 2017
from dual
) y
LEFT JOIN `vacancies` as v on cm.month_id = month(v.create_time)
AND (v.create_time >= (DATE_ADD(NOW(),INTERVAL -12 MONTH)))
AND v.is_deleted = 0
AND v.org_id = 1
LEFT JOIN `vacancy_subscriptions` as vs on v.vacancy_id = vs.vacancy_id
GROUP BY vacyear, vacmonth, label
ORDER BY y.my_year ASC, vacmonth ASC