Oracle основанная на времени аналитика - PullRequest
2 голосов
/ 02 января 2012

У меня есть требование для расчета сводной статистики, агрегированной по определенным пользовательским периодам времени. В частности, сеть ресторанов открыта 24 часа в сутки. Мне нужно рассчитать статистику, такую ​​как общий объем продаж по периодам, где периоды "Завтрак", "Обед", "Ужин" и "Ночь". Для этой компании официальный день, за который они отслеживают статистику, начинается после обеда. Таким образом, 24-часовой период, который составляет официальный день, начинается в 8 вечера и продолжается до 8 вечера по Гринвичу) на следующий день. Это один период. Другой период - «Ночь», который длится с 8 вечера до 5:30 утра. Я поместил эти определения в таблицу с именем "tdef" следующим образом:

drop table tdef cascade constraints 
;

create table tdef 
(
    cd char(3) not null,
    start_ts date not null,
    stop_ts date not null 
)

И затем я вставляю определения в таблицу tdef, которая хранится в виде дат, где начальная дата всегда начинается 1 января 1900 года, а если она начинается в полночь, то она заканчивается 2 января 1900 года. Примерно так:

insert into tdef (start_ts, stop_ts, cd) 
values
(
to_date('1900/01/01 20:00:00', 'yyyy/mm/dd hh24:mi:ss'),
to_date('1900/01/02 19:59:59', 'yyyy/mm/dd hh24:mi:ss'),
'24H'
);

insert into tdef (start_ts, stop_ts, cd) 
values
(
to_date('1900/01/01 10:30:00', 'yyyy/mm/dd hh24:mi:ss'),
to_date('1900/01/01 13:29:59', 'yyyy/mm/dd hh24:mi:ss'),
'LUN
);

insert into tdef (start_ts, stop_ts, cd) 
values
(
to_date('1900/01/01 15:30:00', 'yyyy/mm/dd hh24:mi:ss'),
to_date('1900/01/02 08:29:59', 'yyyy/mm/dd hh24:mi:ss'),
'ON'
);

У меня очень большая таблица (около 2,5 миллиардов строк), которая содержит все транзакции регистра. Мне нужно суммировать продажи по дате (их определение 8 вечера-8 вечера), продукту и времени измерения и сохранить это в таблице для отчетов быстрого доступа. Таблица должна выглядеть так:

Dec 12 2011, Hamburger, 24H, 1000
Dec 12 2011, Hamburger, ON, 100
Dec 12 2011, Hamburger, LUN, 400

Вот что я сделал, чтобы сделать это, я добавил два столбца даты в таблицу транзакций, которые являются временем транзакции 01.01.1900 и 1/2/1900, например:

to_date(concat('01/01/1900 ', tran_tm), 'mm/dd/yyyy hh24:mi'),
to_date(concat('01/02/1900 ', tran_tm), 'mm/dd/yyyy hh24:mi')

Я проиндексировал эти два столбца. Затем я создал таблицу перекрестного поиска, которая связывает идентификаторы транзакций с временными кодами. Каждый код транзакции может иметь более одного определения времени. Так это выглядит так:

24H, 1
24H, 2
24H, 3
...
LUN, 100
LUN, 101
LUN, 102
...
ON, 1
ON, 2
...

Для этого я использовал два оператора вставки select:

select  t.trans_id, td.cd, to_date(to_char(to_date(concat(to_char(ts, 'mm/dd/yyyy '), to_char(td.stop_ts, 'hh24:mi:ss')), 'mm/dd/yyyy hh24:mi:ss', 'yyyymmdd'), 'yyyymmdd')
from trans t, tdef td
where ts1 >= td.start_ts and ts1 <= td.stop_ts

select  t.trans_id, td.cd, to_date(to_char(to_date(concat(to_char(ts, 'mm/dd/yyyy '), to_char(td.stop_ts, 'hh24:mi:ss')), 'mm/dd/yyyy hh24:mi:ss', 'yyyymmdd'), 'yyyymmdd')
from trans t, tdef td
where ts2 >= td.start_ts and ts2 <= td.stop_ts

Третье поле - «официальная дата». Как это работает, предположим, что транзакция произошла в 12.12.2011 20:01, тогда поле ts1 будет 1/1/1900 20:01, а поле ts2 будет 1/2/1900 20:01. В первом запросе это поле будет присоединено к CD «24H» и «ON». И официальная дата будет рассчитываться как 13.12.2011 для «24H» и 13.12.2011 для «ON». Эта транзакция не будет присоединена ко второму запросу, потому что она выходит за пределы диапазона дат. Предположим, что транзакция произошла в 13.12.2011, 12:05. По первому запросу ts1 будет присоединяться следующим образом: «24H» для даты 13.12.2011, «LUN» для даты 13.12.2011.

Если у меня есть эта таблица, ее легко объединить:

select tdef_trans.dt, sum(sales) from trans, tdef_trans where trans.id = tdef_trans.id and tdef_trans.cd = 'LUN'

Хотя это решение, кажется, работает, я держу пари, что есть более элегантный способ сделать это. Есть идеи?

Ответы [ 2 ]

2 голосов
/ 02 января 2012

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

Тогда ваш запрос станет относительно простым соединением с этим измерением времени

1 голос
/ 03 января 2012

Добавление ввода / вывода для каждой записи в таблице транзакций для сопоставления второй транзакции с бизнес-периодом кажется слишком высокой ценой.Возможно, вы могли бы вместо этого хранить и сводить данные, как показано ниже:

select case 
         when txn_ts - trunc(txn_ts) > numtodsinterval(20, 'hour')
           then trunc(txn_ts) + 1 
           else trunc(txn_ts)     
       end as business_day,
       sum (case when (   txn_ts - trunc(txn_ts) > numtodsinterval(20, 'hour')
                       or txn_ts - trunc(txn_ts) < numtodsinterval(5.5, 'hour')
                 then txn_amt else 0 end) as overnight_sales,
       sum (case when (   txn_ts - trunc(txn_ts) >= numtodsinterval(5.5, 'hour')
                      and txn_ts - trunc(txn_ts) <  numtodsinterval(11, 'hour')
                 then txn_amt else 0 end) as breakfast_sales,
       sum (case when (   txn_ts - trunc(txn_ts) >= numtodsinterval(11, 'hour')
                      and txn_ts - trunc(txn_ts) <  numtodsinterval(4, 'hour')
                 then txn_amt else 0 end) as lunch_sales,
       sum (case when (   txn_ts - trunc(txn_ts) >= numtodsinterval(11, 'hour')
                      and txn_ts - trunc(txn_ts) <  numtodsinterval(4, 'hour')
                 then txn_amt else 0 end) as dinner_sales
  from txn_table
 group by case when txn_ts - trunc(txn_ts) > numtodsinterval(20, 'hour')
             then trunc(txn_ts) + 1 
             else trunc(txn_ts)     
          end 

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

См. Создание гистограмм с определяемыми пользователем сегментами в данных OracleРуководство по складированию для других примеров, включая неповоротную версию.

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