Oracle Join 表与第一个表中的日期范围和第二个表中的日期
Posted
技术标签:
【中文标题】Oracle Join 表与第一个表中的日期范围和第二个表中的日期【英文标题】:Oracle Join tables with range of dates in first table and dates in second table 【发布时间】:2015-01-05 05:55:30 【问题描述】:我在 Oracle 数据库中有两个表:
第一个表有一个日期范围,我需要帮助来编写一个 SQL 查询来查找第二个表中的所有记录,如下面的结果表所示。日期中的前四位数字是年份,后两位是会话(10-Fall;20-Spring;30-Summer)。
1) 表1
seqnum | min_date| max_date |c_id
1 | 201210 | 201210 | 100
1 | 201220 | 201330 | 150
1 | 201410 | 201410 | 200
2) 表2
seqnum | b_date
1 | 201210
1 | 201220
1 | 201230
1 | 201310
1 | 201320
1 | 201330
1 | 201410
1 | 201420
1 | 201430
3) 结果表
seqnum | b_date | c_id
1 | 201210 | 100
1 | 201220 | 150
1 | 201230 | 150
1 | 201310 | 150
1 | 201320 | 150
1 | 201330 | 150
1 | 201410 | 200
1 | 201420 | 200
1 | 201430 | 200
如果Table1
只有第一条记录,那么Table2
中的所有日期必须与c_id
仅关联100。
【问题讨论】:
表1和表2的关系是什么? 【参考方案1】:小提琴: http://sqlfiddle.com/#!4/45c72/10/0
select t2.seqnum,
t2.b_date,
case when t2.b_date < min_rg then x.c_id
when t2.b_date > max_rg then y.c_id
else t1.c_id
end as c_id
from (select min(min_date) as min_rg, max(max_date) as max_rg from table1) z
join table1 x
on x.min_date = z.min_rg
join table1 y
on y.max_date = z.max_rg
cross join table2 t2
left join table1 t1
on t2.b_date between t1.min_date and t1.max_date
order by b_date
当 table2 上的 B_DATE 低于 table1 上的第一个 MIN_DATE 时,它将显示 table1 中最低 MIN_DATE 的 C_ID(在您的情况下为 100,现在)。
当 table2 上的 B_DATE 高于 table1 上的最后一个 MAX_DATE 时,它将显示 table1 中最高 MAX_DATE 的 C_ID(在您的情况下为 200,现在)。
【讨论】:
【参考方案2】:with table1 as (
select 1 seqnum, 201210 min_date, 201210 max_date, 100 c_id from dual
union all select 1, 201220, 201330, 150 from dual
union all select 1, 201410, 201410, 200 from dual
),
table2 as (
select 1 seqnum, 201210 b_date from dual
union all select 1, 201220 from dual
union all select 1, 201230 from dual
union all select 1, 201310 from dual
union all select 1, 201320 from dual
union all select 1, 201330 from dual
union all select 1, 201410 from dual
union all select 1, 201420 from dual
union all select 1, 201430 from dual
),
semi as (
select t2.seqnum, t2.b_date, t1.c_id,
-- since Oracle 11g
--lag(c_id IGNORE NULLS) over(partition by t2.seqnum order by t2.b_date) prev_c_id
last_value(c_id IGNORE NULLS) over(partition by t2.seqnum
order by t2.b_date
ROWS BETWEEN UNBOUNDED PRECEDING
AND 1 PRECEDING) prev_c_id
from table2 t2 left join table1 t1
on t2.seqnum = t1.seqnum and t2.b_date between t1.min_date and t1.max_date
)
select seqnum, b_date, nvl(c_id, prev_c_id) c_id
from semi;
这可以通过分析函数来完成。
Table2 和 Table1 的左连接
使用每个seqnum
(LAG
或LAST_VALUE
+ 窗口)计算上一个(行按b_date
排序)而不是c_id
的空值。
如果 c_id 为 NULL,则显示第一个不为空的先前值。
【讨论】:
【参考方案3】:要尽可能简单地做到这一点:
select t2.seqnum, t2.b_date, coalesce(t1.c_id, t3.max_id) as c_id
from table2 t2
left outer join table1 t1
on t2.b_date between t1.min_date and t1.max_date
cross join (select max(c_id) as max_id from table1) t3
order by t1.c_id, t2.b_date
SQLFiddle here
分享和享受。
【讨论】:
以上是关于Oracle Join 表与第一个表中的日期范围和第二个表中的日期的主要内容,如果未能解决你的问题,请参考以下文章
Oracle Query 按另一个表中的每个日期范围对一列求和
SQL从日期范围内的同一表中的不同记录中获取多个项目的总和(ORACLE)
Oracle表与表之间的连接方式(内连接:inner join 外连接 全连接: full outer join左连接:left outer join 右连接:right outer join(代码