更新一个节点的值,如果不存在则忽略

Update value of a node, ignore if not exists

我想替换 XML 中节点的值。 XML 存储在 Oracle 12.2 数据库中的 XMLTYPE 列中。 我的 XML:

<Warehouse>
  <WarehouseId>1</WarehouseId>
  <WarehouseName>Southlake, Texas</WarehouseName>
  <Building>Owned</Building>
  <Area>25000</Area>
</Warehouse>

UPDATEXML 函数可以完成这项工作,但速度较慢。

select
UPDATEXML(myxmlcolumn, '/Warehouse/Building/text()','mynewvalue')
from mytable;

Oracle 说 UPDATEXML 是 deprecated,应该改用 XMLQUERY。 所以,我尝试了 XMLQUERY 代替:

select
 XMLQUERY(
'copy $t := $x modify(
  replace value of node $t/Warehouse/Building with "mynewvalue"
) return $t'
from mytable;

它工作快得多,但有一个小问题:如果请求的节点不存在,它会失败并显示 XVM-01155:[XUDY0027] 无效的目标表达式

例如,此 select 失败并出现上述错误(注意 ZZZ 假节点名称):

select
 XMLQUERY(
'copy $t := $x modify(
  replace value of node $t/Warehouse/ZZZ with "mynewvalue"
) return $t'
from mytable;

问题: 如何更改代码以忽略不存在的节点?[​​=15=]

IF-ELSE 语句可能会有帮助:) 检查示例。

    with mytable as (select xmltype('<Warehouse>
      <WarehouseId>1</WarehouseId>
      <WarehouseName>Southlake, Texas</WarehouseName>
      <Building>Owned</Building>
      <Area>25000</Area>
    </Warehouse>') myxmlcolumn from dual) 
    select 

     XMLQUERY(
    'copy $t := . modify(
     if( $t/Warehouse/WarehouseName) then  
      (
        replace value of node $t/Warehouse/WarehouseName with "mynewvalue"
      )
      else ()
    ) return $t' passing myxmlcolumn returning content)

    from mytable
     union all 
     select 

     XMLQUERY(
    'copy $t := . modify(
     if( $t/Warehouse/ZZZZ) then  
      (
        replace value of node $t/Warehouse/ZZZZ with "mynewvalue"
      )
      else ()
    ) return $t' passing myxmlcolumn returning content)

    from mytable
union all
select 
 XMLQUERY(
'copy $t := . modify(
 for $node in  $t/Warehouse/ZZZZ
  return replace value of node $node with "mynewvalue"
) return $t' passing myxmlcolumn returning content) from mytable;

根据@Arkadiusz Łukasiewicz 的精彩回答,我编写了完整的解决方案,其中包括:

  • 忽略 non-existent 个节点
  • 能够在单个 xmlquery 调用中更改多个节点

开始了:

select
    xmlquery(
'    copy $t := $x modify
        (
          (for $i in $t/Warehouse/Building
             return replace value of node $i with "aaa"),
          (for $i in $t/Warehouse/ZZZ
             return replace value of node $i with "bbb)
        )   
    return $t 
'
passing 
    XMLRECORD as "x"  
from mytable