Добавление всех месяцев прошлого года в результат запроса MySQL, даже если нет строк

0

Я ищу способ получить все подписки на вакансии за последние 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 |
+----------------+---------+----------+--------------------+

UPDATE: я создал скрипт SQL, содержащий некоторые данные! http://www.sqlfiddle.com/#!9/75db76

  • 2
    поместите предложение where в предложение on - предложение where ограничивает результирующий набор прямо сейчас
  • 0
    @DanielMarcus Спасибо за ваш ответ! Хотя шаг в правильном направлении, к сожалению, это не решает проблему ...
Теги:
date

2 ответа

1

Переместите свое условие, связанное с левой таблицей join в позиции on

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
  • 0
    Спасибо за Ваш ответ! Использование вашего SQL не привело к тому, что я ожидал, но к этому: imgur.com/UXY2TuA
  • 0
    странно .. имея образец, который вы предоставили, вы должны выбрать строки для каждого месяца ..
Показать ещё 5 комментариев
1

Ваша логика нарушена. Ваша таблица календаря должна включать как месяц, так и год - и первую дату месяца (для удобства).

Тогда вы можете сделать:

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 месяцев данных с частичным первым и последним месяцами.
  • 0
    Я не знаком с таблицей календаря. Эта таблица содержит каждый год / месяц / день в течение следующих 100 лет?
  • 0
    @ Денис , , Это было бы полезным календарным столом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню