oracle中的参数数量无效

时间:2013-09-14 18:06:29

标签: sql oracle

请告诉我以下查询的insert语句中是否有任何错误。它给了我'无效数量的参数'错误

    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;

2 个答案:

答案 0 :(得分:3)

根本不需要临时表。您的代码可以大大简化:

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;

BTW:您代码中的当前问题是:

EXECUTE IMMEDIATE 'SELECT Result INTO v_MaxTableId FROM TempResult';

正确的行是:

EXECUTE IMMEDIATE 'SELECT Result FROM TempResult' INTO v_MaxTableId;

答案 1 :(得分:0)

首先,您似乎非常非常不希望动态删除并创建临时表。全局临时表就是全局临时表。对于其他会话,表定义是可见的,这与您在其他数据库中习惯使用的不同。就像永久表一样,您可以在安装应用程序时创建一次临时表。删除和重新创建表将无法在多用户环境中正常工作。

其次,似乎没有任何理由在这里使用临时表。您可以动态生成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;  

END;

为什么你首先创建这个程序呢?它似乎用于返回要插入表中的键的下一个值。如果这就是你正在做的事情,你需要重新考虑你的方法。生成扫描主键索引的最大值的动态SQL比使用序列的效率低得多。它也不能在玩具系统之外正常工作,您可以保证只有一个用户。在实际系统中,多个会话将获得相同的值并尝试插入具有相同键的行。其中一个将阻止INSERT并最终获得重复的密钥错误。