2016-04-06 9 views
0

私は配列をループして挿入/更新を実行しています。ループでは、レコードが存在するかどうかを確認します。そうでない場合は、挿入を実行します。存在する場合は、更新を実行します。 STRING_SPLIT_FNCは、文字列をデリミタ(〜)で分割し、分割した文字列を配列に格納するパッケージです。配列内のOracleクエリ - 奇妙な結果

DECLARE 

service_name VARCHAR(50) := 'Service1'; 
service_version VARCHAR(10) := '2016'; 
i INTEGER; 
record_count NUMBER; 
TYPE T_ARRAY_OF_VARCHAR IS TABLE OF VARCHAR(2000) INDEX BY BINARY_INTEGER; 
main_array T_ARRAY_OF_VARCHAR; 
split_array STRING_SPLIT_FNC.T_ARRAY; 

BEGIN 
    main_array(1) := '2014|2015|2016|~service.info~25500~NULL~1'; 
    main_array(2) := '2014|2015|2016|2017~service.path~/mypath/myfolder/myfile.zip~0'; 
    main_array(3) := '2014|2015|2016|2017|2018~service.date~Yes~NULL~1'; 

    SELECT COUNT(SERVICE_ID) INTO record_count FROM TEST_SERVICE WHERE SERVICE_DESC = service_name AND SERVICE_VERSION = service_version; 
    IF record_count = 0 THEN 
     INSERT INTO TEST_SERVICE(SERVICE_ID, SERVICE_DESC, SERVICE_VERSION) VALUES (SERVICE_SEQ.nextval, service_name, service_version); 
    END IF; 

SELECT SERVICE_ID INTO service_id FROM TEST_SERVICE WHERE SERVICE_DESC = service_name AND SERVICE_VERSION = service_version; 


    i := main_array.FIRST; 
    LOOP 
     record_count := 0; 
     split_array := STRING_SPLIT_FNC.SPLIT(main_array(i),'~'); 
     IF (INSTR(split_array(1), service_version) > 0) THEN 
      DBMS_OUTPUT.PUT_LINE('Record count prior: ' || record_count || ' Service Id: ' || service_id || ' Config: ' || split_array(2)); 
      SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2);  
      DBMS_OUTPUT.PUT_LINE('Record count after: ' || record_count || ' Service Id: ' || service_id || ' Config: ' || split_array(2)); 
      IF record_count = 0 THEN   
       INSERT INTO TEST_REF_SERVICE_CONFIG (REF_CONFIG_ID, SERVICE_ID, CONFIG_NAME, DEFAULT_VALUE, ALLOW_OVERRIDE) VALUES (REF_SERVICE_CONFIG_SEQ.nextval, service_id, split_array(2), split_array(3), TO_NUMBER(split_array(5))); 
       DBMS_OUTPUT.PUT_LINE('Inserted Service: ' || service_name || '[' || service_version || '], Config: ' || split_array(2) || ' [' || split_array(3) || '], Override: ' || split_array(5)); 
      ELSE 
       record_count := 0; 
       SELECT COUNT(REF_CONFIG_ID) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2) AND DEFAULT_VALUE = split_array(3); 
       IF record_count = 0 THEN 
        DBMS_OUTPUT.PUT_LINE('Record count after [in update part]: ' || record_count); 
        UPDATE TEST_REF_SERVICE_CONFIG SET DEFAULT_VALUE = split_array(3), ALLOW_OVERRIDE = split_array(5) WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2) AND DEFAULT_VALUE = split_array(3); 
        DBMS_OUTPUT.PUT_LINE('Updated Service: ' || service_name || '[' || service_version || '], Config: ' || split_array(2) || ' [' || split_array(3) || '], Override: ' || split_array(5)); 
       ELSE 
        record_count := 0; 
        DBMS_OUTPUT.PUT_LINE('No insert or update performed. Service: ' || service_name || '[' || service_version || '], Config: ' || split_array(2) || ' [' || split_array(3) || '], Override: ' || split_array(5)); 
       END IF; 
      END IF; 
     ELSE 
      DBMS_OUTPUT.PUT_LINE('Specified service/version not found ' || service_name || '[' || service_version || ']'); 
     END IF; 
     i := main_array.NEXT(i); 

     EXIT WHEN i IS NULL; 
    END LOOP; 
    END; 

TEST_REF_SERVICE_CONFIGテーブルにレコードがないものとします。 ここでは、service_name = Service1とservice_version = 2015に対してこれを実行します。service_idは500です。main_arrayの3つの要素がすべて挿入されます。

ここでは、service_name = Service1とservice_version = 2017のために実行します。サービスIDは502です。main_arrayの最後の2レコードだけを挿入する必要があります。

それが0であるべきときに戻り、以下のクエリは= 1をRECORD_COUNT:

SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = split_array(2);  

私は別にクエリを実行すると、私はクエリがあるのはなぜ

SELECT COUNT(*) FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = 502 AND CONFIG_NAME = 'service.path'; 

0としてカウントを取得0にする必要があるときにカウントを1に戻すループ?私も試した:

今私は121としてrecord_countを得る! ご協力いただきありがとうございます。

+0

あなたが投稿したコードには、service_idという名前のPL/SQL変数がないので、 'SELECT SERVICE_ID INTO service_id ...'は失敗します。あなたが投稿したコードからそれを除外しましたか?おそらくあなたが見ているものを引き起こしているかもしれません... –

答えて

2

ここで起こっていることは、テーブルの列と同じ名前の変数を選択したためです。

クエリの変数を参照する場合は、その前にa:を付ける必要があります。だから、代わりにこのようにすることの :

  SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = config_name; 

あなたはこのように実行する必要があります。

  SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = :service_id AND CONFIG_NAME = :config_name; 

またはいっそのは、あなたのコードを読みやすくするために、あなたの変数やカラム名に異なる命名規則を使用します。

:接頭辞を省略すると、Oracleはこれを "SERVICE_ID列の値がSERVICE_ID列の値と等しいすべてのレコードに渡します..."と解釈します。これはすべてのレコードに適用されます。

+2

私は 'service_id'はローカルPL/SQL変数ではなく、バインド変数であると考えられますが、投稿された宣言セクションには表示されません。もしそうなら、結腸は正しくない。他の変数の名前はそれをサポートするかもしれませんが、私は間違っているかもしれません。名前を変更することはこれを解決する方法です。 –

+0

ありがとうございました!これは終わりまで私をイライラしていた。今日何かを学んだ。私は変数名を前にv_で変更しましたが、今はうまくいきます! – user1100221

+2

@ user1100221 - [列名の優先順位](http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/nameresolution.htm#LNPLS2038)とそのマニュアルの残りの部分も参照してください。 –

1

エイリアシングの問題が考えられます。

WHERE **SERVICE_ID = service_id** AND CONFIG_NAME = split_array(2);  

これを修正する方法は、変数名を列名と異なるように変更することです。これがPL/SQLプロシージャまたはファンクションの場合は、変数名の前にプロシージャまたはファンクションの名前を付けることができますが、無名ブロックではできません。

+1

接頭辞* which * 'service_id'?どちらも現在は列名として認識されているため、テーブル名で修飾することで違いはありません。名前付きPL/SQLブロック(つまりストアド・プロシージャ)では、ローカル変数の意味を示すために、ブロック名の1つに接頭辞を付けることができます。または[ブロックラベルを使用する](http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/nameresolution.htm#BABGGJJG)を実行することもできます。または、衝突を避けるために変数名を変更してください。いくつかの人々は資格を使うことを好む。 –

+0

あなたはかなり正しい、良いキャッチです。正しい情報を反映するために私の答えを修正しました。 – Jrmde

+0

匿名ブロックにもラベルを付けることができます(前のコメントのリンクにリンクされています)が、現実世界で行われたことを今まで見たことがあるかどうかはわかりません。 –