ORA-08103 在过程中使用全局临时 table DML(insert, update, select), select cursor to 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
基本上我需要修改数据并将其存储在临时文件中table,在公开数据后每次执行过程时删除数据。问题是作为过程结果在游标中使用的临时 table 显示错误
object doesn't exist
我正在尝试使用存储过程从全局临时 table 获取数据,然后截断存储过程中的数据。我从 Oracle 数据库收到 "no longer exists" 错误,我尝试了 3 种不同的方法:
带有 ON COMMIT DELETE ROWS;
语句的临时 table,并且 COMMIT;
在过程结束时。
带有 ON COMMIT PRESERVE ROWS;
语句的临时 table,并且 TRUNCATE TABLE
在过程结束时
常规 table,过程结束时带有 EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_NAME'
语句
所有这些选项都显示相同的错误。
我有 2 个 table,我正在将这 2 个 table 合并到全局临时 table 中,更改记录的一些值。
然后我正在创建一个游标到return一个SELECT
到临时table。
出现错误时就在这里
因此,我创建了以下 tables:
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 服务器上使用了临时 tables,一切都很好。
谢谢! :)
如果您创建了这些 table,那么您就可以访问它们(以及您架构中的过程)。另一方面,该过程使用其他一些 tables - 你能访问它们吗?看看当我 运行 你的代码时会发生什么:
正在创建表:
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
啊哈; table第 17 行和第 34 行中引用的内容不存在(或者我无法访问它们):
17 FROM REM_SECCPREG
34 FROM REM_PREGEVEN PREGE
那么,它们是否存在于您的架构中?如果没有,其他人是否拥有它们?如果是这样,该用户(所有者)应该授予您 SELECT
权限(直接,而不是通过角色),然后您应该在那些 table 名称之前加上所有者名称(例如 scott.rem_seccpreg
),或在您自己的架构中创建同义词。
看看上面写的是否有帮助。
SQL 服务器中的临时 Table 不同于 Oracle 中的全局临时 Table。具体来说,Global Temporary Table 是 permanent 数据结构,它只是临时数据。 GTT 中的数据仅限于插入它的会话,并将在事务或会话结束时被擦除,具体取决于 table 的定义方式。
关于您的过程的另一件事是它将打开的引用游标传递给调用程序。游标不是数据集,它是查询的指针:调用程序然后获取数据,这意味着它执行查询并处理其结果集。问题是,在打开查询后,您的过程立即执行 EXECUTE IMMEDIATE 'TRUNCATE TABLE REM_ORDENSECCIONESP';
。因此,当调用程序试图从游标中获取记录时,橱柜是空的。
删除 truncate table
语句。它正在破坏你的过程。 GTT 的问题之一是发布 DDL 比正常的 tables 更麻烦:例如,如果有任何使用它的会话仍然打开,我们就不能删除 GTT。幸运的是,鉴于全局临时 tables 的行为,截断几乎肯定是不必要的。如果您真的认为自己需要什么,只需在流程开始时 delete from GTT
;这将在您重新填充之前清除会话早期的任何挥之不去的数据(交易?)。
这是 db<>fiddle 上的演示。
基本上我需要修改数据并将其存储在临时文件中table,在公开数据后每次执行过程时删除数据。问题是作为过程结果在游标中使用的临时 table 显示错误
object doesn't exist
我正在尝试使用存储过程从全局临时 table 获取数据,然后截断存储过程中的数据。我从 Oracle 数据库收到 "no longer exists" 错误,我尝试了 3 种不同的方法:
带有
ON COMMIT DELETE ROWS;
语句的临时 table,并且COMMIT;
在过程结束时。带有
ON COMMIT PRESERVE ROWS;
语句的临时 table,并且TRUNCATE TABLE
在过程结束时常规 table,过程结束时带有
EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_NAME'
语句
所有这些选项都显示相同的错误。
我有 2 个 table,我正在将这 2 个 table 合并到全局临时 table 中,更改记录的一些值。
然后我正在创建一个游标到return一个SELECT
到临时table。
出现错误时就在这里
因此,我创建了以下 tables:
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 服务器上使用了临时 tables,一切都很好。
谢谢! :)
如果您创建了这些 table,那么您就可以访问它们(以及您架构中的过程)。另一方面,该过程使用其他一些 tables - 你能访问它们吗?看看当我 运行 你的代码时会发生什么:
正在创建表:
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
啊哈; table第 17 行和第 34 行中引用的内容不存在(或者我无法访问它们):
17 FROM REM_SECCPREG
34 FROM REM_PREGEVEN PREGE
那么,它们是否存在于您的架构中?如果没有,其他人是否拥有它们?如果是这样,该用户(所有者)应该授予您 SELECT
权限(直接,而不是通过角色),然后您应该在那些 table 名称之前加上所有者名称(例如 scott.rem_seccpreg
),或在您自己的架构中创建同义词。
看看上面写的是否有帮助。
SQL 服务器中的临时 Table 不同于 Oracle 中的全局临时 Table。具体来说,Global Temporary Table 是 permanent 数据结构,它只是临时数据。 GTT 中的数据仅限于插入它的会话,并将在事务或会话结束时被擦除,具体取决于 table 的定义方式。
关于您的过程的另一件事是它将打开的引用游标传递给调用程序。游标不是数据集,它是查询的指针:调用程序然后获取数据,这意味着它执行查询并处理其结果集。问题是,在打开查询后,您的过程立即执行 EXECUTE IMMEDIATE 'TRUNCATE TABLE REM_ORDENSECCIONESP';
。因此,当调用程序试图从游标中获取记录时,橱柜是空的。
删除 truncate table
语句。它正在破坏你的过程。 GTT 的问题之一是发布 DDL 比正常的 tables 更麻烦:例如,如果有任何使用它的会话仍然打开,我们就不能删除 GTT。幸运的是,鉴于全局临时 tables 的行为,截断几乎肯定是不必要的。如果您真的认为自己需要什么,只需在流程开始时 delete from GTT
;这将在您重新填充之前清除会话早期的任何挥之不去的数据(交易?)。
这是 db<>fiddle 上的演示。