【问题标题】:How to use for loop in sql developer or oracle如何在sql developer或oracle中使用for循环
【发布时间】:2018-11-29 03:17:48
【问题描述】:

这是我的代码,但是当我运行该项目时,它会显示类似的错误

PLS-00306:调用“TEST_PROCEDURE”时参数的数量或类型错误

我想根据给定的日期插入多条记录。

CREATE OR REPLACE PROCEDURE TEST_PROCEDURE (
   IP_START_DATE           IN     VARCHAR2,
   IP_END_DATE             IN     VARCHAR2,
   IP_MATERIAL_TYPE        IN     VARCHAR2,
   IP_BRM_LIST             IN     VARCHAR2,
   IP_ACTUAL_CONSUMPTION   IN     VARCHAR2,
   IP_YARD_NO              IN     VARCHAR2,
   IP_USER_ID              IN     VARCHAR2,
   IP_USER_IP              IN     VARCHAR2,
   IP_RID                  IN     NUMBER,
   IP_OPERATION            IN     VARCHAR2,
   i                          OUT VARCHAR2,
   OUT_RETURN_MSG             OUT VARCHAR2,
   OUT_RETURN_CODE            OUT NUMBER)
IS
BEGIN
   OUT_RETURN_MSG := '';
   OUT_RETURN_CODE := 0;

   BEGIN
      IF IP_OPERATION = 'INSERT'
      THEN
         FOR i IN IP_START_DATE .. IP_END_DATE
         LOOP
            IF i <= IP_END_DATE
            THEN
               -- exit loop immediately


               INSERT INTO MST_ACTUAL_CONSUMPTION (FROM_DATE,
                                                   TO_DATE,
                                                   MATERIAL_TYPE,
                                                   BRM_TYPE,
                                                   ACTUAL_CONSUMPTION,
                                                   YARD_NO,
                                                   USER_ID,
                                                   USER_IP_ADDRESS,
                                                   CREATED_DATE)
                    VALUES (IP_START_DATE,
                            IP_END_DATE,
                            IP_MATERIAL_TYPE,
                            IP_BRM_LIST,
                            IP_ACTUAL_CONSUMPTION,
                            IP_YARD_NO,
                            IP_USER_ID,
                            IP_USER_IP,
                            SYSDATE);

               EXIT;
            END IF;
         END LOOP;
      END IF;

      IF IP_OPERATION = 'UPDATE'
      THEN
         UPDATE MST_ACTUAL_CONSUMPTION
            SET FROM_DATE = IP_START_DATE,
                TO_DATE = IP_END_DATE,
                MATERIAL_TYPE = IP_MATERIAL_TYPE,
                BRM_TYPE = IP_BRM_LIST,
                ACTUAL_CONSUMPTION = IP_ACTUAL_CONSUMPTION,
                YARD_NO = IP_YARD_NO,
                LAST_UPD_TS = SYSDATE,
                LAST_UPD_UID = IP_USER_ID
          WHERE RID = IP_RID;
      -- AND VESSEL_NAME  = IP_VESSEL_NAME;
      END IF;

      OUT_RETURN_CODE := 1;
      OUT_RETURN_MSG := 'SUCCESS';
   EXCEPTION
      WHEN OTHERS
      THEN
         OUT_RETURN_CODE := 0;
         OUT_RETURN_MSG := SQLERRM;
   END;
END TEST_PROCEDURE;

【问题讨论】:

  • 我想根据给定的开始和结束日期插入多条记录。
  • 对于 ex:start_date=01-06-2018 和 edn_date=05-06-2018,数据条目应具有 01-06-2018 至 05-06-2018 其平均总计 5 条记录应该是插入
  • 错误描述表明您对 TEST_PROCEDURE 的调用不正确。请提供您用于此过程调用的语句。
  • 请检查我的回答并接受它是否对您有帮助或为给定的解决方案提供相关反馈(cmets)。请阅读:stackoverflow.com/help/someone-answers 了解为什么它很重要。

标签: asp.net oracle stored-procedures


【解决方案1】:
create or replace PROCEDURE PROC_ADD_ACTUALCONSUMPTION (
 IP_START_DATE       IN  VARCHAR2,
    IP_END_DATE           IN VARCHAR2,
    IP_MATERIAL_TYPE       IN VARCHAR2,
    IP_BRM_LIST           IN VARCHAR2,
    IP_ACTUAL_CONSUMPTION       IN VARCHAR2,
     IP_YARD_NO       IN VARCHAR2,
    IP_USER_ID                   IN VARCHAR2,
    IP_USER_IP                   IN VARCHAR2,
     IP_RID           IN NUMBER ,
     IP_OPERATION      IN VARCHAR2,
   --S_DATE OUT DATE,
   --E_DATE OUT DATE,
   --datediff OUT NUMBER, 
    OUT_RETURN_MSG OUT VARCHAR2,
    OUT_RETURN_CODE OUT NUMBER)



IS
BEGIN
  OUT_RETURN_MSG  := '';
  OUT_RETURN_CODE := 0;

 -- S_DATE :=TO_DATE(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS');
  --  E_DATE :=TO_DATE(IP_END_DATE,'DD-MM-YYYY HH24:MI:SS');
   -- datediff :=E_DATE-E_DATE;

  BEGIN

IF IP_OPERATION  = 'INSERT' THEN




    INSERT INTO MST_ACTUAL_CONSUMPTION
      (

      FROM_DATE,
      TO_DATE,
      MATERIAL_TYPE,
      BRM_TYPE,
      ACTUAL_CONSUMPTION,
      YARD_NO,
      USER_ID,
      USER_IP_ADDRESS,
      CREATED_DATE

      )


  select 
      TO_CHAR((to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS')+ (level-1)),'DD-MM-YYYY') ,
       TO_CHAR(to_date(IP_END_DATE,'DD-MM-YYYY HH24:MI:SS'),'DD-MM-YYYY') ,
       IP_MATERIAL_TYPE,
        IP_BRM_LIST,
        IP_ACTUAL_CONSUMPTION,
        IP_YARD_NO,
        IP_USER_ID,
        IP_USER_IP,
        SYSDATE
         FROM
        dual
        CONNECT BY
        level <= to_date(IP_END_DATE,'DD-MM-YYYY HH24:MI:SS')-to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS')+1;

  --  to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS'):=to_date(IP_START_DATE,'DD-MM-YYYY HH24:MI:SS')+1;

       END IF;
            END PROC_ADD_ACTUALCONSUMPTION;

【讨论】:

    【解决方案2】:

    你不能循环访问日期,你可以做这样的事情。

    create or replace procedure testproc(
    startdate in date,
    enddate in date
    )
    as
    datediff NUMBER := enddate-startdate;
    newdate date := startdate;
    begin
    
       FOR i IN 1..datediff LOOP
       newdate := newdate+1;
       insert into temp values(newdate);
       END LOOP;
    end;
    

    对于您的错误,这是因为您错误地传递了参数,例如传递参数需要整数值的字符串,或者您传递的参数数量不正确。

    【讨论】:

    • 这可能是一个正确的解决方案,但请记住,循环内的插入总是比单个插入效率低
    【解决方案3】:

    首先,您不应该将varchar2 数据类型用于日期数据类型。这是自找麻烦。

    现在,由于您要为多个日期插入记录,因此您不能像在 for i in 1..10 中那样对日期使用 for 循环迭代器。

    因此,您可以使用connect by 作为生成日期的方法。使用LEVEL伪列引用当前迭代(for循环中的i)

    INSERT INTO mst_actual_consumption (
        from_date,
        TO_DATE,  -- don't use this as a column_name as it's a function
        material_type,
        brm_type,
        actual_consumption,
        yard_no,
        user_id,
        user_ip_address,
        created_date
    )
        SELECT
            ip_start_date, -- you need to use to_date if you are passing date as strings
            ip_end_date,
            ip_material_type,
            ip_brm_list,
            ip_actual_consumption,
            ip_yard_no,
            ip_user_id,
            ip_user_ip,
            SYSDATE
        FROM
            dual
        CONNECT BY
            level <= ( ip_end_date - ip_start_date ); -- you need to use to_date if you are passing date as strings
    

    这部分我没看懂

     IF i <= IP_END_DATE
                THEN
                   -- exit loop immediately
    

    也许你正在尝试这个?如果是的话,放在插入和更新之前

    IF ip_end_date <= ip_start_date 
    THEN
      RETURN;
    END IF;
    

    编辑你说:

    错误已修复,但即使有一次也没有记录插入

    这可能是因为您没有传递正确的日期。正如我在代码 cmets 中所说,您应该使用 to_date 函数将它们转换为日期。 例如:如果您以 dd-mm-yyyy 格式将日期作为字符串传递,则在插入时,您应该使用

    level <= ( to_date(ip_end_date,'dd-mm-yyyy') - to_date(ip_start_date,'dd-mm-yyyy') )
    

    如果表MST_ACTUAL_CONSUMPTION 中的列是日期数据类型,则在插入的选择部分必须执行相同的操作。

    select to_date(ip_start_date,'dd-mm-yyyy'), to_date(ip_end_date,'dd-mm-yyyy')
    

    【讨论】:

    • 是的,在这种情况下结束日期大于开始日期
    • 仍然出现 PLS-00306 之类的错误:调用“TEST_PROCEDURE”ORA-06550 时参数的数量或类型错误:第 1 行,第 7 列:当我尝试从我的项目中插入数据时跨度>
    • @prudhvini :该错误不是因为插入语句。您传递了一些不正确的论点。编辑您的问题并显示您调用该过程的准确程度。带有exec proc1('a','b',1); 形式的样本也就是说,您需要向我们展示您传递给过程的所有值。否则,我们将不知道“您的项目”在做什么
    • :我准确地发布了我所做的程序。然而这还不够
    • @prudhvini:你还没有理解我的问题。我想让你进入 asp.net 代码(我从你的标签中知道),看看程序是如何被调用的,传递了什么参数等等。
    【解决方案4】:

    您需要选择开始和结束之间的天数并将其用作循环计数器,而不是像现在一样尝试直接使用变量。即使您传递的 varchar2 中包含日期,为了安全起见,我仍然会截断转换后的变量以保证整数。

    select trunc(to_date(ip_end_date)) - trunc(to_date(ip_start_date))
    into loop_count
    from dual;
    

    将您的循环更改为按此计数

    if loop_count > 0 then
       FOR i IN 1..loop_count loop
    

    我假设您可能想要更改循环的每次迭代的日期以匹配开始和结束之间的日期。

    【讨论】:

    • 实际上 m 从我的项目中传递变量,如果我像你一样将值在此使用,请选择 trunc(to_date(ip_end_date)) - trunc(to_date(ip_start_date)) 从 dual 到 loop_count;然后它以有效的标识符 rit 显示
    猜你喜欢
    • 2022-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-11
    相关资源
    最近更新 更多