2016-02-22 10 views
0

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

Есть ли лучший способ?

+0

не использовать между диапазонами дат, решение от DRapp делает это правильно (через> = then <) –

ответ

1

Да, вы можете использовать агрегатные функции на условные выражения, например, так:

SELECT SUM(IF(date between ({{today}})), 1, 0) AS count_today 
, SUM(IF(date between ({{today}})), amount, 0) AS amount_today 
, ... 
+0

Спасибо. Прекрасно работает. – user3720435

2

хотя у вас есть отмеченное решение, у меня есть другой, который, вероятно, упрощающие запрос еще дальше, используя переменные MySQL, так что вы не» t должны ошибочно вводить/вычислять даты и т. д.

Вместо того, чтобы объявлять переменные впереди, вы можете сделать их inline как оператор select, а затем использовать их так, как если бы они были столбцами в другой таблице. Поскольку он создается как одна строка, нет декартова результата. Сначала запрос, тогда я опишу вычисления на нем.

select 
     sum(if(t.date >= @today AND t.date < @tomorrow, 1, 0)) as TodayCnt, 
     sum(if(t.date >= @today AND t.date < @tomorrow, amount, 0)) as TodayAmt, 
     sum(if(t.date >= @yesterday AND t.date < @today, 1, 0)) as YesterdayCnt, 
     sum(if(t.date >= @yesterday AND t.date < @today, amount, 0)) as YesterdayAmt, 
     sum(if(t.date >= @FirstOfWeek AND t.date < @EndOfWeek, 1, 0)) as WeekCnt, 
     sum(if(t.date >= @FirstOfWeek AND t.date < @EndOfWeek, amount, 0)) as WeekAmt 
    from 
     transations t, 
    (select @today := curdate(), 
       @yesterday := date_add(@today, interval -1 day), 
       @tomorrow := date_add(@today, interval 1 day), 
       @FirstOfWeek := date_add(@today, interval +1 - dayofweek(@today) day), 
       @EndOfWeek := date_add(@FirstOfWeek, interval 7 day), 
       @minDate := least(@yesterday, @FirstOfWeek)) sqlvars 
    where 
      t.date >= @minDate 
     AND t.date < @EndOfWeek 

Теперь даты. Поскольку @variables готовятся последовательно, вы можете подумать об этом как о встроенной программе для установки переменных. Поскольку они являются предварительным запросом, они выполняются сначала и доступны для остальной части запроса, как указано ранее. Поэтому, чтобы начать, я работаю над тем, что «curdate()» - это то, что получает часть даты только без учета времени. Из этого вычтите 1 день (добавьте -1), чтобы получить начало вчера. Добавьте 1 день, чтобы получить Завтра. Затем первая неделя - это текущая дата +1 - фактический день недели (вы скоро увидите). Добавьте 7 дней с первой недели, чтобы получить окончание недели. Наконец, получите, какая бы ни была дата: МЕНЬШЕ между вчерашним днем ​​(который МОЖЕТ существовать в конце предыдущей недели), ИЛИ в начале недели.

Now look at today for example... Feb 23rd. 
Sun Mon Tue Wed Thu Fri Sat Sun 
21 22 23 24 25 26 27 28 

Today = 23 
Yesterday = 22 
Tomorrow = 24 
First of week = 23 + 1 = 24 - 3rd day of week = 21st 
End of Week = 21st + 7 days = 28th. 

Почему я занимаюсь отключением дат зачистки? Чтобы упростить условие SUM() для> = И <. Если я заявлял, что дата = сегодня, что делать, если ваши транзакции были отмечены по времени. Затем вам нужно будет извлечь часть даты только для квалификации. При таком подходе я могу сказать, что «Сегодня» подсчет и сумма - любая дата> = 23 февраля в 12:00 ночи и < 24 февраля 12:00 полночь. Это все время включительно с 23 февраля до 11:59:59, поэтому МЕНЬШЕ, чем 24 февраля (завтра).

Подобное соображение за вчерашний день включает все, что включено, но не включает в себя все, что «сегодня». Аналогично для недельного диапазона.

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

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

@today := '2015-01-24' 

и вычисления будет, как если запрос был запущен в тот же день ,

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

Надеюсь, вам понравится это гибкое решение для вас.

+0

Спасибо. Выучили некоторые полезные трюки, работающие с датами в запросах. – user3720435