2016-04-06 57 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條記錄。

下面返回查詢record_count = 1時,它應該是0:

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

當我單獨運行查詢,我得到計數​​爲0

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

爲什麼查詢中當它應該是0時,循環返回計數爲1?我也試過:

DECLARE 
config_name VARCHAR(250); 
... 
LOOP 
      record_count := 0; 
      split_array := STRING_SPLIT_FNC.SPLIT(main_array(i),'~'); 
      IF (INSTR(split_array(1), service_version) > 0) THEN 
       config_name := split_array(3); 
       SELECT COUNT(*) INTO record_count FROM TEST_REF_SERVICE_CONFIG WHERE SERVICE_ID = service_id AND CONFIG_NAME = config_name; 

現在我得到record_count爲121 !!! 在此先感謝您的幫助。

+0

您發佈的代碼沒有名爲'service_id'的PL/SQL變量,因此'SELECT SERVICE_ID INTO service_id ...'會失敗;你剛剛離開你發佈的代碼嗎?讓局部變量名稱與表列相同將導致您的問題,但可能會導致你所看到的... –

回答

2

我認爲這裏發生的事情是由於你選擇變量的同名作爲表中的列。

當你在你的查詢中引用一個變量時,你應該用一個:符號作爲前綴。 所以,與其做這樣的:

  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

前綴*哪個*'service_id'?兩者都被視爲目前的專欄名稱,因此符合表名的條件不會有任何區別。在一個命名的PL/SQL塊(即一個存儲過程)中,你可以用塊名前綴其中之一來顯示你的意思是本地變量。或者你可以[使用塊標記](http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/nameresolution.htm#BABGGJJG)。或者改變變量名稱以避免衝突;有些人更喜歡使用資格。 –

+0

你很對,很好。我修改了我的答案以反映正確的信息。 – Jrmde

+0

你也可以標記一個匿名塊(我與之前的評論中的鏈接),但我不確定我是否見過在現實世界中完成的。 –