在过去12个月的mysql中返回空值的空值

时间:2018-04-08 13:43:16

标签: mysql sql

我有以下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

此查询提供正确的金额结果: results first query

如果我然后使用下面@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;

我得到以下结果(金额应该低得多): query 2 results

1 个答案:

答案 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;

“某些变体”考虑到您可能有其他一些计算月份列表的方法。