【问题标题】:Modify XML node value- UpdateXML equivalent for Oracle 12c修改 XML 节点值 - 适用于 Oracle 12c 的 UpdateXML
【发布时间】:2014-01-27 18:13:51
【问题描述】:

我有一些示例代码如下:

WITH xtbl AS
         (SELECT 1 AS xtbl_id,
                 xmltype ('<node_root>
                        <node_1>12</node_1>
                        <node_2>233</node_2>
                        <node_3>223</node_3>
                        <node_4>234</node_4>
                   </node_root>') AS x
            FROM Dual
          UNION ALL
          SELECT 2, xmltype ('<node_root>
                        <node_1></node_1>
                        <node_2>233</node_2>
                        <node_3>223</node_3>
                        <node_4>234</node_4>
                   </node_root>')
            FROM Dual)
SELECT xtbl_id,
       x,
       Updatexml (x,
                  '/node_root/node_2',
                  NULL,
                  '/node_root/node_3',
                  NULL,
                  '/node_root/node_4',
                  NULL)
           AS xcol
  FROM xtbl
 WHERE (SELECT node_1
          FROM Xmltable ('node_root'
                         PASSING x
                         COLUMNS node_1 INTEGER PATH 'node_1'))
           IS NOT NULL;

我的要求是,只要x 列中的/node_root/node_1 不为空,则将/node_root/node_2/node_root/node_3/node_root/node_4 的值替换为空。我在SELECT 查询中使用的Updatexml 函数也是如此。

这里的问题是Updatexml 在 Oracle 12c 中不起作用。这就是我在子查询中使用Xmltable 的原因,它在过滤数据方面非常有效,但我无法用 null 替换节点值。

我尝试查看 XQuery 的 Oracle Docs,但不明白它对替换节点值有何帮助。

请提供一个描述性示例。

【问题讨论】:

    标签: sql xml oracle xquery oracle12c


    【解决方案1】:

    Oracle 文档recommends to use XQuery to update XML。所以首先要尝试。

    首先,可以使用具有功能的旧方法。可以使用下面的 XQuery 而不是调用XmlUpdate

        XMLQuery(
          ' 
            declare function local:copy-replace($element as element()) {  
              if ($element/self::node_2) then <node_2/>
              else if ($element/self::node_3) then <node_3/>
              else if ($element/self::node_4) then <node_4/>
              else element {node-name($element)}  
                           {$element/@*, 
                            for $child in $element/node()  
                            return if ($child instance of element())  
                                   then local:copy-replace($child)  
                                   else $child  
                           }  
            };  
            local:copy-replace($p/*)
          '
          passing x as "p" returning content
        ) as xcol_2  
    

    另一个更短、更直观的变体:

        XMLQuery(
          '              
            copy $p2 := $p
            modify(
              replace value of node $p2/node_root/node_2 with "",
              replace value of node $p2/node_root/node_3 with "",
              replace value of node $p2/node_root/node_4 with ""
            )
            return $p2
          '
          passing x as "p" returning content
        ) as xcol_3
    

    此外,只有在条件不匹配时才可能返回修改后的 XML 值:

    WITH xtbl AS
         (SELECT 1 AS xtbl_id,
                 xmltype ('<node_root>
                        <node_1>12</node_1>
                        <node_2>233</node_2>
                        <node_3>223</node_3>
                        <node_4>234</node_4>
                   </node_root>') AS x
            FROM Dual
          UNION ALL
          SELECT 2, xmltype ('<node_root>
                        <node_1></node_1>
                        <node_2>233</node_2>
                        <node_3>223</node_3>
                        <node_4>234</node_4>
                   </node_root>')
            FROM Dual)
    SELECT xtbl_id,
       x,
        XMLQuery(
          '   
            for $test in $p/*
            return 
              if( empty($p/node_root/node_1/text()) )             
                then $p
                else (
                 copy $p2 := $p
                  modify(
                    replace value of node $p2/node_root/node_2 with "",
                    replace value of node $p2/node_root/node_3 with "",
                    replace value of node $p2/node_root/node_4 with ""
                  )
                  return $p2
               )   
          '
          passing x as "p" returning content
        ) as xcol_4
    FROM xtbl
    

    因此有很多变体可以对 XML 值执行操作,但这需要比相对简单的 XmlUpdate 函数更深入地了解 XQueryXPath ...

    【讨论】:

    • 第一个代码示例适用于 11gR2 和 12c。第二个和第三个示例仅适用于 12c。谢谢!
    • 这很奇怪,因为我针对 11.2.0.3 版本的 Oracle 测试了所有变体。您能否发布您的 Oracle 的确切版本(例如 select * from v$version)?
    • 有两个 - 11.2.0.1.0 和 12.1.0.1.0,都是 64 位的。
    • 看起来像是从 11.2.0.3 开始工作。看this page(抱歉,找不到官方证明)。
    • 没问题。您的第一个示例在 11.2.0.1 中运行,这对我来说已经足够了。谢谢!
    猜你喜欢
    • 2011-12-19
    • 2018-12-20
    • 1970-01-01
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多