Группировка по неделям, как получить пустые недели?

У меня есть следующий код, который группирует некоторые события (YYYY-MM-DD HH: MM: SS) в неделях, которые отображаются, например, как "Y: 2010 - Week: 50".

SELECT DATE_FORMAT(date, 'Y:%X - Week:%V') AS regweek, COUNT(*) as number 

он работает хорошо, но я хотел бы вернуть все недели, даже если те, в которых не помещено событие.

Если на третьей неделе не зарегистрировано ни одного события, на данный момент я получаю:

week 1: 10
week 2: 1
week 4: 2

Я хотел бы получить:

week 1: 10
week 2: 1
week 3: 0
week 4: 2

Ответ 1

SQL не может возвращать строки, которые не существуют в некоторой таблице. Чтобы получить необходимый эффект, вам понадобится таблица Weeks (WeekNo INT) с одной строкой за каждую неделю недели (что, IIRC, составляет 53 или 54 возможных недели, в зависимости от того, как вы рассчитываете).

Затем присоедините эту таблицу к своим регулярным результатам с помощью OUTER JOIN, чтобы добавить дополнительные недели.

SELECT DATE_FORMAT(date, 'Y:%X - Week:%V') AS regweek, COUNT(date) as number 
    FROM YourTable RIGHT OUTER JOIN Weeks ON WEEK(YourTable.date) = Weeks.WeekNo

[Обновить]: обратите внимание на пользователя COUNT (дата), а не на COUNT (*). SQL не будет включать значения NULL в столбце даты при добавлении COUNT. Поскольку отсутствующие недели не будут иметь никаких дат в них, это правильно даст вам 0 событий за эти недели.

Ответ 2

В конце я решил решить проблему следующим образом, создав временную таблицу за недели и используя код, который был обнаружен в ответе, приведенном выше.

CREATE TEMPORARY TABLE weeks (
         id INT
       );
INSERT INTO weeks (id) VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12), (13), (14), (15), (16), (17), (18), (19), (20), (21), (22), (23), (24), (25), (26), (27), (28), (29), (30), (31), (32), (33), (34), (35), (36), (37), (38), (39), (40), (41), (42), (43), (44), (45), (46), (47), (48), (49), (50), (51), (52), (53), (54);
SELECT 
w.id, COUNT(c.issuedate) as numberPerWeek
FROM tableName c RIGHT OUTER JOIN weeks w ON WEEK(c.issuedate) = w.id group by w.id;

Ответ 3

Это та проблема, для которой сделаны таблицы чисел/таблиц - просто простая таблица, которая рассчитывает от 0 до любой. Они полезны вообще, я всегда рекомендую добавлять их в свою базу данных.

С этим вы можете относительно легко генерировать список недель "на лету", не требуя определенной предварительно рассчитанной таблицы недель (так что вам не нужно ни огромная таблица, ни беспокойство о том, чтобы закончились недели), а затем присоединиться к ней против вашего списка назначений, чтобы показать все недели с назначением в них.

Для быстрого запуска:

declare @min    datetime
set     @min    ='2010-01-01'

select
    dateadd(wk, number, @min) as weekDate
from
    numbers
where
    number between 0 and datediff(wk,@min,getdate())

с