четверг, 29 сентября 2011 г.

Последовательности значений в запросе

Создание последовательности значений посредством запроса.

Есть таблица или представление с датой и какой то мерой по этой дате.
Например дата и количество продаж чего либо за этот день.
datecnt
01.09.201110
02.09.201112
05.09.20118
10.09.20116

В результате нужно получить отчет за период по всем дням. При чем если за день не было продаж то его в исходной таблице нет, но в итоговую его нужно добавить с количеством продаж - 0.
Для этого можно использовать либо использовать таблицу или представление где есть все даты используя left join и функцию nvl().
Если подходящей таблицы или представления нет можно либо создать явно либо формировать "на лету".

Собственно создание последовательности из чисел или дат (1, 2, 3, 4, ... или 01.01.2011, 02.01.2011 ...) в запросе.
Используя Level и connect by
select Level from dual
connect by Level <= 10
В данном примере - числовая последовательность от 1 до 10 В случае с датами:
Select to_date('01.09.2011') + Level - 1 as num from dual 
connect by to_date('01.09.2011') + Level <= to_date('10.09.2011') + 1
Т.к. последовательность нужна с 01.09.2011 а исходное значение для Level равно 1, нужно ее уменьшить поэтому Level - 1. Что бы итоговая дата так же попала в выборку добавляем единицу к дате окончания.

Другой способ - без использования Level и Connect By. Для числовой последовательности:
WITH tbl ( n ) AS (
   SELECT 1 AS n FROM dual 
   UNION ALL
   SELECT n + 1 as n FROM tbl  
   WHERE n < 10 
)
SELECT * FROM tbl
Результат - последовательность от 1 до до 10.
В случае с датами:
WITH tbl ( n ) AS (
   SELECT 0 AS n FROM dual 
   UNION ALL
   SELECT n + 1 as n FROM tbl  
   WHERE n < 10 
)
SELECT to_date('01.09.2011') + n as dt FROM tbl
Во второй строке явно указано что начало последовательности - 0, что бы начальная дата попала в последовательность.

Возвращаясь к первоначальному примеру: полученную последовательность нужно соединить с исходной таблицей и использовать функцию nvl() для указания нулей по дням где не было продаж.