Обновить значение узла, игнорировать, если не существует - PullRequest
0 голосов
/ 08 июля 2019

Я хотел бы заменить значение узла в 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 устарел , и XMLQUERY должно бытьиспользуется вместоИтак, я попробовал XMLQUERY вместо этого:

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

Он работает намного быстрее , но есть одна маленькая проблема: если запрошенный узел не существует, он завершится неудачно с XVM-01155:[XUDY0027] Недопустимое целевое выражение

Например, этот выбор завершается неудачно с вышеуказанной ошибкой (обратите внимание на псевдоним узла ZZZ):

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

Вопрос: Как можноИзменить код, чтобы игнорировать несуществующие узлы?

Ответы [ 2 ]

1 голос
/ 08 июля 2019

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;
0 голосов
/ 10 июля 2019

Следуя великолепному ответу @Arkadiusz Łukasiewicz, я составил полное решение, которое включает в себя:

  • игнорирование несуществующих узлов
  • возможность смены нескольких узлов за один вызов 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
...