Как «сгруппировать» по диапазону DATETIME? - PullRequest
3 голосов
/ 26 ноября 2010

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

Пользователь может выбрать диапазон даты / времени (ежемесячно, ежедневно, еженедельно, свободно ...), реализованный мной запрос получит startDateTime и EndDateTime и вернет все транзакции, сгруппированные по дням.

И.Е.

DateTime       Total Sales
---------------------------
10/15/2010      $2,300.38
10/16/2010      $1,780.00
10/17/2010      $4,200.22
10/20/2010      $900.66

Моя проблема заключается в том, что, если установлена ​​смена бизнеса, например, с 05:00 до 02:00 следующего дня, все транзакции, выполненные с полуночи до 02:00, будут сгруппированы на следующий день ... и итак ... итоги искажены. Когда у предприятия есть такой сдвиг, ему нужен отчет, основанный на этом сдвиге, но без исправления кода (я использую Java для вызова собственных запросов Oracle), я не могу получить запрошенный отчет.

Мне интересно, есть ли какой-нибудь разумный способ сгруппировать по диапазону даты и времени эти наборы транзакций, используя только Oracle.

Вот запрос на июль месяц:

SELECT Q1.dateFormat, NVL(Q1.sales, 0) 
    FROM (
        SELECT to_date(to_char(tx.datetimeGMT +1/24 , 'mm-dd-yyyy'), 'mm-dd-yyyy') AS dateFormat                    
                , NVL(SUM(tx.amount),0) AS sales
            FROM Transaction tx
            WHERE tx.datetimeGMT > to_date('20100801 08:59:59', 'yyyymmdd hh24:mi:ss') +1/24  
                AND tx.datetimeGMT < to_date('20100901 09:00:00', 'yyyymmdd hh24:mi:ss') + 1/24  
            GROUP BY to_date(to_char(tx.datetimeGMT +1/24 , 'mm-dd-yyyy'), 'mm-dd-yyyy') 
    ) Q1 
    ORDER BY 1 DESC

Ответы [ 4 ]

3 голосов
/ 29 ноября 2010

Спасибо всем за ответы, взглянув на них, я смог записать запрос, который искал:

SELECT CASE 
     WHEN EXTRACT(HOUR FROM TX.DATETIME) >= 5 THEN TO_CHAR(TX.DATETIME,'DD-MM-YYYY')
     WHEN EXTRACT(HOUR FROM TX.DATETIME) BETWEEN 0 AND 2 THEN TO_CHAR(TX.DATETIME-1,'DD-MM-YYYY')
     WHEN EXTRACT(hour from tx.datetime) between 2 and 5 THEN to_char(TX.DATETIME-1,'DD-MM-YYYY')
   END AS age, 
   NVL(SUM(tx.amount),0) AS sales
FROM TRANSACTION TX
WHERE tx.datetime > to_date('20100801 08:59:59', 'yyyymmdd hh24:mi:ss') 
  AND TX.DATETIME < TO_DATE('20100901 09:00:00', 'yyyymmdd hh24:mi:ss')
GROUP BY CASE 
     WHEN EXTRACT(HOUR FROM TX.DATETIME) >= 5 THEN TO_CHAR(TX.DATETIME,'DD-MM-YYYY')
     WHEN EXTRACT(HOUR FROM TX.DATETIME) BETWEEN 0 AND 2 THEN TO_CHAR(TX.DATETIME-1,'DD-MM-YYYY')
     WHEN EXTRACT(hour from tx.datetime) between 2 and 5 THEN to_char(TX.DATETIME-1,'DD-MM-YYYY')
   END 
ORDER BY 1
0 голосов
/ 26 ноября 2010

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

select trunc(trans_date - interval '8' hour) as shift_date
      ,sum(amount)
  from transactions
 group 
    by trunc(trans_date - interval '8' hour)
 order 
    by shift_date desc;
0 голосов
/ 26 ноября 2010

Вы можете попробовать этот подход (просто из моей головы, даже не уверен, что он работает):

select
trans_date,
trans_shift,
aggregates(whatever)
from (
    select 
    -- we want to group by normalized transaction date, 
    -- not by real transaction date
    normalized_trans_date,
    -- get the shift to group by
    case 
      when trans_date between trunc(normalized_trans_date) + shift_1_start_offset and 
                              trunc(normalized_trans_date) + shift_1_end_offset then
        1
      when trans_date between trunc(normalized_trans_date) + shift_2_start_offset and 
                              trunc(normalized_trans_date) + shift_2_end_offset then
        2
      ...
      when trans_date between trunc(normalized_trans_date) + shift_N_start_offset and 
                              trunc(normalized_trans_date) + shift_N_end_offset then
        N
    end trans_shift,
    whatever
    from (
        select
        -- get a normalized transaction date: if date is before 1st shift
        -- it belongs to the day before
        case 
          when trans_date - trunc(trans_date) < shift_1_start_offset then
            trans_date - 1
          else
            trans_date
        end normalized_trans_date,
        t.*
        from
        transactions t
    )
)
group by trans_date, trans_shift
0 голосов
/ 26 ноября 2010

Чтобы сгруппировать по диапазону дат, вам нужно будет поместить этот диапазон в значение столбца в подзапрос и сгруппировать его по вашему запросу.Очевидно, этот диапазон дат в этом столбце будет иметь тип VARCHAR.

...