SQL如何在不使用嵌套子查询的情况下外部联接第一个匹配值

SQL如何在不使用嵌套子查询的情况下外部联接第一个匹配值,sql,oracle,date,join,Sql,Oracle,Date,Join,所以我有这个问题已经有一段时间了,我需要连接两个表,但是我没有唯一的标识符,所以我必须使用ID和日期范围。若两个日期范围重叠,我需要加入第一个值。我需要成为一个外部连接。我现在的代码在理论上是正确的,但是它不适合这种情况,我不能将这个连接作为外部连接,因为这样我会得到一个错误 逻辑如下:员工可以是外籍人员。如果他是外籍人士,我需要显示所有栏目。但棘手的是,如果在有效开始日期和有效结束日期之间的任务期间,他在两个不同的国家,我只需要显示上次旅行的信息。 最后一部分关于仅在MAXvalid上联接的内

所以我有这个问题已经有一段时间了,我需要连接两个表,但是我没有唯一的标识符,所以我必须使用ID和日期范围。若两个日期范围重叠,我需要加入第一个值。我需要成为一个外部连接。我现在的代码在理论上是正确的,但是它不适合这种情况,我不能将这个连接作为外部连接,因为这样我会得到一个错误

逻辑如下:员工可以是外籍人员。如果他是外籍人士,我需要显示所有栏目。但棘手的是,如果在有效开始日期和有效结束日期之间的任务期间,他在两个不同的国家,我只需要显示上次旅行的信息。 最后一部分关于仅在MAXvalid上联接的内容需要调整-因此,通过这种方式,分配id、有效开始日期、有效结束日期的组合是唯一的,因此此表可以正确联接到其他表

我知道这可以通过一个连接来解决,我只是不知道如何在不使用任何嵌套子查询的情况下完成

请向我提供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 union all
  select  674, 145, 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 
)

我猜您对开始查询的关注点是它使用了一个相关的子查询,而相对于一个不相关的子查询,这确实是一个性能问题。查询的结构确实可以避免相关子查询,但更一般地说,不能避免单独的查询,以确定与每个工作分配相关联的外派人员行是要报告的。下面的版本非常有效,因为最上面的查询只是从CTE结果中过滤不需要的行

这个单独的查询可以结构化为内联视图或公共表表达式。在这一点上,根据问题的字母,我使用下面的CTE来避免查询嵌套,即使在内联视图中有一个完全等效的表达式。它使用标准的外部联接语法。它还使用MAX的窗口函数版本,这需要相当新的Oracle

with 
-- other CTEs ... ,
all_rows (assignment_id, person_id, effective_start_date, effective_end_date,
  home_country, host_country, date_from, date_to, max_from) as
(
  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,
    max(subq.date_from) over (partition by a.assignment_id, a.person_id)
  from
    assignments a
    left outer join expatriates subq
      ON a.person_id = subq.person_id
        and subq.valid_from <= a.effective_end_date
        and subq.valid_to >= a.effective_start_date
)
select *
from all_rows
where date_from = max_from or max_from is null
;

这涵盖了两个范围重叠的所有情况。

使用适当的左连接运算符也是Oracle语法-甚至Oracle也建议停止使用旧的+运算符。您是说您提出的查询给出了正确的结果,但是您想要一个在WHERE子句中不使用子查询的替代方法?您的查询只选择完全在工作分配期间内的外派日期范围。您是否还需要考虑范围重叠但派遣范围不完全包含外派人员范围的情况?可能存在范围重叠但派遣范围不完全包含外派人员范围的情况。如果我使用外部联接,则我提供的查询不起作用。基本上,它提供了我所需要的一切,只是不适用于子查询上的外部联接。您以前问过类似的问题,并使用行号/秩得到了解决方案,您也可以在这里应用它。
      ON a.person_id = subq.person_id
        AND (subq.valid_from BETWEEN a.effective_start_date AND a.effective_end_date
          OR a.effective_start_date BETWEEN subq.valid_from AND subq.valid_to)