MySQL: возможно ли заполнить SELECT значениями без таблицы? - PullRequest
8 голосов
/ 26 марта 2011

Мне нужно отобразить общее количество «заказов» за каждый год и месяц.Но в течение нескольких месяцев нет данных, но я хочу отобразить этот месяц (с общим значением ноль).Я мог бы сделать вспомогательные «месяцы» с 12 записями для каждого года, но есть ли способ получить диапазон месяцев, не вводя новую таблицу?

Что-то вроде:

SELECT [all year-month combinations between january 2000 and march 2011] 
FROM DUAL AS years_months

У кого-нибудь есть идеи, как это сделать?Можете ли вы использовать SELECT с какой-то формулой, чтобы «создавать» данные на лету?!

ОБНОВЛЕНИЕ:

Обнаружил сам: генерировать дни издиапазон дат

Принятый ответ на этот вопрос является своего рода искомым.Возможно, не самый простой способ, но он делает то, что я хочу: заполнить выбор данными на основе формулы ....

Чтобы «создать» таблицу на лету со всеми месяцами за последние 10 лет:

SELECT CONCAT(MONTHNAME(datetime), ' ' , YEAR(datetime)) AS YearMonth,
       MONTH(datetime) AS Month,
       YEAR(datetime) AS Year 
FROM (
    select (curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) MONTH) as datetime
    from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
    cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
    LIMIT 120
) AS t
ORDER BY datetime ASC 

Должен признать, это ОЧЕНЬ экзотично, но оно РАБОТАЕТ ...

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

Но использование таблицы «цифры» или «календарь», вероятно, является наилучшим вариантом, поэтому я собираюсь использовать это.

Ответы [ 8 ]

5 голосов
/ 26 марта 2011

Если это вообще возможно, старайтесь держаться подальше от генерации данных на лету.Это делает очень простые запросы невероятно сложными, но, прежде всего: это приводит в замешательство оптимизатор без конца.

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

Я привел пример того, как создать таблицу чисел и минимальную таблицу календаря (только даты) в этот ответ .

Если у вас есть эти таблицы, ваш запрос станет легко решить.

  1. Объедините данные заказа в МЕСЯЦ.
  2. Право присоединиться к таблице месяцев (или отличить МЕСЯЦ от таблицы дат)
5 голосов
/ 26 марта 2011

Вы можете попробовать что-то вроде этого

select * from 
    (select 2000 as year union
     select 2001 as year union
     select 2009
    ) as years, 
    (select 1 as month union 
     select 2 as month union 
     select 3 as month union 
     select 4 as month union 
     select 5 as month union 
     select 6 as month union 
     select 7 as month union 
     select 8 as month union 
     select 9 as month
     )
AS months 
WHERE year between 2001 AND 2008 OR (year=2000 and month>0) OR (year = 2009 AND month < 4) 
ORDER by year,month

2 голосов
/ 26 марта 2011

Вы можете просто заполнить пропущенные месяцы после выполнения запроса в логике приложения.

1 голос
/ 28 декабря 2015

Если вы используете PostgreSQL, вы можете объединить date_trunc и generate_series , чтобы сделать очень интересную группировку и генерацию серий.

Например, вы можете использовать это для создания таблицы всех дат за последний год:

SELECT current_date - s.a as date 
FROM generate_series(0,365,1) as s(a);

Затем вы можете использовать date_trunc, чтобы получить месяцы и сгруппировать их по полю date_trunc:

SELECT date(date_trunc('month', series.date)) as month, COUNT(*) as days 
FROM (SELECT current_date - s.a as date 
FROM generate_series(0,365,1) as s(a)) series 
GROUP BY month;
1 голос
/ 26 марта 2011

Вы должны определенно делать это в своем приложении, а не на уровне БД.Просто создайте массив дат для временного диапазона и объедините фактические данные с предварительно созданными пустыми датами.См. этот ответ на аналогичный вопрос

0 голосов
/ 30 сентября 2014

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

SELECT date_format(@dt:= DATE_ADD( @dt, INTERVAL 1 MONTH),'%M %Y') date_string, 
   @dt as date_full 
FROM (SELECT @dt := DATE_SUB(CAST(DATE_FORMAT('2013-05-01' ,'%Y-%m-01') AS DATE),
   INTERVAL 1 MONTH) ) vars,
   your_tables 
WHERE @dt<NOW()

Проблема заключается в том, что его следует объединить с таблицей, содержащей достаточно строк, чтобы указать номер ожидаемого месяца.Например, если вам нужно сгенерировать весь месяц в определенном году, вам понадобятся таблицы, состоящие как минимум из 12 строк.

Для меня это немного прямо.Я присоединился к нему с моей таблицей конфигурации, состоящей из 370 строк.Так что он может генерировать месяцы в году или дни в году, если мне это нужно.Переход с интервала месяца на интервал дней будет легким, поскольку мне нужно только изменить интервал с МЕСЯЦА до ДНЯ.

0 голосов
/ 26 марта 2011

Я бы сделал что-то вроде этого:

SELECT COUNT(Order.OrderID)
FROM Orders
WHERE YEAR(Order.DateOrdered) > 2000
GROUP BY MONTH(Order.DateOrdered)

Это даст вам количество заказов, сгруппированных по месяцам.Затем в вашем приложении просто присвойте НУЛЬ тем месяцам, в которые данные не были возвращены

Надеюсь, это поможет

0 голосов
/ 26 марта 2011

Создайте таблицу (например, tblMonths), которая включает все 12 месяцев, и используйте LEFT JOIN (или RIGHT JOIN) для нее и ваших частичных исходных данных.

Проверьте ссылку и это руководство о том, как это работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...