[英]Invalid number of arguments error in oracle
请让我知道以下查询的插入语句中是否有错误。 它给我“无效数量的参数”错误
create or replace PROCEDURE adm_getMaxTableIdLimited
(
v_TableName IN VARCHAR2 DEFAULT NULL ,
v_TableIDColumnName IN VARCHAR2 DEFAULT NULL ,
v_MaxTableId OUT NUMBER
)
AS
v_Limit NUMBER(10,0);
v_SQLStatement VARCHAR2(255);
BEGIN
v_Limit:= 99999 ;
v_MaxTableId:= 0 ;
EXECUTE IMMEDIATE 'DROP TABLE TempResult';
EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE TempResult
(
Result NUMBER(10,0)
)';
v_SQLStatement:= 'Insert INTO TempResult(Result) SELECT max(' || v_TableIDColumnName || ')
FROM ' || v_TableName || ' WHERE ' || v_TableIDColumnName || ' <= ' || CAST(v_limit AS
VARCHAR2) || ';';
EXECUTE IMMEDIATE v_SQLStatement;
EXECUTE IMMEDIATE 'SELECT Result INTO v_MaxTableId FROM TempResult' ;
IF ( v_MaxTableId = v_Limit ) THEN
v_MaxTableId := -1 ;
ELSE
v_MaxTableId := v_MaxTableId + 1 ;
END IF;
EXECUTE IMMEDIATE ' TRUNCATE TABLE TempResult ';
END;
您根本不需要临时表。 您的代码可以大大简化:
create or replace PROCEDURE adm_getMaxTableIdLimited
(
v_TableName IN VARCHAR2 DEFAULT NULL,
v_TableIDColumnName IN VARCHAR2 DEFAULT NULL,
v_MaxTableId OUT NUMBER
)
AS
v_Limit NUMBER;
BEGIN
v_Limit:= 99999 ;
EXECUTE IMMEDIATE
'SELECT MAX(' || v_TableIDColumnName || ') FROM '
|| v_TableName || ' WHERE ' || v_TableIDColumnName || ' <= :limit'
INTO v_MaxTableId
USING v_Limit;
IF v_MaxTableId = v_Limit THEN
v_MaxTableId := -1;
ELSE
v_MaxTableId := v_MaxTableId + 1;
END IF;
END;
顺便说一句:您的代码中的当前问题是:
EXECUTE IMMEDIATE 'SELECT Result INTO v_MaxTableId FROM TempResult';
正确的行是:
EXECUTE IMMEDIATE 'SELECT Result FROM TempResult' INTO v_MaxTableId;
首先,您似乎非常不可能动态删除并创建临时表。 全局临时表就是全局的。 表定义对其他会话可见,这与您可能已经习惯于其他数据库的表定义不同。 与永久表一样,在安装应用程序时只需创建一次临时表。 在多用户环境中,删除和重新创建表将无法正常工作。
其次,似乎没有任何理由在这里使用临时表。 您可以仅动态生成SELECT
语句并将结果存储在局部变量中。
第三,您的INSERT
语句末尾不应使用分号。 这就是生成ORA-00911的原因:无效字符错误。
第四,动态SELECT
语句不应具有INTO
。 该INTO
子句需要是EXECUTE IMMEDIATE
一部分,而不是SQL语句的一部分。
因此,我的猜测是您想要类似
create or replace PROCEDURE adm_getMaxTableIdLimited
(
v_TableName IN VARCHAR2 DEFAULT NULL ,
v_TableIDColumnName IN VARCHAR2 DEFAULT NULL ,
v_MaxTableId OUT NUMBER
)
AS
v_Limit NUMBER(10,0) := 99999;
v_SQLStatement VARCHAR2(255);
BEGIN
v_SQLStatement :=
'SELECT max(' || v_TableIDColumnName || ') ' ||
' FROM ' || v_TableName ||
' WHERE ' || v_TableIDColumnName || ' <= :1';
EXECUTE IMMEDIATE v_SQLStatement
INTO v_MaxTableId
USING v_Limit;
IF ( v_MaxTableId = v_Limit ) THEN
v_MaxTableId := -1 ;
ELSE
v_MaxTableId := v_MaxTableId + 1 ;
END IF;
结束;
但是,为什么首先要创建此过程? 它似乎用于返回要插入表中的键的下一个值。 如果您正在这样做,则需要重新考虑您的方法。 与扫描序列相比,生成动态SQL扫描主键索引的最大值的效率要低得多。 它也不能在玩具系统之外正常工作,在玩具系统中,您可以保证只有一个用户。 在实际系统中,多个会话将获得相同的值,并尝试使用相同的键插入行。 两者之一将在INSERT
上阻塞,并最终得到重复的密钥错误。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.