加入单列日期范围内的记录

时间:2017-03-02 18:57:32

标签: sql oracle

我有两张桌子:

Person
+---------+-----------+
|  Name   |   Added   |
+---------+-----------+
| Roger   | 2/1/2001  |
| Natalie | 5/5/2001  |
| George  | 6/6/2001  |
| Paul    | 12/5/1999 |
+---------+-----------+

Stage
+-------------+----------+
| Description |  Start   |
+-------------+----------+
| 1           | 1/1/1980 |
| 2           | 4/1/2001 |
| 3           | 6/1/2001 |
+-------------+----------+

我想加入舞台的人,以便得到以下结果。

Result
+---------+-----------+--------+
|  Name   |   Added   | Stage  |
+---------+-----------+--------+
| Roger   | 2/1/2001  | 1      |
| Natalie | 5/5/2001  | 2      |
| George  | 6/6/2001  | 3      |
| Paul    | 12/5/1999 | 1      |
+---------+-----------+--------+

因此,阶段1匹配(添加> = 1/1/1980并添加< 4/1/2001),阶段2匹配(添加> = 4/1/2001并添加< 6/1 / 2001),第3阶段(添加> = 6/1/2001)等......这有效,但我觉得它有点丑陋(只是因为描述也是连续的,所以才会发生作用)。

SELECT  person.name,
        person.added,
        (SELECT MAX(description) FROM stage d2 WHERE person.added >= d2.start) description
FROM    person

有没有办法在常规连接中执行此操作,并且如果描述是字符串而不是序列号?感谢。

3 个答案:

答案 0 :(得分:3)

您可以使用row_number()

而不是子查询
select name, added, description
from (
  select p.name, p.added, s.description
    , row_number() over (
        partition by p.name
        order by s.start desc
        ) as rn
  from person p
    inner join stage s
      on s.start <= p.added
) t
where rn = 1

测试设置:http://rextester.com/SIAUAZ29747

with Person (Name,Added_date) as (
  select 'Roger'   , to_date('2001-02-01','yyyy-mm-dd') from dual union all 
  select 'Natalie' , to_date('2001-05-05','yyyy-mm-dd') from dual union all 
  select 'George'  , to_date('2001-06-06','yyyy-mm-dd') from dual union all 
  select 'Paul'    , to_date('1999-12-05','yyyy-mm-dd') from dual
),
Stage ( Description  , Start_date ) as (
  select 1, to_date('1980-01-01','yyyy-mm-dd') from dual union all
  select 2, to_date('2001-04-01','yyyy-mm-dd') from dual union all
  select 3, to_date('2001-06-01','yyyy-mm-dd') from dual
)
select name, to_char(added_date,'yyyy-mm-dd') added, description
from (
  select p.name, p.added_date, s.description
    , row_number() over (
        partition by p.name
        order by s.start_date desc
        ) as rn
  from person p
    inner join stage s
      on s.start_date <= p.added_date
) t
where rn = 1
order by added_date 

返回:

+---------+------------+-------------+
|  NAME   |   ADDED    | DESCRIPTION |
+---------+------------+-------------+
| Paul    | 1999-12-05 |           1 |
| Roger   | 2001-02-01 |           1 |
| Natalie | 2001-05-05 |           2 |
| George  | 2001-06-06 |           3 |
+---------+------------+-------------+

答案 1 :(得分:1)

这是一个将PersonStage中的行以1:1对应方式连接的版本(与将Person加入Stage中的多个行的已接受解决方案不同然后必须过滤掉不需要的行):

Oracle安装程序

CREATE TABLE Person (Name,Added) AS
  SELECT 'Roger'   , DATE '2001-02-01' FROM DUAL UNION ALL 
  SELECT 'Natalie' , DATE '2001-05-05' FROM DUAL UNION ALL 
  SELECT 'George'  , DATE '2001-06-06' FROM DUAL UNION ALL 
  SELECT 'Paul'    , DATE '1999-12-05' FROM DUAL;

CREATE TABLE Stage ( Description  , Start_date ) AS
  SELECT 1, DATE '1980-01-01' FROM DUAL UNION ALL
  SELECT 2, DATE '2001-04-01' FROM DUAL UNION ALL
  SELECT 3, DATE '2001-06-01' FROM DUAL;

<强>查询

SELECT name, added, description
FROM   person p
       INNER JOIN
       (
         SELECT description,
                start_date,
                LEAD( start_date ) OVER ( ORDER BY start_date ) AS end_date
         FROM   stage
       ) s
       ON ( s.start_date <= p.added AND ( s.end_date IS NULL OR p.added < s.end_date ) );

<强>输出

NAME    ADDED               DESCRIPTION
------- ------------------- -----------
Paul    1999-12-05 00:00:00           1
Roger   2001-02-01 00:00:00           1
Natalie 2001-05-05 00:00:00           2
George  2001-06-06 00:00:00           3

答案 2 :(得分:1)

这种类型的问题通常可以通过完全没有加入来解决。相反,将两个表(如下所示)与UNION ALL结合使用,并使用LAST_VALUE()函数:

select   name, added, description
from     (
           select name, added, 
                  last_value(description ignore nulls) 
                       over (order by added, description) as description
           from   ( select name, null as description, added
                      from person
                    union all
                    select null, description, start_date
                      from stage
                  )
         )
where    name is not null
order by added, name   --  if needed
;

NAME    ADDED        DESCRIPTION
------- ---------- -----------
Paul    12/05/1999 1
Roger   02/01/2001 1
Natalie 05/05/2001 2
George  06/06/2001 3

非常感谢@ MT0提供设置(CREATE TABLE语句)。