簡體   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