12
返回列表 发新帖
楼主: gthboy

[PL/SQL] 不明白动态sql的重复占位符

[复制链接]
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
11#
发表于 2011-6-8 12:42 | 只看该作者
ls的不对,pl/sql中的动态sql是按位置的,不是名字
动态pl/sql才是按名字,不按位置

其他的程序编程接口有命名法绑定,那么是按名字的

使用道具 举报

回复
论坛徽章:
520
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
12#
发表于 2011-6-8 22:33 | 只看该作者
我以前都没注意到,确实有点变态。

CREATE TABLE T1 (N1 NUMBER, N2 NUMBER,N3 NUMBER,N4 NUMBER);
  
BEGIN
   EXECUTE IMMEDIATE 'INSERT INTO T1(N1,N2,N3,N4) VALUES (:N1,:N2,:N2,:N1)' USING 1,2;
END;
/

*
ERROR at line 1:
ORA-01008: not all variables bound
ORA-06512: at line 2

BEGIN
   EXECUTE IMMEDIATE 'BEGIN INSERT INTO T1(N1,N2,N3,N4) VALUES (:N1,:N2,:N2,:N1); END;' USING 1,2;
END;
/


PL/SQL procedure successfully completed.

SELECT * FROM T1;

        N1         N2         N3         N4
---------- ---------- ---------- ----------
         1          2          2          1

使用道具 举报

回复
论坛徽章:
69
生肖徽章2007版:羊
日期:2008-11-14 14:42:19复活蛋
日期:2011-08-06 08:59:05ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:542012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:202012新春纪念徽章
日期:2012-02-13 15:13:20版主4段
日期:2012-05-15 15:24:11
13#
发表于 2011-6-9 09:45 | 只看该作者
同意newkid,我也觉得变态.

使用道具 举报

回复
招聘 : 数据分析/ETL
论坛徽章:
4
ITPUB学员
日期:2011-10-09 08:54:30ITPUB十周年纪念徽章
日期:2011-11-01 16:25:222013年新春福章
日期:2013-02-25 14:51:24迷宫蛋
日期:2013-04-24 10:42:36
14#
发表于 2011-7-23 12:44 | 只看该作者
原帖由 涅烨曦 于 2011-6-8 09:42 发表
楼主的问题在书中应该也有提到才对。

原因是,BEGIN calc_stats(:x, :x, :y, :x); END 是一个PL/SQL 代码段,而非 insert into t6 (a,b,c) values (:x,:y,:x) 这样的DML,标准SQL语句。

在EXECUTE IMMEDIATE 中,利用USING语句绑定变量时,Oracle遵循针对PL/SQL存储过程使用占位符名称匹配的原则,而针对SQL语句则采用占位符位置匹配的原则。

PL/SQL 用户指南与参考 中的 例子如下:

动态SQL语句中的占位符与USING子句中的绑定参数是位置关联的,而不是名称关联。所以,如果在SQL语句中同样的占位符出现两次或多次,那么,它的每次出现都必须与一个USING子句中的绑定参数相关联。例如下面的动态字符串:
     sql_stmt := 'INSERT INTO payroll VALUES (:x, :x, :y,  :x)';   我们可以为动态字符串编写对应的USING子句:
     EXECUTE IMMEDIATE  sql_stmt USING a, a, b, a;   但 是,动态PL/SQL块中只有唯一的占位符才与USING子句中的绑定参数按位置对应。所以,如果一个占位符在PL/SQL块中出现两次或多次,那么所有 这样相同的占位符都只与USING语句中的一个绑定参数相对应。比如下面的例子,第一个占位符(x)与第一个绑定参数(a)关联,第二个占位符(y)与第 二个绑定参数(b)关联。
     DECLARE
     a   NUMBER := 4;
     b   NUMBER := 7;
  BEGIN
     plsql_block     := 'BEGIN calc_stats(:x,  :x, :y, :x); END';
  
    EXECUTE IMMEDIATE plsql_block
                  USING a, b;
     ...
  END;   

我觉得这个是问题的核心,即Oracle针对PL/SQL块(BEGIN END之间的存储过程或者SQL语句),对绑定变量采用的是按照参数名称匹配的原则;而针对PL/SQL语句(INSERT、DELETE等)则是采用的按照参数位置匹配的原则。匹配的原则不同,产生了不同的执行结果。就比如下面:

1、成功的情况
create or replace procedure test_dynamicSQL(m number, n number) is
  v_sql varchar2(100);
begin
  v_sql := 'begin insert into t6 (a,b,c) values (:x,:y,:x); end;';
  execute immediate v_sql
    using m, n;
end;

然后执行:
BEGIN
  test_dynamicSQL(38, 2);
END;

2、失败的情况
create or replace procedure test_dynamicSQL(m number, n number) is
  v_sql varchar2(100);
begin
  v_sql := 'insert into t6 (a,b,c) values (:x,:y,:x)';
  execute immediate v_sql
    using m, n;
end;

然后执行:
BEGIN
  test_dynamicSQL(38, 2);
END;

情况1就可以成功,情况2就会失败。问题的差异应该就在这里。向各位前辈学习了。嘻嘻~~~

[ 本帖最后由 ghost2876 于 2011-7-23 12:47 编辑 ]

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表