请告诉我以下查询的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;
答案 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
并最终获得重复的密钥错误。