过程中的 PLSQL Oracle 游标

PLSQL Oracle Cursor in procedure

目前我正在学习PLSQL,使用Oracle。我正在尝试获取比在另一个 table 中贴标的 PARAM 天数更早的数据。我希望程序获取所有数据,检查某些记录是否比 param_value 中的参数更旧 (recv_date),如果是,则触发我的警报程序。我在声明 CURSOR 和 ln_pallets_container 时遇到问题。我知道我只能以某种方式进入 ln_pallets 数据,其中 recv_date 我已经过滤了,但我不知道如何正确地做到这一点。也许我应该在程序之前而不是在程序内部声明游标?

  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;

您好,您没有为 ln_pallets_container 变量指定 table 名称,它还缺少一个“;”游标声明后修复此问题并尝试

修复了代码中的一些问题。

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;

您的代码有几处错误,我已修复并在下面突出显示:

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 值并过滤掉不需要警报过程的任何行运行.

同时,为什么不改用游标循环呢?这样,您就不必担心 opening/fetching from/closing 游标,因为 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;