我有以下SQL检查过去12个月的订阅。 问题是,如果某个月没有订阅,它将不会显示在结果中。 例如,空缺表的结构如下:
+------------+---------------------+--------+------------+--+--+
| vacancy_id | create_time | org_id | is_deleted | | |
+------------+---------------------+--------+------------+--+--+
| 1 | 2018-04-06 08:09:48 | 1 | 0 | | |
| 2 | 2018-02-06 08:09:48 | 1 | 0 | | |
| 3 | 2017-08-06 08:09:48 | 1 | 0 | | |
+------------+---------------------+--------+------------+--+--+
和空缺订阅如下:
+-----------+-------+------------+
| subscr_id | msg | vacancy_id |
+-----------+-------+------------+
| 1 | test | 1 |
| 2 | test2 | 3 |
+-----------+-------+------------+
现在我的查询是:
SELECT
YEAR(v.create_time) as vacyear, MONTH(v.create_time) as vacmonth, COUNT(*) as totalsubscriptions
FROM `vacancies` as v
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
哪个有效并且在该月有订阅的情况下给出了正确的结果。 在此示例中,如何让输出包含所有月份?
2018-04
2018-03
2018-02
2018-01
2017-12
2017-11
2017-10
2017-9
2017-8
2017-7
2017-6
2017-5
更新:
我尝试了用户@Gordon Linoff建议的解决方案,并创建了一个包含month_id的表,其名称如下:
CREATE TABLE `calendar_months` ( `month_id` INT(8) NOT 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;
我在那里插入数据:
month_id = 1
en_long = 'January'
...
month_id = 2
en_long = 'February'
...
然后我将查询修改为:
SELECT
YEAR(v.create_time) as vacyear, MONTH(v.create_time) as vacmonth, COUNT(*) as totalsubscriptions, cm.nl_long
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
结果保持不变
更新3:
SELECT
YEAR(v.create_time) as vacyear, MONTH(v.create_time) as vacmonth, COUNT(*) as totalsubscriptions
FROM `vacancies` as v
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
如果我然后使用下面@Gordon Linoff建议的查询,那就是:
SELECT YEAR(m.dte) as vacyear, MONTH(m.dte) as vacmonth,
COUNT(vs.vacancy_id) as totalsubscriptions
FROM (SELECT DATE_ADD(NOW(), INTERVAL -12 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -11 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -10 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -9 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -8 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -7 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -6 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -5 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -4 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -3 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -2 MONTH) as dte UNION ALL
SELECT DATE_ADD(NOW(), INTERVAL -1 MONTH) as dte
) as m LEFT JOIN
vacancies v
ON v.create_time >= m.dte AND
v.create_time < m.dte + interval 1 month AND
v.is_deleted = 0 AND v.org_id = 1 LEFT JOIN
vacancy_subscriptions vs
ON v.vacancy_id = vs.vacancy_id
WHERE m.dte >= DATE_ADD(NOW(), INTERVAL -12 MONTH)
GROUP BY vacyear, vacmonth
ORDER BY vacyear ASC, vacmonth ASC;
答案 0 :(得分:1)
最安全的解决方案是使用日历表或使用所需月份的派生表。然后,它成为LEFT JOIN
中的第一个表格,WHERE
条件转移到ON
子句。
但是,在许多情况下,WHERE
子句会过滤掉结果集中的月份。如果您的数据属于这种情况,那么您可以使用更简单的解决方案。只需将WHERE
条件移至SELECT
:
SELECT YEAR(v.create_time) as vacyear, MONTH(v.create_time) as vacmonth,
SUM(v.is_deleted = 0 AND v.org_id = 1) as totalsubscriptions
FROM vacancies v LEFT JOIN
vacancy_subscriptions vs
ON v.vacancy_id = vs.vacancy_id
WHERE v.create_time >= DATE_ADD(NOW(), INTERVAL -12 MONTH)
GROUP BY vacyear, vacmonth
ORDER BY vacyear ASC, vacmonth ASC;
我应该强调,这并不总是有效 - 它要求每个感兴趣的月份在您的表格中有一些记录。如果它确实有效,通常是最简单的解决方案。
编辑:
否则,您需要一个以下变体的解决方案:
SELECT YEAR(m.dte) as vacyear, MONTH(m.dte) as vacmonth,
COUNT(vs.vacancy_id) as totalsubscriptions
FROM (SELECT date('2017-05-01') as dte UNION ALL
SELECT date('2017-06-01') as dte UNION ALL
. . .
SELECT date('2018-04-01') as dte
) m LEFT JOIN
vacancies v
ON v.create_time >= m.dte AND
v.create_time < m.dte + interval 1 month AND
v.is_deleted = 0 AND v.org_id = 1 LEFT JOIN
vacancy_subscriptions vs
ON v.vacancy_id = vs.vacancy_id
WHERE m.dte >= DATE_ADD(NOW(), INTERVAL -12 MONTH)
GROUP BY vacyear, vacmonth
ORDER BY vacyear ASC, vacmonth ASC;
“某些变体”考虑到您可能有其他一些计算月份列表的方法。