У меня есть требование для расчета сводной статистики, агрегированной по определенным пользовательским периодам времени. В частности, сеть ресторанов открыта 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'
Хотя это решение, кажется, работает, я держу пари, что есть более элегантный способ сделать это. Есть идеи?