2 Replies Latest reply: Dec 13, 2012 6:58 AM by 979475 RSS

    SQLloaderのWHEN句の指定条件に当てはまらないレコードが廃棄される。

    979475
      シェルスクリプトで
      SQLloaderの制御ファイルのWHEN句を利用して移行の要否を判定させています。
      その制御ファイルのWHEN句の判定について質問があります。


      環境:ORACLE11g

      入力データはSQLplusでCSVファイルに

      USER_ID NOT NULL CHAR(8)
      KUBUN NOT NULL CHAR(1)
      DATE NOT NULL
      YAKUSYOKU_ID CHAR(8)

      以上のようなテーブルデータから抽出したものです。

      制御ファイル
      LOAD DATA
        BADFILE 'USER_MASTER.BAD'
        DISCARDFILE 'DELETE.DSC'
        TRUNCATE INTO TABLE USER_MASTER
        WHEN (USER_ID!='DELETE') AND (YAKUSYOKU_ID!='DELETE')
        FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
        (
          USER_ID , 
          KUBUN ,
          DATE       ,
          YAKUSYOKU_ID
        )

      以上のような制御ファイルを使用しております。


      問題になっているのはUSER_IDかYAKUSYOKU_USER_IDのいずれかに’DELETE'と設定されている、
      廃棄ファイルへ出力されるレコードなのですが、実行後に廃棄ファイルを確認すると
      明らかに’DELETE’で指定されていないレコードは廃棄されてしまっています。


      WHEN条件を分割して試したところ、USER_IDについては問題なく’DELETE’と設定されているレコードが廃棄されているのですが、
      YAKUSYOKU_USER_ID側で試したところ、’DELETE’以外に列の値がNULLになっている項目が廃棄されている事がわかりました。
      それ以外のIDが設定されているか、スペースが設定されているレコードに関しては正常にロードされています。


      今回お聞きしたいのは、
      制御ファイルのWHEN句でNULLの取り扱いがどのようになっているのか、
      WHEN句の指定の仕方が間違っているのか、
      NULLが判定されない場合、制御ファイル内での回避方法があるかどうかです。


      御教授、よろしくお願いします。
        • 1. Re: SQLloaderのWHEN句の指定条件に当てはまらないレコードが廃棄される。
          weyk
          なぜ発生するのかは、以下にマニュアルより引用(10 SQL*Loaderフィールド・リスト・リファレンス より)
          -------------
          フィールド条件の指定
          フィールド条件とは、論理レコード中のフィールドに関して、それが真か偽かを評価する条件を記述したものです。フィールド条件は、WHEN句、NULLIF句およびDEFAULTIF句で使用します。

          注意:

          句の評価に使用するフィールドにNULL値が含まれている場合、常に、その句はFALSEと評価されます。この機能を例10-5に示します。
          -------------
          注意によると、どう書いても句(WHEN句)としてはFALSEになるようです。判定されないわけではなく、書かれている仕様通り正しく判定されています。(仕様が、希望(予想)と異なるのはままあることです)
          SQLのNULLの演算ルールに従った場合、等号・不等号と、AND条件しかないなら、たしかにそうなるんですが、ちょっと不便ですね。
          こうなるとちょっと手詰まりという感じです。可能なら事前にロードするデータを加工して評価値がNULLにならないようにすることになりますが、それなら、DELETEの行をフィルタリングする処理を行ってしまったほうがすっきりしそうです。
          (テーブルに登録する値そのものは、評価値がNULL以外でも、NULLIFを用いることでNULLにできるはず)

          あとは、データをそのままとするなら、YAKUSYOKU_IDをチェックせずにロードしてから、'DELETE'の行の処理を行うことになります。

          他の案としては、YAKUSYOKU_ID='DELETE'の行を(SQL式などで)DISCARDではなくBADに行くようにしてしまうのも手ですが、「本当のBADレコード」が埋もれてしまう危険があるので、お勧めはできません。
          • 2. Re: SQLloaderのWHEN句の指定条件に当てはまらないレコードが廃棄される。
            979475
            お返事ありがとうございます。

            リファレンスは目を通していたんですけど、どうやら注意書きを見落としていたようです。
            WHEN句での実現は無理そうなので、提示していただいか案か、他の方法を考えてみます。


            大変ありがとうございました。