为什么选择有效但更新会抛出无效数据?
DECLARE L_NUMBER NUMBER; L_NUMBER_TABLE DBMS_SQL.NUMBER_TABLE; L_LAST_PRINTED_DATE DATE := SYSDATE; BEGIN L_NUMBER_TABLE(0) := 1033000; -- THIS WORKS SELECT TB.COLUMN_VALUE INTO L_NUMBER FROM TABLE(L_NUMBER_TABLE) TB; -- THIS DOES NOT WORK -- ERROR AT LINE 1 -- ORA-00902: INVALID DATATYPE -- ORA-06512: AT LINE 13 UPDATE SCHEMA.REAL_NUMBER_TABLE SET REAL_NUMBER_DATE = L_LAST_PRINTED_DATE WHERE EXISTS ( SELECT TB.COLUMN_VALUE FROM TABLE( L_NUMBER_TABLE ) TB WHERE TB.COLUMN_VALUE = REAL_NUMBER_COLUMN ); END;
我试图通过游标循环并更新在游标中找到的主要序列的最后打印日期。我尝试通过游标循环,但是当我将游标返回给客户端时,它抛出索引不足错误。因此,我不得不创建两个游标,一个游标循环,另一个游标返回。我的目标是学习保存用于更新表的集合的最简单,最可维护的方法。
DECLARE CURSOR L_ORIGINAL_CURSOR IS SELECT ... L_CURSOR_COLUMN_1 PLS_INTEGER; L_CURSOR_COLUMN_2 PLS_INTEGER; L_CURSOR_COLUMN_3 PLS_INTEGER; -- Keep adding or removing the number of columns to match...1/2 09182019515PM -- L_CURSOR_COLUMN_4 PLS_INTEGER; L_NUMBER_TABLE DBMS_SQL.NUMBER_TABLE; L_COUNTER PLS_INTEGER; L_LAST_PRINTED_DATE DATE := SYSDATE; BEGIN OPEN L_ORIGINAL_CURSOR; LOOP -- Keep adding or removing the number of columns to match... 2/2 09182019515PM FETCH L_ORIGINAL_CURSOR INTO L_CURSOR_COLUMN_1, L_CURSOR_COLUMN_2, L_CURSOR_COLUMN_3; -- , L_CURSOR_COLUMN_4; IF L_ORIGINAL_CURSOR%NOTFOUND THEN EXIT; END IF; IF L_ORIGINAL_CURSOR%FOUND THEN -- CURRENT SOLUTION IS TO UPDATE HERE BOUNCING BETWEEN SQL AND PLSQL ENGINES -- UPDATE .... -- WANTED IMPLEMENTATION L_COUNTER := L_COUNTER + 1; END IF; -- WANTED IMPLEMENTATION STORE PK IN MY COLLECTION L_NUMBER_TABLE(L_COUNTER) := L_CURSOR_COLUMN_1; END LOOP; -- IF COLLECTION IS BIGGER THAN 0 IF L_NUMBER_TABLE.COUNT > 0 THEN -- SCRIPT BREAKS HERE UPDATE ... SET ... = L_LAST_PRINTED_DATE WHERE EXISTS ( SELECT TB.COLUMN_VALUE FROM TABLE(L_NUMBER_TABLE) TB WHERE TB.COLUMN_VALUE = ... ); END IF; CLOSE L_ORIGINAL_CURSOR; OPEN L_CURSOR FOR SELECT ... END SP_GET_PM_WORK_ORDERS; / SHOW ERRORS;
当前,内联单个sql更新语句有效,但需要在SQL和PLSQL引擎之间进行多个引擎跃点。为什么允许我进行选择但不更新我的号码表?
数据库版本:12.1.0.2.0
DBMS_SQL.NUMBER_TABLE
是在DBMS_SQL
包中定义为以下内容的PL / SQL关联数组:
TYPE number_table IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
这是PL / SQL数据类型,不应在SQL语句中工作(我尚未弄清为什么第一个语句起作用)。
如果您想要一种在SQL中工作的数据类型,则需要使用一个集合(不带INDEX BY
;也称为嵌套表数据类型):
CREATE TYPE number_table IS TABLE OF NUMBER;
或定长VARRAY
:
CREATE TYPE number_array IS VARRAY(10) OF NUMBER;
例如:
Oracle安装程序:
CREATE TABLE real_number_table ( real_number_column, real_number_date ) AS
SELECT 1033000, DATE '2019-01-01' FROM DUAL;
CREATE TYPE number_table IS TABLE OF NUMBER;
PL / SQL语句1:
然后,您的SQL语句将使用集合数据类型:
DECLARE
L_NUMBER NUMBER;
L_NUMBER_TABLE NUMBER_TABLE;
L_LAST_PRINTED_DATE DATE := SYSDATE;
BEGIN
L_NUMBER_TABLE := NUMBER_TABLE();
L_NUMBER_TABLE.EXTEND;
L_NUMBER_TABLE( L_NUMBER_TABLE.COUNT ) := 1033000;
UPDATE REAL_NUMBER_TABLE
SET REAL_NUMBER_DATE = L_LAST_PRINTED_DATE
WHERE EXISTS (
SELECT TB.COLUMN_VALUE
FROM TABLE( L_NUMBER_TABLE ) TB
WHERE TB.COLUMN_VALUE = REAL_NUMBER_COLUMN
);
END;
/
然后:
SELECT * FROM real_number_table;
输出:
REAL_NUMBER_COLUMN | REAL_NUMBER_DATE -----------------:| :--------------- 1033000 | 19-OCT-19
PL / SQL语句2:
或者,您可以简化它并使用MEMBER OF
运算符(这仅适用于集合数据类型,不适用于VARRAY
):
REAL_NUMBER_COLUMN | REAL_NUMBER_DATE -----------------: | :--------------- 1033000 | 09-OCT-19
然后:
DECLARE
L_NUMBER NUMBER;
L_NUMBER_TABLE NUMBER_TABLE := NUMBER_TABLE( 1033000 );
L_LAST_PRINTED_DATE DATE := SYSDATE + 1;
BEGIN
UPDATE REAL_NUMBER_TABLE
SET REAL_NUMBER_DATE = L_LAST_PRINTED_DATE
WHERE REAL_NUMBER_COLUMN MEMBER OF L_NUMBER_TABLE;
END;
/
输出:
REAL_NUMBER_COLUMN | REAL_NUMBER_DATE -----------------:| :--------------- 1033000 | 10月10日
db <> 在这里拨弄
您最终的PL / SQL匿名块可以重写为:
SELECT * FROM real_number_table;