3

次のようなサンプルコードがあります。

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;

私の要件は、/node_root/node_1in columnが null でないときはいつでも、とxの値を null に置き換えることです。クエリで使用した関数も同じです。/node_root/node_2/node_root/node_3/node_root/node_4UpdatexmlSELECT

ここでの問題はUpdatexml、Oracle 12c では機能しないことです。これが、サブクエリで使用した理由でありXmltable、データのフィルタリングには完璧に機能しますが、ノード値を null に置き換えることはできません。

Oracle Docs for XQueryを調べてみましたが、ノード値の置換にどのように役立つか理解できませんでした。

わかりやすい例を教えてください。

4

1 に答える 1

3

Oracle ドキュメントでは、XQuery を使用して 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に関するより深い知識が必要です ...

于 2014-01-09T13:37:45.280 に答える