SQL如何只加入第一个匹配的行

时间:2015-08-31 08:22:38

标签: sql oracle join top-n

我不明白如何只加入第一个匹配的行。如果我通过person_id和dates的组合加入,则查询将返回多个值。在这种情况下,如果join返回多个值,我只希望显示此联接中的一行。预期结果 - assignment_id,effective_start_date,effective_end_date的组合是唯一的。

让我最困扰的是我没有唯一的标识符,只有日期。如果来自外派人员表的两个日期范围适合分配有效_start_date,effective_end_date范围我只需要显示一行。

请提供Oracle语法(如我的代码示例)。

with assignments (assignment_id, person_id, effective_start_date, effective_end_date) as (
   select 456, 123, date '2015-01-01', date '2015-03-15' from dual union all  
   select 456, 123, date '2015-03-16', date '4712-12-31' from dual union all   
   select  975, 123, date '2015-03-16', date '4712-12-31' from dual            
 ),
expatriates (person_id, home_country, host_country, date_from, date_to, valid_from, valid_to)
as
(
   select 123, 'TEST2', 'TEST2',    date '2015-01-01', date '2015-03-15', date '2015-01-01', date   '2015-03-15' from dual union all
   select 123, 'TEST1', 'TEST1',    date '2015-04-16', date '2016-06-15', date '2015-04-16', date   '2016-06-15' from dual union all
   select 123, 'TEST',  'TEST',   date '2015-03-16', date '2016-04-15', date '2015-03-16', date '2015-04-15' from dual
)

select 
    a.assignment_id,
    a.person_id, 
    a.effective_start_date, 
    a.effective_end_date,
    subq.home_country, 
    subq.host_country, 
    subq.date_from, 
    subq.date_to
from assignments a
     , expatriates subq 
where 
    a.person_id=subq.person_id
    and subq.valid_from <= a.effective_end_date
   and subq.valid_to >= a.effective_start_date

2 个答案:

答案 0 :(得分:1)

这是子查询中的分析排名函数的经典用例,可以对其进行过滤以返回所需的子集。在这种情况下,我使用了ROW_NUMBER(),因为你还没有提供丢弃行的任何标准,所以假设确实哪个实际行是&#34;第一个&#34;行。

select assignment_id,
        person_id, 
        effective_start_date, 
        effective_end_date,
        date_from, 
        date_to,
        home_country, 
        host_country
from (
    select 
        a.assignment_id,
        a.person_id, 
        a.effective_start_date, 
        a.effective_end_date,
        e.date_from, 
        e.date_to,
        e.home_country, 
        e.host_country,
        row_number() over (partition by a.assignment_id, a.effective_start_date 
                            order by e.date_from) rn
    from assignments a
         join expatriates e
    on  (a.person_id=e.person_id )
    where e.valid_from <= a.effective_end_date
        and e.valid_to >= a.effective_start_date
)
where rn = 1
order by 1, 3, 2
/

这将从您的示例数据中返回以下行:

 28* order by 1, 3, 2

ASSIGNMENT_ID  PERSON_ID EFFECTIVE EFFECTIVE DATE_FROM DATE_TO   HOME_ HOST_
------------- ---------- --------- --------- --------- --------- ----- -----
          456        123 01-JAN-15 15-MAR-15 01-JAN-15 15-MAR-15 TEST2 TEST2
          456        123 16-MAR-15 31-DEC-12 16-MAR-15 15-APR-16 TEST  TEST
          975        123 16-MAR-15 31-DEC-12 16-MAR-15 15-APR-16 TEST  TEST

3 rows selected.

SQL> 

Oracle拥有大量简洁的分析功能。 Find out more

答案 1 :(得分:0)

我不确定从您需要的外派人员表中过滤记录的标准,但作为示例,我们可以按date_from字段进行过滤:

with assignments (assignment_id, person_id, effective_start_date, effective_end_date) as (
   select 456, 123, date '2015-01-01', date '2015-03-15' from dual union all  
   select 456, 123, date '2015-03-16', date '4712-12-31' from dual union all   
   select  975, 123, date '2015-03-16', date '4712-12-31' from dual            
 ),


expatriates (person_id, home_country, host_country, date_from, date_to, valid_from, valid_to)
as
(
   select 123, 'TEST2', 'TEST2',    date '2015-01-01', date '2015-03-15', date '2015-01-01', date   '2015-03-15' from dual union all
   select 123, 'TEST1', 'TEST1',    date '2015-04-16', date '2016-06-15', date '2015-04-16', date   '2016-06-15' from dual union all
   select 123, 'TEST',  'TEST',   date '2015-03-16', date '2016-04-15', date '2015-03-16', date '2015-04-15' from dual

)

select 
a.assignment_id,
a.person_id, 
a.effective_start_date, 
a.effective_end_date,
subq.home_country, 
subq.host_country, 
subq.date_from, 
subq.date_to
from assignments a, expatriates subq 
where 
a.person_id=subq.person_id
and subq.valid_from <= a.effective_end_date
and subq.valid_to >= a.effective_start_date
and subq.date_from = 
(
  select 
    max(date_from) 
  from expatriates sq2 
    where 
      sq2.person_id = a.person_id and 
      sq2.valid_from <= a.effective_end_date and 
      sq2.valid_to >= a.effective_start_date 
)

SqlFiddle