我有桌子: A(ID_A,VALID_FROM,DATA ......) B(ID_B,ID,T1,T2,T3,DATE)
表A可以包含历史数据(例如,在给定时期内有效的数据) 我需要从表B中选择与表A中的appropritate记录连接的记录(从表A我需要行,其中b.id = a.id_a,记录在b.date有效)
select *
from B, (select * from (select * from A where a.id_a = b.id and a.valid_from <= b.date order by valid_from desc) where rownum = 1)
where b.id = a.id_a
答案 0 :(得分:2)
答案 1 :(得分:1)
这不是更优化,但可能更具可读性:
select *
from A a, B b
Where
a.id_a = b.id
and a.valid_from = (select max(valid_from)
from A
where id_a = b.id
and valid_from <= b.date)
order by valid_from desc
我以前见过这个问题,我知道优化它的最好方法是将一个valid_to列放到表A上。
对于最新记录,这应包含Oracle可以处理的最大日期 每当你创建一个较新版本的记录时,用创建新记录的时间更新它(减去毫秒以避免重叠),所以你有这样的东西:
ID Valid_from Valid_to
1 01/01/2011 12.34.56.0000 02/01/2011 12.34.56.0000
1 02/01/2011 12.34.56.0001 03/01/2011 12.34.56.0000
1 03/01/2011 12.34.56.0001 31/12/9999 23.59.59.9999
然后你可以像这样查询:
select *
from A a, B b
Where
a.id_a = b.id
and b.date between a.valid_from and a.valid_to
order by valid_from desc
使用日期列上的索引,性能应该没问题。
答案 2 :(得分:0)
我已经接受了StevieG的回答并对其进行了扩展。如果没有valid_to
列,则需要编写棘手的子查询。我建议使用LEAD
分析函数来查找当前有效期的结束并使用它。这是子查询和valid_to列的替代方法。
LEAD
分析函数查看当前数据集中的行,并查找下一个valid_from日期,并将其用作当前期间的结尾。
我的查询如下所示。它将您提供的样本数据合并到with子句中。
with table_a as (
select 1 as id, 'XXX1' as data, date '2009-01-01' as valid_from from dual union all
select 1 as id, 'XXX2' as data, date '2009-05-30' as valid_from from dual union all
select 1 as id, 'XXX3' as data, date '2010-01-11' as valid_from from dual union all
select 2 as id, 'YYY' as data, date '1999-01-01' as valid_from from dual
),
table_b as (
select 1 as id, 1 as id_a, date '2009-02-01' as date_col from dual union all
select 2 as id, 2 as id_a, date '2009-09-12' as date_col from dual union all
select 3 as id, 1 as id_a, date '2009-06-30' as date_col from dual
)
select *
from table_b b
join (
select
id,
valid_from,
lead(valid_from, 1, date '9999-12-31') over (partition by a.id order by a.valid_from) as valid_to
from table_a a
) a on (a.id = b.id_a)
where
a.valid_from <= b.date_col and
b.date_col < a.valid_to