我有一种情况,我需要根据where子句输入迭代一个条件,想知道它是如何完成的。
背景是,在一个储存单元中,它由几个储罐组成,每个储罐都有自己的储罐倾斜测量状态,具有不同的最后测量日期,我如何获得特定日期的最新倾角值?
示例:
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 作为其中一部分查询结果,因为它不是表的一部分。
从2014年2月1日到2014年2月28日,我怎样才能以动态的方式提供日期范围,以获得完整的结果?和一个显示报告日期的临时栏?
最终结果将是:
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)
您可以使用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
。
答案 1 :(得分: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
答案 2 :(得分: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
。
答案 3 :(得分: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