我有两张桌子:
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
有没有办法在常规连接中执行此操作,并且如果描述是字符串而不是序列号?感谢。
答案 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)
这是一个将Person
与Stage
中的行以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语句)。