Dan*_*anK 1 sql oracle plsql stored-procedures stored-functions
我刚刚找到一个问题的答案,我遇到的问题是PL/SQL变量没有被函数识别,我希望有人可以向我解释为什么我的解决方案有效以及发生了什么"在幕后".
背景
作为优化项目的一部分,我正在尝试收集存储过程中各个SQL脚本的度量标准.我正在解析的存储过程具有一个In-type日期参数,我需要定义它以运行每个单独的SQL脚本:
CREATE OR REPLACE myStoredProc (DATE_IN DATE, ERROR_OUT OUT VARCHAR2)
IS
BEGIN
--Truncate Temp Tables
--6 Individual SQL Scripts
EXCEPTION
--Error Handling
END;
Run Code Online (Sandbox Code Playgroud)
为了单独运行每个脚本,我决定将每个SQL语句放入PL/SQL块并将DATE_IN参数作为变量提供:
DECLARE
DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
--Place individual script here
END;
Run Code Online (Sandbox Code Playgroud)
问题
这种方法适用于引用此DATE_IN变量的几个查询,但是一个查询引用了外部函数,该函数DATE_IN作为参数开始抛出ORA-00904错误:
DECLARE
DATE_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
insert into temp_table
SELECT table1.field1,
table1.field2,
table2.fieldA,
MyFunction(table1.field1, DATE_IN) --This was the problem line
FROM
table1,
table2
WHERE EXISTS (inner query)
AND table1.keys = table2.keys
AND table2.date <= DATE_IN
END;
Run Code Online (Sandbox Code Playgroud)
解
在另一个开发人员的建议下,我能够通过在DATE_IN我传递给函数的变量前面添加一个冒号(:)来解决这个错误,以便读取问题行MyFunction(table1.field1, :DATE_IN).一旦我这样做,我的错误消失了,我能够毫无问题地运行查询.
我对结果很满意,但是其他开发人员无法解释为什么需要它,只是需要从PL/SQL语句中调用任何函数或其他存储过程.我认为这与范围有关,但我想更好地解释为什么这个冒号对于函数查看变量是必要的.
问题
我试图做一些关于参数,变量,绑定/声明和常量的 Oracle文档的研究,但我的研究只给了我更多的问题:
DATE_IN DATE :=陈述不是变量,那么它是什么?DATE_IN被编译器识别但是将值传递给函数超出了范围?提前致谢.我感谢您提供的任何指导!
- - - - - - - - - - - - - - - - - 编辑 - - - - - - - - -----------------------
我被要求提供更多信息.我的Db版本是11G,11.2.0.2.0.我能够重现此错误的查询如下.
DECLARE
EXTRACT_DT_IN DATE := TO_DATE('16-JUL-2014','DD-MON-RR');
BEGIN
--This begins the pre-optimized query that I'm testing
insert into AELI_COV_TMP_2_OPT
SELECT /*+ ordered use_nl(CM MAMT) INDEX (CM CSMB_CSMB2_UK) INDEX (MAMT (MBAM_CSMB_FK_I) */
CM.CASE_MBR_KEY
,CM.pyrl_no
,MAMT.AMT
,MAMT.FREQ_CD
,MAMT.HOURS
,aeli$cov_pdtodt(CM.CASE_MBR_KEY, EXTRACT_DT_IN)
FROM
CASE_MEMBERS CM
,MEMBER_AMOUNTS MAMT
WHERE EXISTS (select /*+ INDEX(SDEF SLRY_BCAT_FK_I) */
'x'
from SALARY_DEF SDEF
where SDEF.CASE_KEY = CM.CASE_KEY
AND SDEF.TYP_CD = '04'
AND SDEF.SLRY_KEY = MAMT.SLRY_KEY)
AND CM.CASE_MBR_KEY = MAMT.CASE_MBR_KEY
AND MAMT.STAT_CD = '00'
AND (MAMT.xpir_dt is null or MAMT.xpir_dt > EXTRACT_DT_IN)
AND MAMT.eff_dt <= EXTRACT_DT_IN;
--This ends the pre-optimized query that I'm testing
END;
Run Code Online (Sandbox Code Playgroud)
这是我在尝试在此语句上运行解释计划时遇到的错误.如果我删除对第13行的引用或者EXTRACT_DT_IN在该行上添加冒号(:),我能够通过此错误.

----------------------编辑2 -------------------
这是aeli $ .cov_pdtodt的函数签名.(出于安全原因,我已经更换了所有者).
CREATE OR REPLACE function __owner__.aeli$cov_pdtodt
(CASE_MBR_KEY_IN IN NUMBER, EXTRACT_EFF_DT_IN DATE)
RETURN DATE IS
PDTODT DATE;
Run Code Online (Sandbox Code Playgroud)
只要您执行整个块,您的匿名块就可以了.如果您尝试仅执行insert或select作为独立命令执行,那么它确实会因ORA-00904而失败.
这不是一个范围问题,这是一个背景问题.您试图在SQL上下文中引用PL/SQL变量,这永远不会起作用.
在PL/SQL上下文中,这将起作用:
declare
some_var dual.dummy%type := 'X';
begin
insert into some_table
select dummy from dual where dummy = some_var;
end;
/
Run Code Online (Sandbox Code Playgroud)
...因为插入可以访问PL/SQL some_var.
在SQL上下文中,这将是错误:
select * from dual where dummy = some_var;
Run Code Online (Sandbox Code Playgroud)
...因为它正在寻找一个名为的列SOME_VAR,并且没有一个.
如果你这样做:
select * from dual where dummy = :some_var;
Run Code Online (Sandbox Code Playgroud)
... some_var现在是客户端管理的绑定变量.如果执行该操作,系统将提示您输入绑定值,或者提供非全部变量绑定错误,或者绑定变量未声明或类似错误,具体取决于您的客户端.
如果你只做一个解释计划,例如,用
set auto trace traceonly explain
select * from dual where dummy = :some_var;
Run Code Online (Sandbox Code Playgroud)
...然后,不一定必须填充绑定变量才能计算计划.有些客户可能仍然抱怨并想要一个绑定值,但是解析器可以用它 - 足以产生一个计划.虽然不能利用绑定变量偷看或直方图等.
例如,如果两个引用都转换为绑定变量,只是insert ...选择了块的一部分,并按下解释计划(F10),SQL Developer会愉快地为原始样本查询生成一个计划.
| 归档时间: |
|
| 查看次数: |
1625 次 |
| 最近记录: |