2012-09-18 28 views
0

我已經尋找了一段時間來解決這個問題,並且我找到的所有NO_DATA_FOUND處理教程都只顯示瞭如何在只有一列的Select Into時執行此操作變量。使用Select Into MULTIPLE變量處理異常處理

首先,這裏是我的代碼:

BEGIN 
    OPEN c_no_source; 
    LOOP 
     DECLARE 
      l_price_code VARCHAR2(20) := ''; 
      l_price_level VARCHAR(10) := ''; 
      l_code_date DATE := p_effective_date; 
     BEGIN 
      FETCH c_no_source INTO c_no_source_row; 
       exit WHEN c_no_source%NOTFOUND; 
      BEGIN 
       WITH codeList AS /* liste des dates ayant une donnée avant la date effective incluse. */ 
       (
        SELECT distinct 
         NVL(effective_date,p_effective_date) as effective_date, 
         NVL(user_group2,'') as price_code, 
         NVL(user_group3,'') as price_level 
        FROM DGA_Service.Hjvsecmaster_Hist 
        WHERE effective_date <= p_effective_date 
         AND user_group2 IS NOT NULL 
         AND security_alias = c_no_source_row.security_alias 
        ORDER BY 1 DESC 
       ) 
       SELECT price_code, price_level, effective_date 
       INTO l_price_code, l_price_level, l_code_date 
       FROM codelist 
       WHERE ROWNUM = 1; 
       EXCEPTION WHEN no_data_found THEN NULL; 

       ... 
       [UPDATE statement using the variables] 
       ... 
      END; 
     END; 
    END LOOP; 

    CLOSE c_no_source; 
END; 

我想要做的就是把我的設置爲三個不同的變量codeList臨時結果的頂部1的結果。 然而,codeList中的三列中的一列往往是NULL。我的3個變量都不會被設置。 我試圖處理異常,但我無法讓我的代碼插入有值的列到它們各自的變量中。如果即使其中一列爲NULL,也不會將它們插入到它們的變量中。

我想選擇進入語句來設置它可以設置的變量。

我試圖單獨處理它們全部使用這樣的事情:

EXCEPTION WHEN NO_DATA_FOUND THEN 
    BEGIN 
     IF price_code IS NOT NULL THEN l_price_code := price_code; END IF; 
     IF price_level IS NOT NULL THEN l_price_level := price_level; END IF; 
     IF effective_date IS NOT NULL THEN l_code_date := effective_date; END IF; 
    END; 

,但我得到了以下錯誤消息:

ORA-06550: line 294, column 18: 
PLS-00201: identifier 'PRICE_CODE' must be declared 
ORA-06550: line 294, column 15: 
PL/SQL: Statement ignored 
ORA-06550: line 295, column 18: 
PLS-00201: identifier 'PRICE_LEVEL' must be declared 
ORA-06550: line 295, column 15: 
PL/SQL: Statement ignored 
ORA-06550: line 296, column 18: 
PLS-00201: identifier 'EFFECTIVE_DATE' must be declared 
ORA-06550: line 296, column 15: 
PL/SQL: Statement ignored 

所以我跑出的想法。我試圖指定臨時表名稱,無濟於事,像這樣:

IF codeList.price_code IS NOT NULL 

我想在這個問題上的任何幫助。這段代碼運行的包已經很重了,我不希望每個列都帶有單獨的With ... As() Select Into子句。

+0

@在第一個原始代碼塊中,如果拋出異常,我執行NULL。最常見的情況是'codeList'表有5到10行,但每行都有3列NULL中的一列。 我認爲這是'NO_DATA_FOUND'錯誤,因爲當我剛剛使用'EXCEPTION WHEN no_data_found THEN NULL;'我的3個變量都沒有設置,即使其中2個應該已經設置。我可能會誤解,在這種情況下,我不知道爲什麼我的變量沒有設置具有值的列。 – EplusL

+0

我只想找到一種方法來抓取循環中的每一行,並設置任何我有價值的變量,然後用''設置其他變量。 – EplusL

回答

2

好吧,我想我找到你了;大部分問題是由於您錯誤地嵌套PL/SQL塊導致的。

您的更新語句包含在EXCEPTION塊中,這意味着只有在拋出異常時纔會執行它。其次,你引用直接在以下幾點:

EXCEPTION WHEN NO_DATA_FOUND THEN 
    BEGIN 
     IF price_code IS NOT NULL THEN l_price_code := price_code; END IF; 
     IF price_level IS NOT NULL THEN l_price_level := price_level; END IF; 
     IF effective_date IS NOT NULL THEN l_code_date := effective_date; END IF; 
    END; 

這是你的編譯錯誤的原因。

最後,如果您的select into中有單行,那麼變量將被設置,因此沒有必要嘗試解決這個問題。

BEGIN 
    OPEN c_no_source; 
    LOOP 
     DECLARE 
      l_price_code VARCHAR2(20); 
      l_price_level VARCHAR(10); 
      l_code_date DATE := p_effective_date; 
     BEGIN 
      FETCH c_no_source INTO c_no_source_row; 
       exit WHEN c_no_source%NOTFOUND; 
      BEGIN 
       WITH codelist AS (
       SELECT DISTINCT effective_date 
         , user_group2 AS price_code 
         , user_group3 AS price_level 
        FROM hjvsecmaster_hist 
        WHERE effective_date <= p_effective_date 
        AND user_group2 IS NOT NULL 
        AND security_alias = c_no_source_row.security_alias 
        ORDER BY 1 DESC 
       ) 
       SELECT price_code, price_level, effective_date 
       INTO l_price_code, l_price_level, l_code_date 
       FROM codelist 
       WHERE ROWNUM = 1; 
       EXCEPTION WHEN no_data_found THEN 
        -- All variables are their initial setting 
        null; 
      END; 
      ... 
       [UPDATE statement using the variables] 
      ... 
     END; 
    END LOOP; 

    CLOSE c_no_source; 
END; 

這樣做通常是非常低效的方式。如果你可以將所有東西放入一個UPDATE或MERGE那麼我會這麼做。你似乎沒有任何額外的邏輯,所以它應該是可能的。

+0

完美,謝謝。我是一個忘記從異常塊中取出UPDATE語句的笨手笨腳的人。是的,我只是設置EXCEPTION處理做'NULL',一切都很好。 – EplusL

+0

如何將所有這些內容整合到更新聲明中?我正在研究使用MERGE的解決方案。 – EplusL

+0

@EplusL,我不確定:-)。我沒有你原來的光標選擇或你的更新聲明。如果你用全部3發佈一個新問題,我確信有人可能會幫助! – Ben

1

然而這三個中的一個將經常爲NULL,並觸發 NO_DATA_FOUND錯誤,沒有我的3個變量的將被設置在查詢不返回任何

NO_DATA_FOUND上升。它與列值無關。他們都可能是空的,聲明會成功。

EXCEPTION WHEN NO_DATA_FOUND THEN 
    BEGIN 
     IF price_code IS NOT NULL THEN l_price_code := price_code; END IF; 
     IF price_level IS NOT NULL THEN l_price_level := price_level; END IF; 
     IF effective_date IS NOT NULL THEN l_code_date := effective_date; END IF; 
    END; 

您的變量前綴「L_」和你正在使用的列名在比較eg.price_code,因此錯誤。 更重要的是,NO_DATA_FOUND意味着所有的變量值都是空的,所以這個異常塊什麼都不做。

所有你可能需要的是這個。

,如果你不希望插入空值對於給定的ID(如果所有都爲空)

BEGIN 
    insert into target_table (id, col1, col2, col3) 
    select id, col1, col2, col3 
    from (target_table) 
    where not (col1 is null and col2 is null and col3 is null); 
    commit; 
end; 
/

如果有一個給定id沒有數據,沒有插入。如果其中至少有一個不爲空,則插入這些值。