0

请让我知道以下查询的插入语句是否有任何问题。它给了我“无效的参数数量”错误

    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;
4

2 回答 2

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;

顺便说一句:您代码中的当前问题是:

EXECUTE IMMEDIATE 'SELECT Result INTO v_MaxTableId FROM TempResult';

正确的行是:

EXECUTE IMMEDIATE 'SELECT Result FROM TempResult' INTO v_MaxTableId;
于 2013-09-14T18:55:40.923 回答
0

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

其次,似乎没有任何理由在这里使用临时表。您可以动态生成SELECT语句并将结果存储在局部变量中。

第三,您的INSERT语句末尾不应有分号。这就是产生 ORA-00911: invalid character 错误的原因。

第四,你的动态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并最终得到重复键错误。

于 2013-09-14T18:56:52.280 回答