【问题标题】:Outer Joins with Multiple Conditions in Oracle Join SyntaxOracle 联接语法中具有多个条件的外部联接
【发布时间】:2020-10-25 05:14:31
【问题描述】:

我有下面的表格

create table xx_base_tbl
(
    tbl_id      number
,   trx_num     varchar2(100)
);


create table xx_dtl_tbl
(
    dtl_id      number
,   tbl_id      number
,   category    varchar2(100)
,   attribute1  varchar2(100)
);

insert into xx_base_tbl (tbl_id, trx_num) values (1, 'trx 1');
insert into xx_base_tbl (tbl_id, trx_num) values (2, 'trx 2');
insert into xx_base_tbl (tbl_id, trx_num) values (3, 'trx 3');
insert into xx_base_tbl (tbl_id, trx_num) values (4, 'trx 4');
insert into xx_base_tbl (tbl_id, trx_num) values (5, 'trx 5');

insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (1, 1, null, 'SAMPLE');
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (2, 1, null, 'hello');
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (3, 2, 'PREPAYMENT', 'this is not a value');
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (4, 2, 'PREPAYMENT', 1);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (5, 3, 'PREPAYMENT', 2);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (6, 3, 'PREPAYMENT', 1);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (7, 3, 'SAMPLE', 15678);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (8, 4, 'PREPAYMENT', 1);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (9, 4, 'PREPAYMENT', NULL);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (10, 5, 'PREPAYMENT', null);
insert into xx_dtl_tbl (dtl_id, tbl_id, category, attribute1) values (11, 5, 'SAMPLE', 'YEY');

我正在使用下面的 ANSI 语法将 xx_dtl_tbl 外连接到另一个 xx_base_tbl 仅显示具有 PREPAYMENT 和数值的 CATEGORY。然后使用LISTAGG() 将结果聚合到一行中

SELECT
    xx1.trx_num,
    LISTAGG(xx3.trx_num, ',') WITHIN GROUP(
        ORDER BY
            xx3.trx_num
    ) prepayment
FROM
         xx_base_tbl xx1
    INNER JOIN xx_dtl_tbl   xx2 ON xx1.tbl_id = xx2.tbl_id
    LEFT JOIN xx_base_tbl  xx3 ON (to_number(xx2.attribute1) = xx3.tbl_id and length(TRIM(translate(xx2.attribute1, ' +-.0123456789', ' '))) IS NULL)    
GROUP BY
    xx1.trx_num

结果看起来不错:

TRX_NUM     PREPAYMENT
-------     -------------
trx 1   
trx 2       trx 1
trx 3       trx 1,trx 2
trx 4       trx 1
trx 5   

但是,当我使用SQL Developer's tool to change the syntax to Oracle Join Syntax 时,会得到以下结果:

SELECT
    xx1.trx_num,
    LISTAGG(xx3.trx_num, ',') WITHIN GROUP(
        ORDER BY
            xx3.trx_num
    ) prepayment
FROM
    xx_base_tbl  xx1,
    xx_dtl_tbl   xx2,
    xx_base_tbl  xx3
WHERE
        xx1.tbl_id = xx2.tbl_id
    AND to_number(xx2.attribute1) = xx3.tbl_id (+)
    AND ( length(TRIM(translate(xx2.attribute1, ' +-.0123456789', ' '))) IS NULL )
GROUP BY
    xx1.trx_num
    

结果变了:

TRX_NUM     PREPAYMENT
-------     -------------
trx 2       trx 1
trx 3       trx 1,trx 2
trx 4       trx 1
trx 5   

trx 1 行突然丢失。如何在 Oracle 语法中编写此代码?

【问题讨论】:

    标签: sql oracle join left-join oracle-sqldeveloper


    【解决方案1】:

    这个查询不是那么容易转换为旧语法。对我有用的是:

    select a.trx_num,
           listagg(b.trx_num, ',') within group (order by b.trx_num) prepayment 
      from (
    
        select trx_num, attribute1, 
               case when trim(translate(xx2.attribute1, ' +-.0123456789', ' ')) is null 
                    then to_number(xx2.attribute1) 
               end attr_num
        from xx_base_tbl xx1, xx_dtl_tbl xx2 
        where xx1.tbl_id = xx2.tbl_id) a, 
      
        xx_base_tbl b
      
      where a.attr_num = b.tbl_id (+)
      group by a.trx_num
    

    dbfiddle

    两个步骤,首先在子查询中使用case when创建连接列,然后在主查询中使用它。

    编辑:

    上面的查询可以简化为:

    select xx1.trx_num,  
           listagg(xx3.trx_num, ',') within group (order by xx3.trx_num) prepayment
    from xx_base_tbl xx1, xx_dtl_tbl xx2, xx_base_tbl xx3
    where xx1.tbl_id = xx2.tbl_id
      and case when trim(translate(xx2.attribute1, ' +-.0123456789', ' ')) is null 
                then to_number(xx2.attribute1) 
           end = xx3.tbl_id(+)
    group by xx1.trx_num
    

    dbfiddle

    【讨论】:

      【解决方案2】:

      在您的第一个查询中使用的语法是 ANSI 标准连接,并且可以与 oracle 一起正常工作。

      第二个查询的语法是旧的 SQL-92 标准,应该避免使用。此外,它很难理解和处理。

      顺便说一句,您的第二个查询将需要一些额外的子句,如下所示:

      WHERE
          xx1.tbl_id = xx2.tbl_id
          AND to_number(xx2.attribute1) = xx3.tbl_id (+)
          AND (xx3.tbl_id is null -- this extra OR condition is needed with below condition
               or ( length(TRIM(translate(xx2.attribute1, ' +-.0123456789', ' '))) IS NULL )
              ) 
      

      【讨论】:

      • 嗨,是的,我知道它在 Oracle 中工作,但我需要它在 Oracle 语法中,因为我正在制作一个物化视图 (stackoverflow.com/questions/52303492/…)
      • 抱歉,您的建议无效:ORA-01719: outer join operator (+) not allowed in operand of OR or IN 01719. 00000 - "outer join operator (+) not allowed in operand of OR or IN" *Cause: An outer join appears in an or clause. *Action: If A and B are predicates, to get the effect of (A(+) or B), try (select where (A(+) and not B)) union all (select where (B)). Error at Line: 14 Column: 23
      • 查看答案,我已删除 (+)。现在检查
      猜你喜欢
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-07
      • 1970-01-01
      • 2015-04-08
      • 2020-06-26
      • 2015-01-03
      相关资源
      最近更新 更多