2017-07-27 130 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;