在 11g 中使用两步方法。在第一步中,简单地连接两个带有年份约束的表。
select a.id, a.year, b.year b_year, b.val
from a
left outer join b
on a.id = b.id and a.year >= b.year
;
I YEAR B_YEAR VAL
- ---------- ---------- ----------
a 2000 2000 1
b 2000 1999 1
c 2003 2003 1
c 2000
通常每个a.id 和a.year 都会获得更多行,因此在第二步中,您只过滤具有最低b.year 的行 - 这是使用ROW_NUMBER 完成的,并在第一行(@ 987654326@)
with ab as (
select a.id, a.year, b.val,
row_number() over (partition by a.id, a.year order by b.year) as rn
from a
left outer join b
on a.id = b.id and a.year >= b.year
)
select
id, year, val
from ab
where rn = 1
I YEAR VAL
- ---------- ----------
a 2000 1
b 2000 1
c 2000
c 2003 1
正如您所提到的,如果要加入许多版本,这种方法可能会令人望而却步。我将通过交换你的条件来模拟它以获得最小的更高年份(因为没有多少更低的年份可用)。
这里是示例数据
create table a as
select 'a' id, 2000 year from dual union all
select 'b' id, 2000 year from dual union all
select 'c' id, 2000 year from dual union all
select 'c' id, 2003 year from dual;
drop table b;
create table b as
select 'a' id, 1000 + rownum year, rownum val from dual connect by level <= 1000000
union all
select 'b', 1000 + rownum year, rownum val from dual connect by level <= 1000000
union all
select 'c', 2000 + rownum year, rownum val from dual connect by level <= 2
;
确实,前面的方法会导致大量的中间结果
with ab as (
select a.id, a.year, b.val
from a
left outer join b
on a.id = b.id and a.year <= b.year
)
select count(*) from ab;
1998005
那么替代解决方案是什么?
简单的在第一步中预计算最小的最高年份
select a.id, a.year, min(case when b.year >= a.year then b.year end) b_year
from a
left outer join b
on a.id = b.id
group by a.id, a.year
I YEAR B_YEAR
- ---------- ----------
c 2000 2001
a 2000 2000
c 2003
b 2000 2000
并使用预先计算的表与b 进行等值连接
with ab as (
select a.id, a.year, min(case when b.year >= a.year then b.year end) b_year
from a
left outer join b
on a.id = b.id
group by a.id, a.year)
select
ab.id, ab.year, b.val
from ab
left outer join b
on ab.id = b.id and ab.b_year = b.year;
I YEAR VAL
- ---------- ----------
c 2000 1
a 2000 1000
c 2003
b 2000 1000