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 的左连接

    使用每个seqnumLAGLAST_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(代码

ORACLE的SQL JOIN方式小结

oracle SQL left join()或full out join()根据键排除记录

left joinright joininner joinfull join