Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Помогите с запросом!  [new]
Alex_SPD
Member

Откуда:
Сообщений: 17
10 лет не брал в руки SQL, а Оракл вообще никогда не брал. Уже весь мозг себе сломал, не могу понять как сделать.
Нужно вставить в промежутки недостающие даты с интервалом в месяц и заполнить остальные поля значением из предидущей строки.
Пример:

В результате некого запроса я получаю табличку вида:

Дата	        Значение	Значение 2
01.01.2010	1	        A
01.02.2010	1	        B
01.06.2010	1	        C
01.09.2010	1	        D
01.10.2010	1	        E
01.12.2010	1	        F
01.01.2010	2	        Q
01.02.2010	2         	W
01.04.2010	2       	E
01.09.2010	2       	R
01.10.2010	2       	T


А нужно такого:

Дата	         Значение	Значение 2
01.01.2010	       1	A
01.02.2010           1	       B
01.03.2010	       1	B
01.04.2010	       1	B
01.05.2010	       1	B
01.06.2010	       1	C
01.07.2010	       1	C
01.08.2010	       1	C
01.09.2010	       1	D
01.10.2010	       1	E
01.11.2010	       1	E
01.12.2010           1       	F
01.01.2010	       2	Q
01.02.2010	       2	W
01.03.2010	       2	W
01.04.2010	       2	E
01.05.2010	       2	E
01.06.2010	       2	E
01.07.2010	       2	E
01.08.2010	       2	E
01.09.2010	       2	R
01.10.2010	       2	T
01.11.2010	       2	T
01.12.2010	       2	T


Заранее спасибо!!!
6 ноя 12, 04:36    [13424404]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Добрый Э - Эх
Guest
cross join с inline-view + аналитикой поверху (last_value ignore nulls)
6 ноя 12, 07:02    [13424459]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Добрый Э - Эх
Guest
Уточнения по вопросу: данные всегда за один год?
А если в результате "некого запроса" отсутствуют данные на начало года?
К примеру, на таких данных что возвращать:
Дата	        Значение	Значение 2
01.09.2010	1	        D
01.10.2010	1	        E
01.12.2010	1	        F

01.04.2010	2       	E
01.09.2010	2       	R
01.10.2010	2       	T
6 ноя 12, 08:07    [13424511]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Alex_SPD
Member

Откуда:
Сообщений: 17
Добрый Э - Эх,

Данные за разные года, возвращать нужно с первого месяца. Данные не могут быть страше января 2000 года и младше sysdate.

Значнеие1 должно быть от 1 до 9, а знание 2 в запросе вычисляется и если нет начала, то оно должно быть подставным по умолчанию или null. По идее на сегодня запрос должен возвращать 1395 строк:
(12*12 //месяцев с 2000-2011 года 
+11 //месяцев в 12 году
)*9 // количество обязательных значений.
6 ноя 12, 09:35    [13424634]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
ora78
Member

Откуда:
Сообщений: 20
не совсем ясно с постановкой задачи
может так ?
with q as (
   select to_date('01.01.2010') ddate, 1 val1, 'A' val2 from dual union all
   select to_date('01.02.2010') ddate, 1 val1, 'B' val2 from dual union all
   select to_date('01.06.2010') ddate, 1 val1, 'C' val2 from dual union all
   select to_date('01.09.2010') ddate, 1 val1, 'D' val2 from dual union all
   select to_date('01.10.2010') ddate, 1 val1, 'E' val2 from dual union all
   select to_date('01.12.2010') ddate, 1 val1, 'F' val2 from dual union all
   select to_date('01.01.2010') ddate, 2 val1, 'Q' val2 from dual union all
   select to_date('01.02.2010') ddate, 2 val1, 'W' val2 from dual union all
   select to_date('01.04.2010') ddate, 2 val1, 'E' val2 from dual union all
   select to_date('01.09.2010') ddate, 2 val1, 'R' val2 from dual union all
   select to_date('01.10.2010') ddate, 2 val1, 'T' val2 from dual
   )
   select add_months(ddate, column_value) ddate,
          decode(column_value, 0, val1, l_val1) val1,
          decode(column_value, 0, val2, l_val2) val2
     from (select q.ddate,
                  extract(month from ddate) - lag(extract(month from ddate)) over(partition by val1 order by ddate) ndiff_m,
                  extract(year from ddate) - lag(extract(year from ddate)) over(partition by val1 order by ddate) ndiff_y,
                  val1,
                  val2,
                  lag(val1) over(partition by val1 order by ddate) l_val1,
                  lag(val2) over(partition by val1 order by ddate) l_val2
             from q) t,
          table(cast(multiset
                     (select 1 - level from dual connect by level <= 12*ndiff_y+t.ndiff_m ) as
                     sys.odcinumberlist)) l
    order by val1, ddate;
 
DDATE             VAL1 VAL2
----------- ---------- ----
01.01.2010           1 A
01.02.2010           1 B
01.03.2010           1 B
01.04.2010           1 B
01.05.2010           1 B
01.06.2010           1 C
01.07.2010           1 C
01.08.2010           1 C
01.09.2010           1 D
01.10.2010           1 E
01.11.2010           1 E
01.12.2010           1 F
01.01.2010           2 Q
01.02.2010           2 W
01.03.2010           2 W
01.04.2010           2 E
01.05.2010           2 E
01.06.2010           2 E
01.07.2010           2 E
01.08.2010           2 E
01.09.2010           2 R
01.10.2010           2 T
 
22 rows selected
6 ноя 12, 09:58    [13424736]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Добрый Э - Эх
Guest
Общая схема подхода к решению задачи:
select nvl(q.dt, pvt.dt) as dt,
       nvl(q.val1, pvt.val1) as val1,
       val2 -- х.з. что за обработка или значение по умолчанию
  from (-- тут твой запрос, при помощи которого ты получаешь "табличку вида":
         select to_date('01.01.2010','dd.mm.yyyy') as dt, 1 as val1, '1' as val2 from dual union all
         select to_date('01.02.2010','dd.mm.yyyy') as dt, 1 as val1, '2' as val2 from dual union all
         select to_date('01.06.2010','dd.mm.yyyy') as dt, 1 as val1, '3' as val2 from dual union all
         select to_date('01.09.2010','dd.mm.yyyy') as dt, 1 as val1, '4' as val2 from dual union all
         select to_date('01.10.2010','dd.mm.yyyy') as dt, 1 as val1, '5' as val2 from dual union all
         select to_date('01.12.2010','dd.mm.yyyy') as dt, 1 as val1, '6' as val2 from dual union all
         select to_date('01.01.2010','dd.mm.yyyy') as dt, 2 as val1, '1' as val2 from dual union all
         select to_date('01.02.2010','dd.mm.yyyy') as dt, 2 as val1, '2' as val2 from dual union all
         select to_date('01.04.2010','dd.mm.yyyy') as dt, 2 as val1, '3' as val2 from dual union all
         select to_date('01.09.2010','dd.mm.yyyy') as dt, 2 as val1, '4' as val2 from dual union all
         select to_date('01.10.2010','dd.mm.yyyy') as dt, 2 as val1, '5' as val2 from dual
       ) q
  right join
        (-- Генерируем нужное кол-во строк (кол-во месяцев * 9)
          select add_months(date'2000-01-01', ceil(level/9) - 1) as dt,
                 ceil(level/9) as val1
            from dual connect by level < 9*(months_between(sysdate, date'2000-01-01') + 1) - 1
        ) pvt
    on pvt.dt = q.dt
   and pvt.val1 = q.val1
order by 2,1
6 ноя 12, 10:07    [13424771]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Добрый Э - Эх
Guest
ora78
может так ?
22 rows selected
Точно не так. За два года на исходном наборе должно было вернуть как минимум 24 строки
6 ноя 12, 10:08    [13424775]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
FANTASIST
Member

Откуда:
Сообщений: 38
Добрый Э - Эх,

Значит, количество строк зависит от количества уникальных "значений 1" ?

Тога нужно:

-- количество месяцев
select add_months(to_date('01.01.2000'), level-1), level
from dual
connect by level <= months_between(last_day(sysdate)+1, '01.01.2000')

-- пересечь на количество уникальных значений
select distinct "значение 1" from you_table

потом вычисли например при помощи case и/или lag, используя аналитику, приведенную выше.
6 ноя 12, 12:27    [13425672]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
MasterZiv
Member

Откуда: Питер
Сообщений: 34630
Alex_SPD,

Если не пытаться написать это одним запросом, будет гораздо проще и эффективнеее.
6 ноя 12, 14:00    [13426486]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
SY
Member

Откуда: Middlebury, CT USA
Сообщений: 10051
MasterZiv
Если не пытаться написать это одним запросом, будет гораздо проще и эффективнеее.


Да ну ?

SY.
6 ноя 12, 16:01    [13427538]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Добрый Э - Эх
Guest
SY
MasterZiv
Если не пытаться написать это одним запросом, будет гораздо проще и эффективнеее.


Да ну ?

SY.
SY, будь снисходительнее - MasterZiv новичок в Оракле и ещё не знает всех его тонкостей. Да и Кайта, наверное, прочитать ещё не успел. :)
Но он старательный и быстро проникнется всеми нюансами, исправится и так шутить больше не будет ;)
6 ноя 12, 17:47    [13428554]     Ответить | Цитировать Сообщить модератору
 Re: Помогите с запросом!  [new]
Alex_SPD
Member

Откуда:
Сообщений: 17
Всем огромное спасибо! Очень помогло. Сделал в итоге вот так (если не лень на явные косяки можно указать):

WITH
M AS (-- Столбец с номерами микрорайонов (1-9)
       SELECT 1 AS MDistr FROM dual UNION ALL
       SELECT 2 AS MDistr FROM dual UNION ALL       
       SELECT 3 AS MDistr FROM dual UNION ALL
       SELECT 4 AS MDistr FROM dual UNION ALL
       SELECT 5 AS MDistr FROM dual UNION ALL
       SELECT 6 AS MDistr FROM dual UNION ALL
       SELECT 7 AS MDistr FROM dual UNION ALL
       SELECT 8 AS MDistr FROM dual UNION ALL
       SELECT 9 AS MDistr FROM dual 
),

D AS (--- заполнение столбца датами с иинтервалом в месяц
       SELECT TRUNC(ADD_MONTHS('01-янв-2000', ROWNUM),'mon') AS SumAppDateS
       FROM all_objects 
       WHERE TRUNC(ADD_MONTHS('01-янв-2000', ROWNUM),'mon')<=SYSDATE 
     ),
     
MD AS (-- Объеденяем M и D, получаем массив со всеми месяцами начиная с 2000 года и со всеми микрорайонами
        SELECT * FROM D,M),    
     
      
S AS (-- Здесь мой исходный запрос
      
     ),
     
RES AS ( -- соединяем с таблицей с датами, чтобы не было пробелов в месяцах
       SELECT rownum AS RES_ID,
              SumAppDateS AS SumAppDateS, 
              MDISTR AS MDISTR,
              AppStore AS AppStore, 
              AppStoreSum AS AppStoreSum    
       
              FROM S
              right join MD
                    on MD.SumAppDateS = S.SumAppDate
                    and MD.MDistr=S.MicroDistr 
              where (MD.MDistr=S.MicroDistr OR S.MicroDistr is null) -- убираем лишние строки
       ) 
  
SELECT SumAppDateS AS SumAppDate,
       MDistr AS MicroDistr, 
       NVL(AppStore,0) AS AppStore, -- заполняем пустые месяцы нулями
       last_value(AppStoreSum ignore nulls) over(partition BY MDistr order by RES_ID) AS AppStoreSum -- заполняем сумму по пустым месяцам
       From RES
7 ноя 12, 21:58    [13436242]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить