2015-02-24 5 views
1

У меня возникла ситуация, когда мне нужно итерировать условие, основанное на вводе предложения, интересно, как это можно сделать.Итерация внутри подзапроса

Фон, в одном блоке хранения, состоит из нескольких резервуаров, каждый танк имеет свой собственный измеренный статус танков, с другой последней измеренной датой, как я могу получить последнее значение погружения определенной даты?

Пример:

Tank A having last measured date (EndDate) as 01 Feb 2015. 
Tank B having last measured date (EndDate) as 31 Jan 2015. 
Tank B having last measured date (EndDate) as 17 Feb 2015. 
Tank C having last measured date (EndDate) as 18 Feb 2015. 

Структура таблицы:

Tanks| DipDaytime| Volume| EndDate 
A, 28 Jan 2015 8pm, 1000, 01 Feb 2015 
B, 30 Jan 2015 5pm, 2000, 31 Jan 2015 
B, 01 Feb 2015 5pm, 2500, 17 Feb 2015 
C, 01 Feb 2015 3pm, 3000, 18 Feb 2015 

Ожидаемый результат будет:

For 31 Jan 2015: 
A, 28 Jan 2015 8pm, 1000, 01 Feb 2015 
B, 30 Jan 2015 5pm, 2000, 31 Jan 2015 

For 18 Feb 2015: 
A, 28 Jan 2015 8pm, 1000, 01 Feb 2015 
B, 01 Feb 2015 5pm, 2500, 17 Feb 2015 
C, 01 Feb 2015 3pm, 3000, 18 Feb 2015 

я смог выйти что-то вроде этого:

SELECT ts.Tanks, ts.DipDaytime, ts.EndDate , ts.Volume 
FROM table ts 
WHERE ts.EndDate =  
(SELECT MAX(ts2.EndDate) FROM table ts2 
         WHERE ts2.Tanks = ts.Tanks 
         AND ts2.EndDate <= '17.02.2014') 

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

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

Конечный результат будет тогда:

For 31 Jan 2015: 
Tank | DipDaytime| Volume| EndDate, ReportDate 
A, 28 Jan 2015 8pm, 1000, 01 Feb 2015, 31 Jan 2015 
B, 30 Jan 2015 5pm, 2000, 31 Jan 2015, 31 Jan 2015 

For 18 Feb 2015: 
Tank | DipDaytime| Volume| EndDate, ReportDate 
A, 28 Jan 2015 8pm, 1000, 01 Feb 2015, 18 Feb 2015 
B, 01 Feb 2015 5pm, 2500, 17 Feb 2015, 18 Feb 2015 
C, 01 Feb 2015 3pm, 3000, 18 Feb 2015, 18 Feb 2015 

Оценил если кто может помочь. Благодарю.

+0

почему танк А появляясь в обоих случаях? –

+0

@SagarJoon: потому что нет никаких изменений в танке А между 31.01 и 18.02? – Andomar

ответ

0

Вы можете использовать row_number(), чтобы фильтровать последние строки за (Tank) группы. Использование подзапросов трюка вы можете использовать константу как для фильтрации и отображение:

select * 
from (
cross join 
     (
     select row_number() over (
        partition by tank 
        order by EndDate desc) as rn 
     ,  * 
     from Tanks 
     cross join 
       (
       select '17.02.2014' as report_date 
       from dual 
       ) pars 
     where EndDate <= report_date 
     ) numbered_rows 
where rn = 1 -- Latest row per tank 

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

0

Вы можете попробовать что-то вроде:

with report_dates as 
(
    select to_date('31 Jan 2015', 'dd Mon yyyy') report_date from dual 
    union all 
    select to_date('18 Feb 2015', 'dd Mon yyyy') report_date from dual 
) 
select t.tanks, d.report_date, 
     max(t.dipdaytime) keep (dense_rank last order by t.enddate) DipDaytime, 
     max(t.volume) keep (dense_rank last order by t.enddate) volume, 
     max(t.enddate) enddate 
from table t, report_dates d 
where t.dipdaytime <= d.report_date 
group by t.tanks, d.report_date 
order by d.report_date, t.tanks 
; 

Это дает:

TANKS VOLUME REPORT_DATE DIPDAYTIME ENDDATE 
1 A 1000 31-janv.-2015 28-janv.-2015 01-févr.-2015 
2 B 2000 31-janv.-2015 30-janv.-2015 31-janv.-2015 
3 A 1000 18-févr.-2015 28-janv.-2015 01-févr.-2015 
4 B 2500 18-févr.-2015 01-févr.-2015 17-févr.-2015 
5 C 3000 18-févr.-2015 01-févr.-2015 18-févr.-2015 
0

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

with rd as (
     select date '2015-01-31' as ReportDate from dual 
     union all 
     select date '2015-02-18' from dual 
    ) 
select rd.ReportDate, t.* 
from table t cross join 
    rd 
where t.dipdaytime = (select max(t2.dipdaytime) 
         from table t2 
         where t2.tank = t.tank and 
          t2.dipdaytime <= rd.ReportDate 
        ); 

Это используется коррелированный подзапрос, чтобы найти максимум dipdaytime для каждого резервуара до любой заданной даты.

0

Этот запрос дает результаты для выбранного периода. Вы должны определить начальную дату отчета и последнюю дату в первом подзапросе (dates).

with dates as (
    select to_date('2015-02-15') + level - 1 tdate 
    from dual 
    connect by to_date('2015-02-15') + level - 1 <= '2015-02-18'), 
tanks as (
    select * 
    from (
     select tdate, tanks, dipdaytime, volume, enddate 
      row_number() over (partition by tanks, tdate order by enddate desc) rn 
     from dates 
     left join ts on ts.enddate <= dates.tdate) 
    where rn = 1) 
select tdate, tanks, dipdaytime, volume 
    from tanks 
    order by tdate, tanks 


TDATE  TANKS  DIPDAYTIME  VOLUME 
----------- ---------- ----------- ---------- 
2015-02-15 A   2015-01-28  1000 
2015-02-15 B   2015-01-30  2000 
2015-02-16 A   2015-01-28  1000 
2015-02-16 B   2015-01-30  2000 
2015-02-17 A   2015-01-28  1000 
2015-02-17 B   2015-02-01  2500 
2015-02-18 A   2015-01-28  1000 
2015-02-18 B   2015-02-01  2500 
2015-02-18 C   2015-02-01  3000 

9 rows selected 

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

with dates as (
    select to_date('2015-02-15') + level - 1 tdate 
    from dual 
    connect by to_date('2015-02-15') + level - 1 <= '2015-02-18'), 
tanks as (
    select * 
    from (
     select tdate, tanks, dipdaytime, volume, enddate, 
      row_number() over (partition by tanks, tdate order by enddate desc) rn 
     from dates 
     left join ts on ts.enddate <= dates.tdate) 
    where rn = 1) 
select dates.tdate, 
    ta.dipdaytime a_ddt, ta.volume a_vol, ta.enddate a_end, 
    tb.dipdaytime b_ddt, tb.volume b_vol, tb.enddate b_end, 
    tc.dipdaytime c_ddt, tc.volume c_vol, tc.enddate c_end 
    from dates 
    left join tanks ta on ta.tdate = dates.tdate and ta.tanks = 'A' 
    left join tanks tb on tb.tdate = dates.tdate and tb.tanks = 'B' 
    left join tanks tc on tc.tdate = dates.tdate and tc.tanks = 'C' 
    order by tdate 

Результаты:

TDATE  A_DDT   A_VOL A_END  B_DDT   B_VOL B_END  C_DDT   C_VOL C_END 
----------- ----------- ---------- ----------- ----------- ---------- ----------- ----------- ---------- ----------- 
2015-02-15 2015-01-28  1000 2015-02-01 2015-01-30  2000 2015-01-31       
2015-02-16 2015-01-28  1000 2015-02-01 2015-01-30  2000 2015-01-31       
2015-02-17 2015-01-28  1000 2015-02-01 2015-02-01  2500 2015-02-17       
2015-02-18 2015-01-28  1000 2015-02-01 2015-02-01  2500 2015-02-17 2015-02-01  3000 2015-02-18 
Смежные вопросы