【问题标题】:Is the below use of outer join correct as the data doesn't fetch correctly由于数据未正确获取,以下外部联接的使用是否正确
【发布时间】:2016-03-22 09:42:12
【问题描述】:

您好,我在表格中有以下数据 Exsiting data 通过下面的查询,我只得到普通的优惠券 Output

但是我还需要没有具有相应 -ve 的凭证的行(它基本上是出售的凭证和兑换的凭证。)

因此,仅售出和兑换了 1 张优惠券,还有一张尚未兑换。 如何恢复尚未赎回的行。

SELECT t1.STORE,
       t1.DAY,
       t1.tran_seq_no,
       t2.tran_seq_no,
       t2.DAY,
       t1.tender_amt,
       t2.tender_amt,
       t1.voucher_no,
       t2.voucher_no 
FROM   sa_tran_tender t1,
       sa_tran_tender t2
where  t1.voucher_no(+)=t2.voucher_no
AND    t1.DAY=4
AND    t1.tender_amt<0
AND    t1.tender_type_group ='VOUCH' 
AND    t2.tender_amt>0
AND    t1.STORE=400112
AND    t1.tran_seq_no       IN(2632729010,2632729056,3140772029)
AND    t1.STORE(+)=t2.STORE
and    t1.tender_type_group(+)=t2.tender_type_group;

【问题讨论】:

  • 现代的LEFT/RIGHT JOIN 语法(对大多数人来说)更清晰,更不容易出错,不妨试试?
  • 也许决定一个大写/小写策略并坚持下去。上面的代码让我偏头痛;)
  • Oracle 建议停止使用(+) 运算符并改用显式LEFT JOIN

标签: sql oracle join inner-join outer-join


【解决方案1】:

当您使用 oracle joun 语法时,您应该将(+) 添加到左连接表的WHERE 条件中的每个字段(不仅适用于与另一个表连接的字段) -

where  t1.voucher_no(+)=t2.voucher_no
AND    t1.DAY=4(+)
AND    t1.tender_amt(+)<0
AND    t1.tender_type_group(+) ='VOUCH' 
AND    t2.tender_amt>0
AND    t1.STORE(+)=400112
AND    t1.tran_seq_no(+) IN(2632729010,2632729056,3140772029)
AND    t1.STORE(+)=t2.STORE
and    t1.tender_type_group(+)=t2.tender_type_group

或者您可以使用 ANSI 连接。

【讨论】:

    【解决方案2】:

    假设将有单次代金券销售(带有负数tender_amt),然后是单次可选的代金券兑换(正数tender_amt 和后来的tran_seq_no),那么您不需要使用自加入;相反,您可以使用LAGLEAD 分析函数(与自连接的两个表扫描相比,只需要一个表扫描):

    SQL Fiddle

    Oracle 11g R2 架构设置

    CREATE TABLE sa_tran_tender ( store, day, tran_seq_no, voucher_no, tender_amt, tender_type_group ) AS
    SELECT 400112, 4, 2632729010, '400112*101*21090', -39.95, 'VOUCH' FROM DUAL UNION ALL
    SELECT 400112, 4, 2632729056, '400112*101*21136',  -6.99, 'VOUCH' FROM DUAL UNION ALL
    SELECT 400112, 5, 3140772029, '400112*101*21090',  39.95, 'VOUCH' FROM DUAL;
    

    查询 1

    SELECT *
    FROM   (
      SELECT t.*,
             LEAD( DAY )         OVER ( PARTITION BY voucher_no, store, tender_type_group ORDER BY tran_seq_no ) AS redeemed_day,
             LEAD( tender_amt )  OVER ( PARTITION BY voucher_no, store, tender_type_group ORDER BY tran_seq_no ) AS redeemed_amt,
             LEAD( tran_seq_no ) OVER ( PARTITION BY voucher_no, store, tender_type_group ORDER BY tran_seq_no ) AS redeemed_tran_seq_no
      FROM   sa_tran_tender t
    )
    WHERE  tran_seq_no       IN( 2632729010, 2632729056, 3140772029)
    AND    tender_type_group ='VOUCH' 
    AND    STORE             =400112
    AND    DAY               =4
    

    Results

    |  STORE | DAY | TRAN_SEQ_NO |       VOUCHER_NO | TENDER_AMT | TENDER_TYPE_GROUP | REDEEMED_DAY | REDEEMED_AMT | REDEEMED_TRAN_SEQ_NO |
    |--------|-----|-------------|------------------|------------|-------------------|--------------|--------------|----------------------|
    | 400112 |   4 |  2632729010 | 400112*101*21090 |     -39.95 |             VOUCH |            5 |        39.95 |           3140772029 |
    | 400112 |   4 |  2632729056 | 400112*101*21136 |      -6.99 |             VOUCH |       (null) |       (null) |               (null) |
    

    但是,如果您确实想使用(低效)自联接,那么您可以这样做:

    SELECT t1.STORE,
           t1.DAY,
           t1.tran_seq_no,
           t2.tran_seq_no,
           t2.DAY,
           t1.tender_amt,
           t2.tender_amt,
           t1.voucher_no,
           t2.voucher_no 
    FROM   sa_tran_tender t1
           LEFT OUTER JOIN
           sa_tran_tender t2
           ON (    t1.voucher_no        = t2.voucher_no
               AND t2.tender_amt        > 0
               AND t1.store             = t2.store
               AND t1.tender_type_group = t2.tender_type_group )
    WHERE  t1.DAY               = 4
    AND    t1.tender_amt        < 0
    AND    t1.tender_type_group = 'VOUCH' 
    AND    t1.STORE             = 400112
    AND    t1.tran_seq_no       IN (2632729010,2632729056,3140772029);
    

    【讨论】:

    • 嗨@MT0,非常感谢您提供上述方法。第二个工作完美。而上述使用LEAD功能的方法,不显示兑换凭证等详细信息。所有其他列(redeemed_day,redeemed_amt,redeemed_tran_seq_no)对于这两个凭证都是空的,而它必须是空的,只有一个没有被兑换的......
    猜你喜欢
    • 2021-11-28
    • 1970-01-01
    • 2018-08-18
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多