Oracle SQL报错SP2-0552绑定变量T_END未声明但T_START正常原因求解
报错核心原因
1. 语法混淆
SP2-前缀的报错都属于SQL*Plus客户端错误,不是Oracle数据库服务端返回的错误,触发的根因是你混淆了SQL*Plus客户端命令和PL/SQL服务端语法:
EXEC是SQL*Plus专属命令,本质是BEGIN ... END;的简写,只能在PL/SQL块外部使用,不能写在DECLARE...BEGIN...END包裹的PL/SQL逻辑内部- 你在赋值语句中使用的
:opr/:t_start/:t_end属于SQL*Plus级别的绑定变量,需要提前用VARIABLE 变量名 类型命令声明才能赋值,你没有做声明操作直接赋值就会触发SP2-0552错误
2. 仅后定义变量报错的原因
SQL*Plus解析连续的未声明绑定变量赋值语句时,会尝试为前几个短赋值语句隐式创建适配类型的绑定变量,但受客户端解析缓存、语句长度限制,最后一个变量的隐式创建会失败,所以只会抛出最后一个绑定变量未声明的报错,你之前用t1、t2命名时仅t2报错也是这个逻辑。
脚本其他隐藏问题
除了绑定变量报错外,你写的脚本还有多个语法/逻辑问题:
duration变量未在DECLARE块中声明,执行时会触发PL/SQL标识符未定义错误time_sum初始值为NULL,直接与其他数值做运算会始终返回NULL,需要初始化为0- 两个
timestamp相减得到的是INTERVAL时间间隔类型,不能直接做求和、除法这类数值运算,需要先转换为秒级数值 - 存储在字符串变量中的动态SQL不能直接写
query;执行,需要用EXECUTE IMMEDIATE或者游标语法执行 - 你在
DECLARE块中声明的opr/op/ext_act等局部变量完全未被使用,实际用的是:开头的外部绑定变量
修正后参考脚本
SET SERVEROUTPUT ON SIZE 200000; DECLARE start_ts TIMESTAMP; fin_ts TIMESTAMP; duration INTERVAL DAY TO SECOND; time_sum NUMBER := 0; counter INTEGER := 1; -- 直接用PL/SQL局部变量存参数,不需要用外部绑定变量 v_opr VARCHAR2(64) := '88000001'; v_op VARCHAR2(64) := 'CHANGE_OWNER'; v_ext_act VARCHAR2(64) := 'NOT_APPLICABLE'; v_t_start DATE := TO_DATE('2018/07/01', 'yyyy/mm/dd'); v_t_end DATE := TO_DATE('2020/05/01', 'yyyy/mm/dd'); query1 VARCHAR2(4096):='select * from ITEM_HISTORY IH join PACKAGE P on P.PACKAGE_NAME = IH.PACKAGE_NAME where OPERATOR_ID = :opr and (IH.OPERATION != :op OR IH.EVENT_DATE = IH.INSTALLATION_DATE) and IH.EXTERNAL_SERVICE_ACTION != :ext_act and IH.EVENT_DATE >= :t_start and IH.EVENT_DATE < :t_end and rownum < 500000 order by IH.EVENT_DATE'; query2 VARCHAR2(4096):='select * from (select * from ITEM_HISTORY IH join PACKAGE P on P.PACKAGE_NAME = IH.PACKAGE_NAME where OPERATOR_ID = :opr and (IH.OPERATION != :op OR IH.EVENT_DATE = IH.INSTALLATION_DATE) and IH.EXTERNAL_SERVICE_ACTION != :ext_act and IH.EVENT_DATE >= :t_start and IH.EVENT_DATE < :t_end) where rownum < 500000'; query3 VARCHAR2(4096):='select * from ITEM_HISTORY IH join PACKAGE P on P.PACKAGE_NAME = IH.PACKAGE_NAME where OPERATOR_ID = :opr and (IH.OPERATION != :op OR IH.EVENT_DATE = IH.INSTALLATION_DATE) and IH.EXTERNAL_SERVICE_ACTION != :ext_act and IH.EVENT_DATE >= :t_start and IH.EVENT_DATE < :t_end fetch first 500000 rows only'; -- 游标接收查询结果,避免大量输出干扰耗时统计 cur SYS_REFCURSOR; BEGIN FOR query IN (SELECT column_value AS sql_text FROM TABLE(sys.dbms_debug_vc2coll(query1, query2, query3))) LOOP DBMS_OUTPUT.PUT_LINE('This is query ' || counter); time_sum := 0; FOR i IN 1..10 LOOP start_ts := SYSTIMESTAMP; -- 执行动态SQL,按顺序传入绑定变量 OPEN cur FOR query.sql_text USING v_opr, v_op, v_ext_act, v_t_start, v_t_end; CLOSE cur; fin_ts := SYSTIMESTAMP; duration := fin_ts - start_ts; -- 时间间隔转秒级数值累加 time_sum := time_sum + EXTRACT(SECOND FROM duration) + EXTRACT(MINUTE FROM duration)*60 + EXTRACT(HOUR FROM duration)*3600; DBMS_OUTPUT.PUT_LINE('Time taken for query' || counter || ' for run ' || i || ': ' || duration); END LOOP; DBMS_OUTPUT.PUT_LINE('Avg time for query' || counter || ': ' || ROUND(time_sum / 10, 2) || 's'); counter := counter+1; END LOOP; END; /
内容的提问来源于stack exchange,提问作者WesternGun
相关产品推荐
相关产品推荐

