2017-07-27 129 views
0

目前我正在學習PLSQL,使用Oracle。我正在嘗試獲取比另一個表中的參數日期更早的數據。我希望程序獲取所有數據,檢查一些記錄是否比param_value中的參數早(recv_date),並且如果是,則要啓動我的警報程序。我在聲明一個CURSOR和ln_pallets_container時遇到了問題。我知道我可以以某種方式進入ln_pallets數據只有在recv_date我已經過濾,但在這裏,我不知道如何正確地做到這一點。也許我應該在過程之前聲明光標,而不是在它之內?PLSQL Oracle遊標程序

procedure CHECK_STOCK_DATE(warehouse_id_in IN warehouse.warehouse_id%TYPE) 
IS 
ln_pallet_count NUMBER; 
ln_days_till_expiration param_value.param_value%TYPE; 

CURSOR ln_pallets IS 
     SELECT container_id, recv_date 
     FROM wms_stock ws 

ln_pallets_container%ROWTYPE; 


BEGIN 

     OPEN ln_pallets; 
      LOOP 
       FETCH ln_pallets INTO ln_pallets_container; 
       EXIT WHEN ln_pallets%NOTFOUND; 

       SELECT param_value.param_value 
       INTO ln_days_till_expiration 
       FROM param_value 
       WHERE param_value.parameter_id = 266; 

        IF(ln_pallets_container.recv_date >= trunc(sysdate - ln_days_till_expiration) 

         ALARM.ALARM(WAREHOUSE_ID =>MY_COMMONS.GET_WHRS_ID, 
SOURCE_TEXT => ln_pallets_container.container_id, 
MESSAGE_CODE => 'Cannot find this container on warehouse. Check container code.'); 
        END IF; 
      END LOOP; 
     CLOSE ln_pallets; 
END; 

回答

1

有幾件事情你的代碼錯誤,我已經固定,並在下面突出顯示:

PROCEDURE check_stock_date(warehouse_id_in IN warehouse.warehouse_id%TYPE) IS 
    ln_pallet_count   NUMBER; 
    ln_days_till_expiration param_value.param_value%TYPE; 

    CURSOR ln_pallets IS 
    SELECT container_id, 
      recv_date 
    FROM wms_stock ws; -- added semicolon 

    ln_pallets_container ln_pallets%ROWTYPE; -- amended to set the datatype of the variable to be the cursor rowtype 

BEGIN 

    OPEN ln_pallets; 
    LOOP 
    FETCH ln_pallets 
     INTO ln_pallets_container; 
    EXIT WHEN ln_pallets%NOTFOUND; 

    SELECT param_value.param_value 
    INTO ln_days_till_expiration 
    FROM param_value 
    WHERE param_value.parameter_id = 266; 

    IF /*removed bracket*/ ln_pallets_container.recv_date >= trunc(SYSDATE - ln_days_till_expiration) 
    THEN --added 

     alarm.alarm(warehouse_id => my_commons.get_whrs_id, 
        source_text => ln_pallets_container.container_id, 
        message_code => 'Cannot find this container on warehouse. Check container code.'); 
    END IF; 
    END LOOP; 
    CLOSE ln_pallets; 
END check_stock_date; 

然而,這可以更有效地完成。目前,您正在遍歷wms_stock中的所有行,並且您正在明確地打開,提取並關閉遊標。

這意味着對於wms_stock中的每一行,您都可以找到parameter_id 266的值(我假設您在循環播放結果時不會改變!),以及檢查是否可以運行你的報警程序。

而不是獲取所有的行,爲什麼不移動檢查到遊標 - 這樣,你只會獲取參數266值一次,並篩選出任何不需要運行警報程序的行。

與此同時,爲什麼不切換到使用循環遊標?這樣,您就不必擔心打開/關閉/關閉遊標,因爲Oracle會爲您處理所有這些問題。

這樣做,這將導致在更短的代碼,這恰好是更有效和更容易閱讀和維護,就像這樣:

PROCEDURE check_stock_date(warehouse_id_in IN warehouse.warehouse_id%TYPE) IS 
BEGIN 
    FOR ln_pallets_rec IN (SELECT container_id, 
           recv_date 
         FROM wms_stock ws 
         WHERE recv_date >= (SELECT trunc(SYSDATE - param_value.param_value 
               FROM param_value 
               WHERE param_value.parameter_id = 266)) 
    LOOP 
    alarm.alarm(warehouse_id => my_commons.get_whrs_id, 
       source_text => ln_pallets_rec.container_id, 
       message_code => 'Cannot find this container on warehouse. Check container code.'); 
    END LOOP; 

END check_stock_date; 
+0

看起來方式更好!正如你所說容易維護,但我有幾個問題。 我不需要在這裏聲明任何東西?你只是使用了一些var ln_pallets_rec。稍後在LOOP中,source_text是我們想要使用的ln_pallets_rec.container_id,我不應該告訴哪種類型是ln_pallets_rec? –

+0

[cursor-for-loop](https://docs.oracle.com/cloud/latest/db112/LNPLS/cursor_for_loop_statement.htm#LNPLS1155)的美妙之處在於Oracle會處理記錄聲明(有點像是什麼時候你在1..10循環中做'我...'你不必聲明i變量)加上光標處理。我更新了我的答案,以引用循環內正確的記錄名稱。值得注意的是,你可以顯式聲明遊標,然後在for中引用遊標名稱,如下所示:'declare cursor my_cur as ...;在my_cur循環中開始my_rec ...,如果你想的話。 – Boneist

+0

此外,隱式定義在cursor-for-loop中的記錄範圍純粹是循環的,因此如果需要在循環外部引用它(例如,出於錯誤日誌記錄目的),則需要將其存儲到變量中你有預先定義的,例如'聲明my_var數字;開始for my_rec in(select ....)循環my_var:= my_rec.num_col; .... end loop;當其他人異常log_error(my_var);' – Boneist

0

嗨,你沒有爲ln_pallets_container變量也是它缺少指定表名「;」遊標聲明修復後,並嘗試

1

修復了代碼中的一些問題。

procedure check_stock_date(warehouse_id_in in warehouse.warehouse_id%type) is 

     ln_pallet_count   number; 
     ln_days_till_expiration param_value.param_value%type; 

     l_container_id wms_stock.container_id%type; 
     l_recv_date wms_stock.recv_date%type; 

     cursor ln_pallets is 
      select container_id 
       ,recv_date 
      from wms_stock ws; 

    begin 

     open ln_pallets; 

     loop 
      fetch ln_pallets 
      into l_container_id 
       ,l_recv_date; 

      exit when ln_pallets%notfound; 

      select param_value.param_value 
      into ln_days_till_expiration 
      from param_value 
      where param_value.parameter_id = 266; 

      if l_recv_date >= trunc(sysdate - ln_days_till_expiration) 
      then 
      alarm.alarm(warehouse_id => my_commons.get_whrs_id 
         ,source_text => l_container_id 
         ,message_code => 'Cannot find this container on warehouse. Check container code.'); 
      end if; 
     end loop; 
     close ln_pallets; 
    end;