使用子查询进行外部连接(Oracle 11g)

时间:2016-04-05 11:31:28

标签: oracle oracle11g subquery outer-join

我需要一个受子查询限制的表的外连接。但是,Oracle正在返回

ORA-01799: a column may not be outer-joined to a sub-query

然后我尝试在另一个子查询中推送外部联接,但由于原始子查询依赖于正在连接的主表中的字段,因此

失败
ORA-00904: "DTL"."TRANS_DATETIME": invalid identifier

有人可以建议如何解决此联接吗?

查询:

SELECT *
FROM header  hdr
JOIN detail  dtl
    ON hdr.trans_number = ptd.trans_number
LEFT JOIN ( SELECT  product_code
                   ,cost_price
            FROM prodcost pr
            WHERE pr.last_amend_date = (SELECT MAX(pc.last_amend_date)
                                        FROM   prodcost pc
                                        WHERE  pc.product_code = pr.product_code
                                            AND pc.last_amend_date <= trunc(dtl.trans_datetime))) p
    ON ptd.product_code = p.product_code

解释 我有headerdetail个表连接到事务编号(这实际上与问题无关,可以被视为单个表)。然后我需要在prodcost上加入product_code表格。但是,我必须根据last_amend_date

之前的最新trans_datetime对此进行限制

因此detail表是包含产品ID(product_code)和交易日期(trans_datetime)的交易记录。 prodcost表格中包含产品费用的记录,其中包含产品ID(product_code)和生效日期(last_amend_date)。因此,单个产品可能会有多种成本,具体取决于交易发生的时间。要确定正确的费用,我需要在product_code之前与last_amend_date之前的最新trans_datetime相关联。

我知道我可以将它分成两个查询,UNION它们可以提供完整的结果集。但是,如果可能的话,我宁愿避免这样做。关于如何解决的任何其他建议将不胜感激。

1 个答案:

答案 0 :(得分:1)

这里有几个例子应该可以帮助你实现自己的目标(由于你拒绝提供样本数据,我编制了自己的表/数据,但原则保持不变,你应该这样做能够将它应用到您自己的查询中):

示例1(使用左连接和分析函数):

with t1 as (select 1 id, to_date('01/01/2016', 'dd/mm/yyyy') dt, 'a' val from dual union all
            select 2 id, to_date('02/03/2016', 'dd/mm/yyyy') dt, 'b' val from dual union all
            select 3 id, to_date('03/02/2016', 'dd/mm/yyyy') dt, 'c' val from dual union all
            select 4 id, to_date('04/01/2016', 'dd/mm/yyyy') dt, 'd' val from dual),
     t2 as (select 1 id, 100 val, to_date('01/12/2015', 'dd/mm/yyyy') dt from dual union all
            select 1 id, 120 val, to_date('12/12/2015', 'dd/mm/yyyy') dt from dual union all
            select 1 id, 130 val, to_date('04/01/2016', 'dd/mm/yyyy') dt from dual union all
            select 2 id, 200 val, to_date('01/03/2016', 'dd/mm/yyyy') dt from dual union all
            select 3 id, 300 val, to_date('04/03/2016', 'dd/mm/yyyy') dt from dual union all
            select 3 id, 330 val, to_date('06/03/2016', 'dd/mm/yyyy') dt from dual)
-- end of mimicking two tables, t1 and t2, containing data. See SQL below:
select id,
       t1_dt,
       t1_val,
       t2_val
from   (select t1.id,
               t1.dt t1_dt,
               t1.val t1_val,
               t2.val t2_val,
               t2.dt t2_dt,
               row_number() over (partition by t1.id order by t2.dt desc) rn
        from   t1
               left outer join (select id,
                                       val,
                                       dt
                                from   t2) t2 on (t1.id = t2.id and t2.dt <= t1.dt))
where  rn = 1;

        ID T1_DT      T1_VAL     T2_VAL
---------- ---------- ------ ----------
         1 01/01/2016 a             120
         2 02/03/2016 b             200
         3 03/02/2016 c                
         4 04/01/2016 d    

示例2(使用标量子查询):

with t1 as (select 1 id, to_date('01/01/2016', 'dd/mm/yyyy') dt, 'a' val from dual union all
            select 2 id, to_date('02/03/2016', 'dd/mm/yyyy') dt, 'b' val from dual union all
            select 3 id, to_date('03/02/2016', 'dd/mm/yyyy') dt, 'c' val from dual union all
            select 4 id, to_date('04/01/2016', 'dd/mm/yyyy') dt, 'd' val from dual),
     t2 as (select 1 id, 100 val, to_date('01/12/2015', 'dd/mm/yyyy') dt from dual union all
            select 1 id, 120 val, to_date('12/12/2015', 'dd/mm/yyyy') dt from dual union all
            select 1 id, 130 val, to_date('04/01/2016', 'dd/mm/yyyy') dt from dual union all
            select 2 id, 200 val, to_date('01/03/2016', 'dd/mm/yyyy') dt from dual union all
            select 3 id, 300 val, to_date('04/03/2016', 'dd/mm/yyyy') dt from dual union all
            select 3 id, 330 val, to_date('06/03/2016', 'dd/mm/yyyy') dt from dual)
-- end of mimicking two tables, t1 and t2, containing data. See SQL below:
select id,
       dt t1_dt,
       val t1_val,
       (select max(val) keep (dense_rank first order by t2.dt desc) max_val
        from   t2
        where  t1.id = t2.id
        and    t2.dt <= t1.dt) t2_val
from   t1;

        ID T1_DT      T1_VAL     T2_VAL
---------- ---------- ------ ----------
         1 01/01/2016 a             120
         2 02/03/2016 b             200
         3 03/02/2016 c                
         4 04/01/2016 d    

N.B。我假设t1.id是唯一的。