Oracle实现动态SQL的拼装要领 |
虽说Oracle的动态SQL语句使用起来确实很方便,但是其拼装过程却太麻烦 。尤其在拼装语句中涉及到date类型字段时,拼装时要加to_char先转换成字符,到了sql中又要使用to_date转成date类型和原字段再比较 。 例如有这样一个SQL语句: select ========= and (t.created>=to_date(||to_char(sysdate,yyyy-mm-dd)||,yyyy-mm-dd) AND t.created< to_date(||to_char(sysdate+1,yyyy-mm-dd)||,yyyy-mm-dd)) from dual; 它就是将sysdate转成字符串,再在生成的SQL中将字符串转换成date 。 其拼装出来的结果如下: ========= and (t.created>=to_date(2012-11-08,yyyy-mm-dd) AND t.created< to_date(2012-11-09,yyyy-mm-dd)) 字符串2012-11-08是我们使用to_char(sysdate,yyyy-mm-dd)生成的,语句中涉及到的每一个单引号,都要写成两个单引号来转义 。 虽然拼装过程很烦人,但只要掌握好三点,就应能拼装出能用的SQL语句 。 一、先确定目标 。应保证拼装出来的SQL应该是什么样子,然后再去配置那个动态SQL 二、拼装SQL的时候,所有使用连接符||连接的对象都应是varchar2类型,这种类型的对象以单引号开头,以单引号结尾 。数字会自动转,但date需要我们手工使用to_char函数转 。 三、遇到有引号的,就写成两个单引号 。 如 I am a SQL developer ||v_name|| in China. telephone is ||v_number|| . v_name是字符型的,所以拼装它是需要前后加单引号 。 这种转换很烦人,但从10g开始有一个新功能,可以让人不用这么烦 。它就是q[xxxxx] 示例如下: select q[ Im a SQL developer ]||to_char(sysdate,yyyy)||q[ in China. telephone is ]||1990||. from dual; 结果如下: Im a SQL developer 2012 in China. telephone is 1990. Im使用一个单引号在q[]中就可以 。 简而言之,掌握这三点,就应该能拼装出能用的SQL 。至于如果使用绑定变量输入输出,则需要使用into using关键字 。 set serveroutput on; declare incoming date:=sysdate-10; outgoing int; begin execute immediate select COUNT(*) FROM user_objects where created > :incoming into outgoing using incoming ; dbms_output.put_line( count is: || outgoing); end; 使用using的好处,就是不用去转date类型为varchar类型,再转回去date类型这种繁琐的操作 。 SQL代码如下: declare incoming date:=sysdate-10; outgoing int; begin execute immediate insert into t_object(a) select COUNT(*) FROM user_objects where created > :incoming into outgoing using incoming ; dbms_output.put_line( count is: || outgoing); end; ORA-01007: 变量不在选择列表中 declare v_cursor number; --定义游标 v_string varchar2(2999); v_row number; begin v_string := insert into t_object(a) select COUNT(*) FROM user_objects where created > :incoming;--操作语句,其中:name是语句运行时才确定值的变量 v_cursor:=dbms_sql.open_cursor;--打开处理游标 dbms_sql.parse(v_cursor,v_string,dbms_sql.native);--解释语句 dbms_sql.bind_variable(v_cursor,:incoming,sysdate-30); --给变量赋值 v_row := dbms_sql.execute(v_cursor);--执行语句 dbms_sql.close_cursor(v_cursor);--关闭游标 --dbms_output.put_line(v_row); commit; exception when others then dbms_sql.close_cursor(v_cursor); --关闭游标 rollback; end; |