无法使用oracle中的游标在表中插入记录

Posted

技术标签:

【中文标题】无法使用oracle中的游标在表中插入记录【英文标题】:Not able to insert the records in table using cursor in oracle 【发布时间】:2020-04-16 17:34:08 【问题描述】:

我想使用cursor 将记录插入到表中。所以下面是相同的查询。

CREATE OR REPLACE PROCEDURE FIBER_TRANSM_VALID_DATA 
AS 

BEGIN

DECLARE

SPANID NVARCHAR2(50);
MZONENAME NVARCHAR2(50);


CURSOR CR_SPAN_VALID_DATA IS

 SELECT RJ_SPAN_ID, RJ_MAINTENANCE_ZONE_NAME
        FROM APP_FTTX.transmedia@SAT
        WHERE  LENGTH(RJ_SPAN_ID) = 21
       AND INVENTORY_STATUS_CODE = 'IPL'
       AND REGEXP_LIKE(rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
       AND RJ_MAINTENANCE_ZONE_CODE IN ('INMUNVMB01')
       AND ROWNUM < 11;  


BEGIN      
    OPEN CR_SPAN_VALID_DATA;
    LOOP    
    FETCH CR_SPAN_VALID_DATA INTO SPANID, MZONENAME;
    EXIT WHEN CR_SPAN_VALID_DATA%NOTFOUND;    

    IF SPANID > 0
    THEN
        BEGIN                              
            INSERT INTO TBL_FIBER_VALID_TRANS_DATA (RJ_SPAN_ID, RJ_MAINTENANCE_ZONE_NAME)
            VALUES (SPANID, MZONENAME);           

        END;
       END IF; 
          COMMIT;

       END LOOP;  
  CLOSE CR_SPAN_VALID_DATA;  

END;
END FIBER_TRANSM_VALID_DATA;

但我收到错误

错误(36,13): PL/SQL: SQL 语句被忽略 错误(36,65):PL/SQL:ORA-00904:“RJ_MAINTENANCE_ZONE_NAME”:标识符无效

更新

表结构如下

SPAN_ID                       NVARCHAR2(50)  
MAINTENANCE_ZONE_NAME         NVARCHAR2(50)  
MAINTENANCE_ZONE_CODE         NVARCHAR2(50)  
R4G_STATE_NAME                NVARCHAR2(50)  
STATE_NAME                    NVARCHAR2(50)  
NETWORK_CATEGORY              NVARCHAR2(100) 
NETWORK_TYPE                  NVARCHAR2(100) 
CONSTRUCTION_METHODOLOGY      NVARCHAR2(50)  
INVENTORY_STATUS_CODE         NVARCHAR2(20)  
OWNERSHIP_TYPE_CODE           NVARCHAR2(20)  
ROUTE_NAME                    NVARCHAR2(100) 
INTRACITY_LINK_ID             NVARCHAR2(100) 
CALCULATED_LENGTH             NUMBER(38,8)   
LAST_UPDATED_BY               NVARCHAR2(100) 
LAST_UPDATED_DATE             DATE 

【问题讨论】:

当 SQL> desc TBL_FIBER_VALID_TRANS_DATA 发出时你会得到什么。 @BarbarosÖzhan:表格的结构,由其他几列组成 我的意思是表中是否包含名为RJ_MAINTENANCE_ZONE_NAME的列,您确定表中存在该列吗? @BarbarosÖzhan 让我再次检查并在此处发布表结构 @BarbarosÖzhan:很抱歉这是我的专栏错误 【参考方案1】:

如果它必须是游标循环,请参见另一种方法 - 游标FOR 循环。它更容易编写和维护,因为 Oracle 为您做了大部分事情,即您不必显式声明游标和游标变量,打开它,从中获取,注意何时退出循环,关闭光标。所有肮脏的工作都是为你完成的。

您所要担心的是,您编写的select 实际上返回了一些行,因为我已经看到您写的评论 - 尽管过程已编译,但它没有插入任何行。由于我们没有您的数据,因此我们无能为力。

给你(假设表和列确实存在):

create or replace procedure fiber_transm_valid_data as 
begin
  for cur_r in (select rj_span_id, 
                       rj_maintenance_zone_name
                from app_fttx.transmedia@sat
                where length(rj_span_id) = 21
                  and inventory_status_code = 'IPL'
                  and regexp_like(rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
                  and rj_maintenance_zone_code in ('INMUNVMB01')
               )
  loop               
    if cur_r.rj_span_id > '0' then
       insert into tbl_fiber_valid_trans_data 
         (span_id, maintenance_zone_name)
       values (cur_r.rj_span_id, cur_r.rj_maintenance_zone_name);
    end if;
  end loop;  
end fiber_transm_valid_data;

还有一些注意事项:不要在循环中使用COMMIT,因为它会导致问题(例如 snapshot too old 错误)。考虑将其完全移出过程,让调用者决定是否提交。

你真的执行了这个过程吗?您确实创建了它,但是 - 如果您从未调用过它,这可能是您看不到插入任何行的原因。所以:

begin
  fiber_transm_valid_data ;
end;
/

【讨论】:

感谢 littlefoot 的回答。我一定会尝试您的代码并测试它是否相应地工作。给我一些时间,我会相应地更新你 我在运行它时遇到了这个错误ORA-06502: PL/SQL: numeric or value error: character to number conversion error ORA-06512: at "APP_FIBERINV.FIBER_TRANSM_VALID_DATA", line 12 ORA-06512: at line 2 是因为这行:if cur_r.rj_span_id &gt; 0 。 RJ_SPAN_ID 似乎是 VARCHAR2(字符串),因此您无法将其与 0(零,数字)进行比较。将其修改为 if cur_r.rj_span_id &gt; '0' (将 0 括在单引号中)可修复 this 错误,但是 - 我不知道这是否是您真正想要做的事情。 是的,这就是原因,现在错误消失了,所以在运行后我测试了表,仍然没有插入记录,我应该删除那个 if 条件并检查吗? 确保select返回任何结果吗?【参考方案2】:

您的整个 PL/SQL 代码可以用简单的INSERT INTO..SELECT 编写。无需遍历游标中的每条记录,只需在普通 SQL 中执行即可:

INSERT INTO TBL_FIBER_VALID_TRANS_DATA 
  (SPAN_ID, MAINTENANCE_ZONE_NAME)
SELECT RJ_SPAN_ID, RJ_MAINTENANCE_ZONE_NAME
FROM APP_FTTX.transmedia@SAT
WHERE  LENGTH(RJ_SPAN_ID) = 21
AND INVENTORY_STATUS_CODE = 'IPL'
AND REGEXP_LIKE(rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
AND RJ_MAINTENANCE_ZONE_CODE IN ('INMUNVMB01')
AND ROWNUM < 11
AND SPAN_ID > 0; --> This is the check you are using in your PL/SQL code

AND ROWNUM

我希望您知道ROWNUM 只会为您提供它获取的随机行,除非您特别提及ORDER BY,否则它不会按任何特定顺序排列,然后在其上应用rownum。在您的代码中,您将获得10 随机行。要了解更多信息,请参阅How ROWNUM works。

【讨论】:

感谢 lalit 的回答,但我想用光标来做,可以吗?我快完成了。我想是因为当我删除 ROWNUM 部分时,你回答的方式花费了太多时间 @nkb SQL 总是比 PL/SQL 快。如果您仍想使用游标在 PL/SQL 中逐行执行,也就是逐行缓慢,请使用 FORALL 语句查看 BULK COLLECT。关于ROWNUM,看我给的链接。

以上是关于无法使用oracle中的游标在表中插入记录的主要内容,如果未能解决你的问题,请参考以下文章

在 oracle 中使用游标插入和更新记录

无法使用 Liquibase 中的序列在表中插入值

oracle 执行存储过程 无法中断 但是是循环执行 怎么办

在表中找不到给定记录时如何处理游标中的异常

使用 C# 出现错误“无法在表中插入标识列的显式值”

Oracle 12c - 使用另一个表中的值在表中插入值