Oracle Plus(+)加入ANSI转换

时间:2016-11-02 12:22:25

标签: oracle outer-join ansi

我正处于从Oracle迁移到SQL Datawarehouse Azure的仓库中,并遇到了此查询的问题。

来自Oracle的原始查询 - 它返回1872520行。

SELECT
 *
FROM
 STG_REV_APPORTION_CSC_NO t1,
 STG_SEP_VL t2,
 STG_SEP_VL t3
WHERE
 t3.BUSINESS_DATE(+)    = t1.BUSINESS_DATE
AND t3.CSC_APP_NO(+)     = t1.CSC_APP_NO
AND t3.JOURNEY_NO(+)     = t1.JOURNEY_NO
AND t3.PURSE_TXN_CTR(+)  = t1.PURSE_TXN_CTR
AND t2.BUSINESS_DATE(+) = t1.BUSINESS_DATE
AND t2.CSC_APP_NO(+)    = t1.CSC_APP_NO
AND t2.JOURNEY_NO(+)    = t1.JOURNEY_NO
AND
 (
   t2.TRIP_NO(+) + 1
 )
 = t1.TRIP_NO
AND
 (
   t2.MSG_TYPE_CD(+)  = 13070
 AND t3.MSG_TYPE_CD(+) = 4357
 );

documentation获取线索,我尝试重新写入ANSI:

SELECT COUNT(*) 
 FROM STG_REV_APPORTION_CSC_NO t1
 RIGHT OUTER JOIN STG_SEP_VL t3 ON t3.BUSINESS_DATE = t1.BUSINESS_DATE
 AND t3.CSC_APP_NO     = t1.CSC_APP_NO
 AND t3.JOURNEY_NO     = t1.JOURNEY_NO
 AND t3.PURSE_TXN_CTR  = t1.PURSE_TXN_CTR
 RIGHT OUTER JOIN STG_SEP_VL t2 ON t2.BUSINESS_DATE = t1.BUSINESS_DATE
AND t2.CSC_APP_NO   = t1.CSC_APP_NO
AND t2.JOURNEY_NO    = t1.JOURNEY_NO 
AND (t2.TRIP_NO + 1)  = t1.TRIP_NO
WHERE t2.MSG_TYPE_CD = 13070 AND t3.MSG_TYPE_CD = 4357

返回零行。 ANSI版本应该在oracle实例上运行 - 它也返回零行。

然后我尝试使用toad上的refactor选项将plus join转换为ANSI。我得到以下

SELECT *
  FROM STG_SEP_VL  T2
       RIGHT OUTER JOIN STG_REV_APPORTION_CSC_NO T1
           ON     (T2.BUSINESS_DATE = T1.BUSINESS_DATE)
              AND (T2.CSC_APP_NO = T1.CSC_APP_NO)
              AND (T2.JOURNEY_NO = T1.JOURNEY_NO)
       RIGHT OUTER JOIN STG_SEP_VL T3
           ON     (T3.PURSE_TXN_CTR = T1.PURSE_TXN_CTR)
              AND (T3.BUSINESS_DATE = T1.BUSINESS_DATE)
              AND (T3.CSC_APP_NO = T1.CSC_APP_NO)
              AND (T3.JOURNEY_NO = T1.JOURNEY_NO)
 WHERE     ( ( (T2.TRIP_NO                                             /*(+)*/
                          ) + 1) = T1.TRIP_NO)
       AND ( ( (T2.MSG_TYPE_CD                                         /*(+)*/
                              ) = 13070) AND ( (T3.MSG_TYPE_CD         /*(+)*/
                                                              ) = 4357));

现在,此查询应该在Oracle上运行并返回相同数量的行,然后才能在SQL Server上运行它。但它没有 - 它返回零行。

我查看了这两个查询的解释计划。以下是(+)加入计划的样子: enter image description here

以下是此查询的ANSI版本的外观: enter image description here

我错过了什么吗?

3 个答案:

答案 0 :(得分:3)

以下是我提出的建议:

SELECT *
  FROM stg_rev_apportion_csc_no t1 
  LEFT JOIN stg_sep_vl t3
         ON t1.business_date = t3.business_date AND
            t1.csc_app_no = t3.csc_app_no       AND
            t1.journey_no = t3.journey_no       AND
            t1.purse_txn_ctr = t3.purse_txn_no  AND
            4357 = t3.msg_type_cd
  LEFT JOIN stg_sep_vl t2
         ON t1.business_date = t2.business_date AND
            t1.csc_app_no = t2.csc_app_no       AND
            t1.journey_no = t2.journey_no       AND
            t1.trip_no = t2.trip_no + 1         AND
            13070 = t2.msg_type_cd;

表t2和t3外部连接到t1,因此您要先列出t1并进行左连接,要么首先列出t2和t3并进行右连接。

答案 1 :(得分:2)

如果没有样本数据,很难确定,但我认为where子句应该受到责备。

在where子句中包含t2和t3中的字段会否定外连接的效果,除非您还允许空值(t2.MSG_TYPE_CD = 13070 OR 2.MSG_TYPE_CD IS NULL)。将这些过滤器移动到连接中可以将不匹配的记录放入结果中。

SELECT 
    COUNT(*) 
FROM 
    STG_REV_APPORTION_CSC_NO t1
        RIGHT OUTER JOIN STG_SEP_VL t3      ON  t3.BUSINESS_DATE    = t1.BUSINESS_DATE
                                            AND t3.CSC_APP_NO       = t1.CSC_APP_NO
                                            AND t3.JOURNEY_NO       = t1.JOURNEY_NO
                                            AND t3.PURSE_TXN_CTR    = t1.PURSE_TXN_CTR
                                            AND t3.MSG_TYPE_CD      = 4357
        RIGHT OUTER JOIN STG_SEP_VL t2      ON  t2.BUSINESS_DATE    = t1.BUSINESS_DATE
                                            AND t2.CSC_APP_NO       = t1.CSC_APP_NO
                                            AND t2.JOURNEY_NO       = t1.JOURNEY_NO 
                                            AND (t2.TRIP_NO + 1)    = t1.TRIP_NO
                                            AND t2.MSG_TYPE_CD      = 13070 
;

我并非100%确信此查询是正确的。我怀疑右外连接应该用左外连接替换。这将返回t1中的每条记录,只返回匹配的t2和t3的记录。

答案 2 :(得分:1)

很难找到导致这种不匹配的确切原因,但我认为您已经互换了表STG_SEP_VL中PURSE_TXN_CTR列的连接条件。

SELECT *
FROM STG_REV_APPORTION_CSC_NO t1
RIGHT
JOIN STG_SEP_VL t2
ON  t2.BUSINESS_DATE = t1.BUSINESS_DATE
AND t2.CSC_APP_NO    = t1.CSC_APP_NO
AND t2.JOURNEY_NO    = t1.JOURNEY_NO
AND  ( t2.TRIP_NO + 1 ) = t1.TRIP_NO
RIGHT
JOIN  STG_SEP_VL t3
ON  t3.BUSINESS_DATE    = t1.BUSINESS_DATE
AND t3.CSC_APP_NO     = t1.CSC_APP_NO
AND t3.JOURNEY_NO     = t1.JOURNEY_NO
AND t3.PURSE_TXN_CTR  = t1.PURSE_TXN_CTR
WHERE ( t2.MSG_TYPE_CD  = 13070 AND t3.MSG_TYPE_CD = 4357 );