Sql Oracle联接语法中具有多个条件的外部联接

Sql Oracle联接语法中具有多个条件的外部联接,sql,oracle,join,left-join,oracle-sqldeveloper,Sql,Oracle,Join,Left Join,Oracle Sqldeveloper,我有下面的表格 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_t

我有下面的表格

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仅显示预付款和数字值的类别。然后使用
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   
但是,当我使用时,它会得到以下结果:

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语法编写此代码?

第一个查询中使用的语法是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 )
        ) 

这个查询很难转换为旧语法。对我起作用的是:

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

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

编辑:

上述查询可简化为:

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

您好,我知道它在Oracle中工作,但我需要Oracle语法中的它,因为我正在生成物化视图()对不起,您的建议不起作用:
ORA-01719:在或的操作数或01719中不允许使用外部联接运算符(+)。00000-“*的或的操作数中不允许使用外部联接运算符(+)原因:外部联接出现在OR子句中*操作:如果A和B是谓词,要获得(A(+)或B)的效果,请尝试(选择where(A(+),而不是B))union all(选择where(B))。第14行第23列出错参见答案,我已删除(+)。现在检查