【问题标题】:Bind variable with single quotes in Oracle dynamic sql在Oracle动态sql中用单引号绑定变量
【发布时间】:2020-01-16 10:44:09
【问题描述】:

我收到了不同版本的 xml 文件,每个文件都在不同的命名空间中定义。所以我需要在我的动态查询中使用命名空间作为绑定变量。

在 Oracle 12.1 上,该语句使用硬编码命名空间运行良好:XMLNAMESPACES (DEFAULT 'http://www.ff.org')

如果我尝试用绑定变量替换字符串,则会由于缺少单引号而引发错误。我已经尝试在“立即执行”中绑定变量时添加单引号,或者在包含绑定变量 :sNamespace 的动态查询中添加引号,但它们都不起作用。

declare 
  sNamespace varchar2(100);
  sXMLVersion  VARCHAR2(3);
  sstmt varchar2(1000);
begin
  sNamespace := 'http://www.ff.org';

  sstmt := q'#
   with t_base as (select xmltype('<froot xmlns="http://www.ff.org">
                                     </froot>') as xml from dual)
   SELECT  case when v.is_root = 1 then '1' 
                else '2' end       
    into :sXMLVersion
           FROM t_base t, 
           XMLTABLE(XMLNAMESPACES(DEFAULT :sNamespace),
                 '$d' passing t.xml as "d"
                     columns 
                       is_root INTEGER           PATH 'exists(froot)'
                 ) v

  #';
    execute immediate sstmt using sNamespace into sXMLVersion;
    dbms_output.put_line(sXMLVersion);   
end; 

【问题讨论】:

  • XMLTABLE(XMLNAMESPACES(DEFAULT :sNamespace) 更改为XMLTABLE(XMLNAMESPACES(DEFAULT ':sNamespace')
  • 不幸的是,这不是正确的解决方案,因为它现在抛出 ORA-01006 绑定变量不存在。请仅提供工作代码作为解决方案建议。
  • 你的说法一大问题是sstmt := 'SELECT ... INTO :sXMLVersion FROM ...',错了,一定是sstmt := 'SELECT ... FROM ...'; execute immediate sstmt INTO sXMLVersion

标签: sql oracle dynamic bind-variables


【解决方案1】:

在DEFAULT命名空间中使用绑定变量的问题

 XMLTABLE(XMLNAMESPACES(DEFAULT :sNamespace)

是你收到错误ORA-19102: XQuery string literal expected

这表明,只有字面量作为命名空间,这再次表明您必须动态设置 SQL 语句。

我能想象的最好的方法是给你 两个 q-quoted 字符串如下

declare 
  sNamespace varchar2(100) := 'http://www.ff.org';
  sIsRoot number;
  sstmt varchar2(1000) := q'#with t_base as (select xmltype('<froot xmlns="http://www.ff.org">
                                     </froot>') as xml from dual)
   SELECT  v.is_root    
           FROM t_base t, 
           XMLTABLE(XMLNAMESPACES(DEFAULT '#'||sNamespace||q'#'),
                 '$d' passing t.xml as "d"
                     columns 
                       is_root INTEGER           PATH 'exists(froot)'
                 ) v#';
begin  
    execute immediate sstmt  into sIsRoot;
    dbms_output.put_line(sIsRoot);   
end;
/

【讨论】:

    【解决方案2】:

    你为什么使用with t_base as (select xmltype(...) as xml from dual)?我想你可以直接使用它。您不能绑定 XML 命名空间,因为它不是变量。您可以使用以下之一:

    DECLARE
        sstmt  VARCHAR2(10000);
        sNamespace VARCHAR2(100);
        res INTEGER;
    BEGIN
    
        sNamespace := 'http://www.ff.org';
    
        sstmt  := q'# 
        SELECT 
            CASE WHEN is_root = 1 THEN 1 
            ELSE 2 END       
        FROM 
            XMLTABLE(
                XMLNAMESPACES(DEFAULT '#'||sNamespace||'''),'||
        q'#'), 
                '$d' PASSING :x as "d" COLUMNS 
                is_root INTEGER PATH 'exists(froot)'
            ) x 
        #';
    
        DBMS_OUTPUT.PUT_LINE(sstmt);
    
        EXECUTE IMMEDIATE sstmt INTO res USING XMLTYPE('<froot xmlns="http://www.ff.org"></froot>');
        DBMS_OUTPUT.PUT_LINE ( 'res = ' || res );
    
    
        sstmt  := q'# 
        SELECT 
            CASE WHEN is_root = 1 THEN 1 
            ELSE 2 END       
        FROM 
            XMLTABLE(
                XMLNAMESPACES(DEFAULT '#'||sNamespace||'''),'||
        q'# 
                '$d' PASSING XMLTYPE(:x) as "d" COLUMNS 
                is_root INTEGER PATH 'exists(froot)'
            ) x 
        #';
    
        DBMS_OUTPUT.PUT_LINE(sstmt);
    
        EXECUTE IMMEDIATE sstmt INTO res USING '<froot xmlns="http://www.ff.org"></froot>';
        DBMS_OUTPUT.PUT_LINE ( 'res = ' || res );
    
    
    
    END;
    

    这应该没问题,因为命名空间通常不包含任何引号。

    【讨论】:

    • 感谢您的回复。发布的代码只是一个巨大语句的一小部分,仅出于演示目的,我已经解析了子查询 t_base 中的 xml 代码,当然它也可以通过执行语句绑定。我不能使用普通的字符串 concat,因为我的 sql 包含带有大量单引号的自动生成代码。这就是为什么我更喜欢使用特殊的引用 q'# 来构建动态代码。这里的问题是绑定命名空间变量,其余代码肯定可以以不同的方式进行更改..
    • 前两个语句不符合语法(using 来自after the into 子句)。修复后你会得到ORA-19102: XQuery string literal expected
    猜你喜欢
    • 2021-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 2017-06-30
    • 1970-01-01
    • 2015-01-18
    相关资源
    最近更新 更多