今天接着来学习DNS语句(原生动态SQL),学习有关绑定变量或绑定参数的使用规则。
参数模式
绑定参数可以有3种模式:
IN 只读值(默认模式)
OUT 只允许写
IN OUT 可以读取输入的值,也可以把值传递出去
当我们执行动态查询时,所有绑定参数必须是IN模式,除非我们使用的是RETURNING子句,如下所示:
PROCEDURE wrong_incentive(
IN INTEGER,
new_layoffs IN NUMBER
)
IS
sql_String VARCHAR2(32767);
sal_after_layoffs NUMBER;
BEGIN
sql_string := ‘UPDATE ceo_compensation SET salary = salary + 10 * :layoffs
WHERE company_id = :company
RETURNING salary INTO :newsal’;
EXECUTE IMMEDIATE sql_string
USING new_layoffs, company_in, sal_after_layoffs;
DBMS_OUTPUT.PUT_LINE(
‘CEO compensation after latest round of layoffs $’ ||sal_after_layoffs);
END;
除了和RETURNING子句一起使用,out和in out模式的绑定参数在执行动态PL/SQL时也发挥了很大作用。
在动态PL/SQL中,绑定参数的模式必须与PL/SQL程序的参数模式以及动态PL/SQL块中变量的使用相匹配。
下面是执行动态PL/SQL的USING子句的使用指导:
1、可以给一个IN模式的绑定变量提供任何类型正确的表达式:直接量、命名常量、变量或者复杂表达式。这些表达式被求值后再传递给动态PL/sql块。
2、必须提供一个变量来接收OUT或IN OUT模式绑定变量的输出值。
3、只能绑定动态PL/SQL块中有SQL类型的变量。例如,如果过程有布尔参数,我们不能使用USING子句设置(或提取)布尔值。
例子:
PROCEDUREanalyze_new_technology(
Tech_nameIN VARCHAR2,
Analysis_yearIN INTEGER,
Number_of_adherents IN OUT NUMBER,
Projected_revenue OUT NUMBER
)
--一个动态执行该过程的块
DECLARE
devoted_followers NUMBER;
est_revenue NUMBER;
BEGIN
EXECUTE IMMEDIATE
‘BEGIN
Analyze_new_technology (:p1, :p2, :p3, :p4);
END;’
USING‘JAVA’, 2002, IN OUT devoted_followers, OUT est_revenue;
END;
重复的占位符
在动态构造和执行的SQL字符串中,NDS将占位符通过位置而非名称与USING子句绑定参数关联。
然而,多个拥有相同名称的占位符的处理需要根据我们使用的是动态SQL还是动态PL/SQL来确定。
需要遵循以下原则:
1、我们执行动态SQL字符串时,我们必须为每个占位符提供一个参数,即使这些占位符有重复。
2、当我们执行动态PL/sql块时,必须为每个唯一占位符提供一个参数。
/*一个有重复占位符的动态SQL的示例。注意val_in参数的重复使用*/
PROCEDURE updnumval_SQL(
col_in IN Varchar2,
start_in IN DATE,
end_in IN DATE,
val_in IN NUMBER
)
IS
dml_str VARCHAR2(32767);
BEGIN
dml_str := 'UPDATE emp SET ' || col_in || ' = :val
WHERE hiredate BETWEEN :lodate AND :hidate
AND :val IS NOT NULL';
EXECUTE IMMEDIATE dml_str
USING val_in, start_in,end_in,val_in;
END;
/*一个有重复占位符的动态PL/SQL块的示例。注意val_in只提供一次就可以*/
PROCEDURE updnumval_PLSQL(
col_in IN Varchar2,
start_in IN DATE,
end_in IN DATE,
val_in IN NUMBER
)
IS
dml_str VARCHAR2(32767);
BEGIN
dml_str :=
'BEGIN
UPDATE emp SET ' || col_in || '= :val
WHERE hiredate BETWEEN :lodateAND :hidate
AND :val IS NOT NULL;
END;';
EXECUTE IMMEDIATE dml_str
USING val_in,start_in,end_in;
END;
传递NULL值
有时会遇到将NULL值作为参数传递的情况,像下面这样:
EXECUTE IMMEDIATE ‘UPDATE emp SET salary = :newsal
WHERE hiredate IS NULL’
USING NULL;
然而,会出现以下错误:
PLS-00457:in USING clause,expressions have to be of SQL types
意思是在USING子句的表达式必须是SQL类型,而NULL没有数据类型。
那么该怎么传递NULL值?有以下两种做法:
1、将NULL值隐藏在一个变量的后面,如果用一个未初始化的变量会更容易些:
DECLARE
--默认初始值为NULL
No_salary_when_firednumber;
BEGIN
EXECUTE IMMEDIATE ‘UPDATE emp SET salary = :newsal
WHERE hiredate IS NULL’
USING no_salary_when_fired;
END;
2、使用转换函数将NULL转换为一个有类型的值:
EXECUTE IMMEDIATE ‘UPDATE emp SET salary = :newsal
WHERE hiredate IS NULL’
USING to_number(NULL);