2016-11-02 10 views
2

OracleからSQL Datawarehouse Azureへのウェアハウス移行の途中で、この問合せの問題が発生しました。Oracle Plus(+)がANSI変換に結合

Oracleの元のクエリ - それは1872520の行を返します。 documentationから手がかりを取る

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 
); 

、私は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のリファクタリングオプションを使用して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

私は何かが欠け午前:ここ enter image description here

は、このクエリのANSIバージョンはどのように見えるかですか?

+4

すべての '(+)'条件は、 'ON'節で書かなければなりません!この問合せにはWHERE句は必要ありません。 'RIGHT JOIN STG_SEP_VL t2 ON ... AND t2.MSG_TYPE_CD = 13070'。 ORは 'where':' 'WHERE(t2.MSG_TYPE_CD = 13070 OR t2.MSG_TYPE_CD IS NULL/*(t2に存在しない行について)* /' – Mike

+3

で、これは恐ろしいです。場所が間違っているのは残念ですが、あなたがいれば申し訳ありません。どこにエラーがあるのか​​わかりませんが、AND(t2.TRIP_NO + 1)= t1なので、あなたのクエリはToadリファクタリングされたものよりも正確です。 TRIP_NO'はWHERE節ではなくON節になければなりません。これはa(+)を持つすべてのものに対して有効です。私はあなたの場所で何をしたらいいですか:元のクエリを書き直して、1つのテーブルだけを使用し、次に2つ、次に3を書き直します。そして、1と2と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と正しい参加をしてください。

+0

恐ろしい!この問合せでは、Oracle上の行数が正確になりました。これは、SQL Server上でさらに多くの結果をもたらしました。私はその問題を今すぐデバッグします:) –

+1

@RKKuppala - したがって、明確にする:マイク(元の質問の最初のコメント)には、不一致の正しい理由がありました。元のクエリからの外部結合条件「t2.MSG_TYPE_CD(+)= 13070」は、「外部結合」および(+)のない「WHERE」条件に置き換えることはできません。あなたが行を持たない理由は、すべての結合が計算され、WHERE条件が適用された後だけです。そして今、WHERE条件は実際にそのハードコード化された値を必要とするので、(または 't3'の他のもの)外部結合のすべての行を拒否します。 DCookieのソリューションはそれを回避します。 – mathguy

+0

ありがとう、@ mathguy私は今、あなたの説明が役立つことを理解しました。 –

2

サンプルデータがないと確信が持てませんが、where節は責任があると思います。

ヌル(t2.MSG_TYPE_CD = 13070 OR 2.MSG_TYPE_CD IS NULL)も許可しない限り、where句にt2とt3のフィールドを含めて外部結合の効果を無効にします。これらのフィルタをジョインに移動すると、一致しないレコードが結果に反映されます。

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 
; 

このクエリが正しいと確信しているわけではありません。 I 容疑者右外側の結合は、左側の外側結合で置き換える必要があります。これは、t1からのすべてのレコードと、一致するt2とt3からのレコードのみを返します。

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); 
関連する問題