Есть ли простой способ сделать GROUP BY DATE(timestamp), который включает все дни в периоде времени, независимо от того, есть ли какие-либо записи, связанные с этой датой?
По сути, мне нужно создать такой отчет:
24 Dec - 0 orders
23 Dec - 10 orders
22 Dec - 8 orders
21 Dec - 2 orders
20 Dec - 0 orders






Один из способов - создать календарную таблицу и присоединиться к ней.
Я бы создал его постоянно, а затем создал задачу, которая будет вставлять новые даты, это можно делать еженедельно, ежедневно, ежемесячно и т. д.
Обратите внимание: я предполагаю, что вы конвертируете метку времени в дату.
Это немного сложно при обслуживании, хотя это более производительно, чем создание SP, динамически генерирующего список.
Проблема обслуживания здесь действительно означает, что создание календарной таблицы нецелесообразно. В итоге вы получите календарную таблицу, которая станет центром всей базы данных, и отладка станет очень сложной.
@Neil, я должен сказать, что согласен, но мне не нравится создавать календарную таблицу на лету, если, конечно, это не нужно делать периодически, а не часто.
Вместо использования GROUP BY создайте таблицу (возможно, временную), которая содержит конкретные даты, которые вы хотите, например:
24 Dec
23 Dec
22 Dec
21 Dec
20 Dec
Затем присоедините эту таблицу к таблице заказов.
Хотя это действительный метод, ответ Thangalin ниже программно делает это без необходимости создавать какие-либо новые таблицы.
Тангаллин сказал: «В Oracle», но OP пометил вопрос «mysql».
вам нужно сгенерировать промежуточный набор результатов со всеми датами в нем, которые вы хотите включить в вывод ...
если вы делаете это в хранимой процедуре, вы можете создать временную таблицу или табличную переменную (я не знаю возможностей MySQL), но как только у вас есть все даты в таблице или каком-либо наборе результатов
Просто присоединитесь к реальным данным из временной таблицы, используя внешнее соединение
В SQL Server это было бы так
Declare @Dates Table (aDate DateTime Not Null)
Declare @StartDt DateTime Set @StartDt = 'Dec 1 2008'
Declare @EndDt DateTime Set @EndDt = 'Dec 31 2008'
While @StartDt < @EndDt Begin
Insert @Dates(aDate) Values(@StartDt)
Set @StartDt = DateAdd(Day, 1, @StartDt)
End
Select D.aDate, Count(O.*) Orders
From @Dates D Left Join
OrderTable O On O.OrderDate = D.aDate
Group By D.aDate
В хранилище данных используется метод создания таблицы, содержащей все даты, и создания внешнего ключа между вашими данными и таблицей дат. Я не говорю, что это лучший способ в вашем случае, просто это лучшая практика в тех случаях, когда большие объемы данных необходимо объединить множеством способов для целей отчетности.
Если вы используете уровень отчетности поверх SQL Server, вы можете просто написать некоторую логику для вставки недостающих дат в интересующий диапазон после возврата данных и перед визуализацией отчета.
Если вы создаете свои отчеты непосредственно из SQL Server, и у вас еще нет хранилища данных, и нет времени или необходимости создавать его прямо сейчас, я бы создал таблицу дат и присоединился к ней. Форматирование, необходимое для объединения и получения желаемого результата, может быть немного неудобным, но оно выполнит свою работу.
Предполагая, что у вас больше заказов, чем дат, может сработать что-то вроде этого:
select date, count(id) as orders
from
(
SELECT DATE_ADD('2008-01-01', INTERVAL @rn:=@rn+1 DAY) as date from (select @rn:=-1)t, `order` limit 365
) d left outer join `order` using (date)
group by date
Я знал, что должен быть способ сделать это без календаря или таблицы чисел. И это легко адаптируется к другим интервалам (мне нужно было группировать каждые 15 минут).
Есть довольно простой способ сделать это… за исключением того, что я не могу его вспомнить. Но я адаптировал этот запрос из эта ветка:
SELECT
DISTINCT(LEFT(date_field,11)) AS `Date`,
COUNT(LEFT(date_field,11)) AS `Number of events`
FROM events_table
GROUP BY `Date`
Он работает и в MySQL
Это не сработает, так как будут пропущены даты без событий.
Ах, правда. Думаю, этот ответ можно рассматривать только в том случае, если вы готовы программно заполнить пробелы.
Подумал, что нет очевидного способа сделать это, но решил, что спрошу. Спасибо всем, кто откликнулся.