繁体   English   中英

oracle中无效的参数数量错误

[英]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.

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