2016-09-28 8 views
0

Мне нужно заменить данные по умолчанию для одной строки, которая не существует. Ниже приводится то, что у меня есть для данных, за которыми следует то, что мне нужно для возврата данных. Я хотел бы сделать это в SQL, а не строить что-то в PL/SQL. Я использую Oracle 8i.Имитировать строки, которые не существуют

Что у меня есть:

Item  Period_start_date  Qty_Used 
1234  1-MAR-2015   10 
1234  1-JUN-2015   32 
1234  1-JUL-2015   14 
1234  1-SEP-2015   11 

Что мне нужно:

1234  1-MAR-2015   10 
1234  1-APR-2015   0 
1234  1-MAY-2015   0 
1234  1-JUN-2015   32 
1234  1-JUL-2015   14 
1234  1-AUG-2015   0 
1234  1-SEP-2015   11 
+0

Ну, это форматирование не получилось. Я использовал много пробелов для имитации столбцов, но, очевидно, это не сработало. Ясно, что я новичок: - | –

+0

[Как отформатировать мои сообщения с помощью Markdown или HTML?] (Http://stackoverflow.com/help/formatting). Стоит посмотреть вокруг справочного центра или, по крайней мере, [принять тур] (http://stackoverflow.com/tour), если вы еще этого не сделали. –

+0

Как определить начальный и конечный месяцы - самый низкий и самый высокий в таблице, или вы можете увидеть данные за март 2015 года, даже если в этом месяце нет строки, скажем? –

ответ

3

Использование 8i делает это немного более сложным, чем это могло бы быть в более поздних версиях.

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

select item, min(period_start_date) min_date, 
    months_between(max(period_start_date), min(period_start_date)) as num_months 
from your_table 
group by item 

... и использовать это в качестве внутренний запрос для иерархического запроса:

select item, add_months(min_date, level) as period_start_date 
from (
    select item, min(period_start_date) min_date, 
    months_between(max(period_start_date), min(period_start_date)) as num_months 
    from your_table 
    group by item 
) 
connect by level < num_months 

Это дает вам, в этом случае, шесть фиктивных строки, за апрель по августу. (Мы знаем, что нам не нужны фиктивные строки в марте или сентябре).

Тогда вы можете исключить из списка настоящие данные с not exists; и союз, с данными реальной таблицы:

select item, period_start_date, qty_used 
from your_table 
union all 
select item, period_start_date, 0 
from (
    select item, add_months(min_date, level) as period_start_date 
    from (
    select item, min(period_start_date) min_date, 
     months_between(max(period_start_date), min(period_start_date)) as num_months 
    from your_table 
    group by item 
) 
    connect by level < num_months 
) t 
where not exists (
    select null 
    from your_table 
    where item = t.item 
    and period_start_date = t.period_start_date 
) 
order by item, period_start_date; 

     ITEM PERIOD_STAR QTY_USED 
---------- ----------- ---------- 
     1234 01-MAR-2015   10 
     1234 01-APR-2015   0 
     1234 01-MAY-2015   0 
     1234 01-JUN-2015   32 
     1234 01-JUL-2015   14 
     1234 01-AUG-2015   0 
     1234 01-SEP-2015   11 

С фиксированной датой начала вы можете изменить сгенерированную таблицу:

select item, period_start_date, qty_used 
from your_table 
union all 
select item, period_start_date, 0 
from (
    select item, add_months(date '2013-03-01', level - 1) as period_start_date 
    from (select distinct item from your_table) 
    connect by add_months(date '2013-03-01', level - 1) < sysdate 
) t 
where not exists (
    select null 
    from your_table 
    where item = t.item 
    and period_start_date = t.period_start_date 
) 
order by item, period_start_date; 

Вы можете также левую внешнее соединение из сгенерированных данных таблицы, но конечно, придется использовать старый синтаксис, специфичный для Oracle:

select t.item, t.period_start_date, nvl(yt.qty_used, 0) as qty 
from (
    select item, add_months(date '2013-03-01', level - 1) as period_start_date 
    from (select distinct item from your_table) 
    connect by add_months(date '2013-03-01', level - 1) < sysdate 
) t, your_table yt 
where yt.item (+) = t.item 
and yt.period_start_date (+) = t.period_start_date 
order by t.item, t.period_start_date; 
+0

Спасибо всем. То, что мы закончили, не очень гламурно, но оно работает. См. Ниже: –

+0

Путь слишком много символов - LOL - мы использовали минус и объединение все в двух словах. Как и ответ Алекса. Благодаря! –