繁体   English   中英

ORA-08103在过程中使用全局临时表DML(插入,更新,选择),将光标选择到temp-table显示错误对象不存在

[英]ORA-08103 Using global temporary table DML(insert, update, select) inside a procedure, select cursor to temp-table shows error object doesn't exists

基本上,我需要修改数据并将其存储在临时表中,每次在暴露数据后执行该过程时都删除数据。 问题是过程结果在游标中使用的临时表显示错误

对象不存在

我正在尝试从具有存储过程的全局临时表中获取数据,然后截断存储过程中的数据。 我从Oracle数据库中收到“不再存在”错误,我尝试了3种不同的方法:

  1. 带有ON COMMIT DELETE ROWS;临时表ON COMMIT DELETE ROWS; 声明,并COMMIT; 在程序结束时。

  2. 带有ON COMMIT PRESERVE ROWS;临时表ON COMMIT PRESERVE ROWS; 语句和过程末尾的TRUNCATE TABLE

  3. 在过程结束时带有EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_NAME'语句的常规表

所有这些选项都显示相同的错误。

我有2个表,我正在合并这2个表,以更改记录的某些值。

然后,我创建一个游标以将SELECT返回到临时表。

错误出现在这里。

因此,我创建了以下表格:

CREATE GLOBAL TEMPORARY TABLE REM_ORDENSECCIONES_TPM (
    SE_CONSEC   NUMBER(38,0),
    SE_NOMBRE   VARCHAR2(250 BYTE),
    ET_CONSEC   NUMBER(38,0),
    SE_ORDENS   NUMBER(38,0),
    DI_CONSEC   NUMBER(38,0)
)
ON COMMIT DELETE ROWS;
--
CREATE GLOBAL TEMPORARY TABLE REM_ORDENSECCIONES (
    SE_CONSEC   NUMBER(38,0),
    SE_NOMBRE   VARCHAR2(250 BYTE),
    ET_CONSEC   NUMBER(38,0),
    SE_ORDENS   NUMBER(38,0),
    DI_CONSEC   NUMBER(38,0)
)
ON COMMIT PRESERVE ROWS;
--
CREATE TABLE REM_ORDENSECCIONESP (
    SE_CONSEC   NUMBER(38,0),
    SE_NOMBRE   VARCHAR2(250 BYTE),
    ET_CONSEC   NUMBER(38,0),
    SE_ORDENS   NUMBER(38,0),
    DI_CONSEC   NUMBER(38,0)
)

我有这个存储过程:

CREATE OR REPLACE PROCEDURE SP_OBTENER_SECCION_AMBULATORIO(etConsec NUMBER DEFAULT NULL,
                                                    diConsec NUMBER DEFAULT NULL,
                                                    cursorParam OUT SYS_REFCURSOR)
AS
BEGIN
    --
    -- SE TRAEN TODAS LAS SECCIONES QUE ESTÁN EN PREGEVEN Y LAS QUE COINCIDAN
    -- CON LA ETAPA Y EL DIAGNÓSTICO EN SECCPREG
    -- SE GUARDAN EN LA TABLA TEMPORAL PARA PODER MODIFICAR EL ORDEN MÁS ADELANTE.

    --DEBUG
    -- SELECT * FROM REM_ORDENSECCIONES_TPM;
    -- SELECT * FROM REM_SECCPREG WHERE SE_CONSEC = 217;
    -- UPDATE REM_PREGEVEN SET SE_ORDEN = 11 WHERE SE_CONSEC = 217;
    INSERT INTO REM_ORDENSECCIONESP (SE_CONSEC, SE_NOMBRE, ET_CONSEC, SE_ORDENS)
        SELECT SE_CONSEC, SE_NOMBRE, ET_CONSEC, SE_ORDENS
        FROM REM_SECCPREG  
        WHERE SE_CONSEC IN 
                        (SELECT DISTINCT SE_CONSEC
                         FROM REM_PREGEVEN 
                         WHERE ET_CONSEC = etConsec AND DI_CONSEC = diConsec AND PR_ESTADO <> 'I') 
        OR ET_CONSEC = etConsec and Di_Consec = diConsec
        ORDER BY SE_ORDENS;
    --        
    -- ACTUALIZA LA TABLA TEMPORAL DE LAS SECCIONES CON EL SE_ORDEN
    -- DE LA TABLA DE REM_PREGEVEN.
    --

    --DEBUG
    -- SELECT * FROM REM_ORDENSECCIONES_TPM;
    -- COMMIT;
    UPDATE REM_ORDENSECCIONESP TMP
        SET TMP.SE_ORDENS = (SELECT DISTINCT PREGE.SE_ORDEN 
                             FROM REM_PREGEVEN PREGE 
                             WHERE ET_CONSEC = etConsec AND DI_CONSEC = diConsec AND PR_ESTADO <> 'I'
                             AND TMP.SE_CONSEC = PREGE.SE_CONSEC)
    WHERE EXISTS (SELECT 1
                    FROM REM_PREGEVEN PREGE
                    WHERE TMP.SE_CONSEC = PREGE.SE_CONSEC AND SE_ORDEN IS NOT NULL);

 OPEN cursorParam FOR 
  SELECT SE_CONSEC, SE_NOMBRE, ET_CONSEC FROM REM_ORDENSECCIONESP;
--COMMIT; --COMMIT NECESARIO PARA ELIMINAR LOS DATOS TEMPORALES


  EXECUTE IMMEDIATE 'TRUNCATE TABLE REM_ORDENSECCIONESP';-- || TBL_NAME;
END;

有什么建议吗? 我没有其他尝试的途径。

我不是Oracle专家,我在SQL Server中使用了临时表,一切都很好。

谢谢! :)

SQL Server中的临时表与Oracle中的全局临时表不同。 具体来说,全局临时表是永久数据结构,只是临时数据。 GTT中的数据仅限于插入该数据的会话,并将在事务或会话结束时擦除,具体取决于表的定义方式。

关于过程的另一件事是,它将过程打开的引用游标传递给调用程序。 游标不是数据集,而是指向查询的指针 :调用程序然后获取数据,这意味着它执行查询并处理其结果集。 问题是,打开查询后,您的过程EXECUTE IMMEDIATE 'TRUNCATE TABLE REM_ORDENSECCIONESP';执行EXECUTE IMMEDIATE 'TRUNCATE TABLE REM_ORDENSECCIONESP'; 因此,当调用程序尝试从游标中获取记录时,橱柜是空的。

删除truncate table语句。 它正在破坏您的流程。 GTT的问题之一是,发布DDL比使用普通表更麻烦:例如,如果有任何使用它的会话仍处于打开状态,则我们不能删除GTT。 幸运的是,考虑到全局临时表的行为,几乎肯定不需要截断。 如果您确实认为需要某些东西,只需在流程开始时将其delete from GTTdelete from GTT 在您重新填充之前,这将清除会话中较早的所有残留数据(事务?)。

这是db <> fiddle上的演示。

如果创建了这些表,那么您就可以访问它们(以及模式中的过程)。 另一方面,该过程使用其他一些表-您可以访问它们吗? 看看我运行您的代码时会发生什么:

正在创建表:

SQL> CREATE GLOBAL TEMPORARY TABLE REM_ORDENSECCIONES_TPM (
  2      SE_CONSEC   NUMBER(38,0),
  3      SE_NOMBRE   VARCHAR2(250 BYTE),
  4      ET_CONSEC   NUMBER(38,0),
  5      SE_ORDENS   NUMBER(38,0),
  6      DI_CONSEC   NUMBER(38,0)
  7  )
  8  ON COMMIT DELETE ROWS;

Table created.

SQL> --
SQL> CREATE GLOBAL TEMPORARY TABLE REM_ORDENSECCIONES (
  2      SE_CONSEC   NUMBER(38,0),
  3      SE_NOMBRE   VARCHAR2(250 BYTE),
  4      ET_CONSEC   NUMBER(38,0),
  5      SE_ORDENS   NUMBER(38,0),
  6      DI_CONSEC   NUMBER(38,0)
  7  )
  8  ON COMMIT PRESERVE ROWS;

Table created.

SQL> --
SQL> CREATE TABLE REM_ORDENSECCIONESP (
  2      SE_CONSEC   NUMBER(38,0),
  3      SE_NOMBRE   VARCHAR2(250 BYTE),
  4      ET_CONSEC   NUMBER(38,0),
  5      SE_ORDENS   NUMBER(38,0),
  6      DI_CONSEC   NUMBER(38,0)
  7  );

Table created.

该过程已创建,但有一些警告:

SQL> CREATE OR REPLACE PROCEDURE SP_OBTENER_SECCION_AMBULATORIO(etConsec NUMBER DEFAULT NULL,
  2                                                      diConsec NUMBER DEFAULT NULL,
  3                                                      cursorParam OUT SYS_REFCURSOR)
  4  AS
  5  BEGIN
  6      --
  7      -- SE TRAEN TODAS LAS SECCIONES QUE ESTÁN EN PREGEVEN Y LAS QUE COINCIDAN
  8      -- CON LA ETAPA Y EL DIAGNÓSTICO EN SECCPREG
  9      -- SE GUARDAN EN LA TABLA TEMPORAL PARA PODER MODIFICAR EL ORDEN MÁS ADELANTE.
 10
 11      --DEBUG
 12      -- SELECT * FROM REM_ORDENSECCIONES_TPM;
 13      -- SELECT * FROM REM_SECCPREG WHERE SE_CONSEC = 217;
 14      -- UPDATE REM_PREGEVEN SET SE_ORDEN = 11 WHERE SE_CONSEC = 217;
 15      INSERT INTO REM_ORDENSECCIONESP (SE_CONSEC, SE_NOMBRE, ET_CONSEC, SE_ORDENS)
 16          SELECT SE_CONSEC, SE_NOMBRE, ET_CONSEC, SE_ORDENS
 17          FROM REM_SECCPREG
 18          WHERE SE_CONSEC IN
 19                          (SELECT DISTINCT SE_CONSEC
 20                           FROM REM_PREGEVEN
 21                           WHERE ET_CONSEC = etConsec AND DI_CONSEC = diConsec AND PR_ESTADO <> 'I')
 22          OR ET_CONSEC = etConsec and Di_Consec = diConsec
 23          ORDER BY SE_ORDENS;
 24      --
 25      -- ACTUALIZA LA TABLA TEMPORAL DE LAS SECCIONES CON EL SE_ORDEN
 26      -- DE LA TABLA DE REM_PREGEVEN.
 27      --
 28
 29      --DEBUG
 30      -- SELECT * FROM REM_ORDENSECCIONES_TPM;
 31      -- COMMIT;
 32      UPDATE REM_ORDENSECCIONESP TMP
 33          SET TMP.SE_ORDENS = (SELECT DISTINCT PREGE.SE_ORDEN
 34                               FROM REM_PREGEVEN PREGE
 35                               WHERE ET_CONSEC = etConsec AND DI_CONSEC = diConsec AND PR_ESTADO <> 'I'
 36                               AND TMP.SE_CONSEC = PREGE.SE_CONSEC)
 37      WHERE EXISTS (SELECT 1
 38                      FROM REM_PREGEVEN PREGE
 39                      WHERE TMP.SE_CONSEC = PREGE.SE_CONSEC AND SE_ORDEN IS NOT NULL);
 40
 41   OPEN cursorParam FOR
 42    SELECT SE_CONSEC, SE_NOMBRE, ET_CONSEC FROM REM_ORDENSECCIONESP;
 43  --COMMIT; --COMMIT NECESARIO PARA ELIMINAR LOS DATOS TEMPORALES
 44
 45
 46    EXECUTE IMMEDIATE 'TRUNCATE TABLE REM_ORDENSECCIONESP';-- || TBL_NAME;
 47  END;
 48  /

Warning: Procedure created with compilation errors.

那么,这怎么了?

SQL> show err
Errors for PROCEDURE SP_OBTENER_SECCION_AMBULATORIO:

LINE/COL ERROR
-------- -----------------------------------------------------------------
15/5     PL/SQL: SQL Statement ignored
17/14    PL/SQL: ORA-00942: table or view does not exist
32/5     PL/SQL: SQL Statement ignored
34/35    PL/SQL: ORA-00942: table or view does not exist

啊哈; 第17和34行中引用的表不存在(或者我无法访问它们):

17          FROM REM_SECCPREG
34                               FROM REM_PREGEVEN PREGE

那么,它们是否存在于您的架构中? 如果没有,别人是否拥有它们? 如果是这样,则该用户(所有者)应授予您SELECT特权(直接而不是通过角色),然后您应在这些表名之前添加所有者名称(例如scott.rem_seccpreg ),或在自己的模式中创建同义词。

看看上面写的内容是否有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM