обновление столбца CLOB с несколькими пространствами имен в Oracle - PullRequest
0 голосов
/ 11 июня 2019

Я пытаюсь обновить элемент, который находится внутри столбца clob в базе данных Oracle.

Первая проблема, с которой я сталкиваюсь, состоит в том, что мой clob xml имеет 2 пространства имен, и я не могу заставить это работать.

<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
  <esbmsg:Body>
    <Transaction xmlns="http://test.com">
      <test-element>
        <finalElement>false</finalElement>
      </test-elemen>
    </Transaction>
  </esbmsg:Body>
</esbmsg:EsbMessage>



select x.* from cc_messagehistory y
cross join xmltable(
  xmlnamespaces('http://www.test.com/esb/message/1.0' as "esbmsg",
    'http://test.com ' ),
  '/esbmsg:EsbMessage'
  passing xmltype.createxml(y.payload)  
    factext varchar2(10) path '/esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement'
) x;

ORA-19102: ожидается строковый литерал XQuery 19102. 00000 - «Ожидается строковый литерал XQuery» * Причина: отсутствует строковый литерал, содержащий выражение XQuery. * Действие: Укажите выражение XQuery в виде строкового литерала. Ошибка в строке: 64 столбец: 99

1 Ответ

0 голосов
/ 12 июня 2019

Непосредственной причиной ORA-01902 является то, что вы пропустили ключевое слово default:

  xmlnamespaces('http://www.test.com/esb/message/1.0' as "esbmsg",
    default 'http://test.com'),

Я удалил лишний пробел в конце URI, что позже вызовет проблемы. Но вам также не хватает ключевого слова columns, и вы можете упростить преобразование значения CLOB в XMLType.

Собрав все это вместе с CTE для предоставления вашего (исправленного) образца XML:

-- CTE for sample data
with cc_messagehistory(payload) as (
select to_clob('<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
  <esbmsg:Body>
    <Transaction xmlns="http://test.com">
      <test-element>
        <finalElement>false</finalElement>
      </test-element>
    </Transaction>
  </esbmsg:Body>
</esbmsg:EsbMessage>') from dual
)
-- actual query
select x.*
from cc_messagehistory y
cross join xmltable (
  xmlnamespaces (
    'http://www.test.com/esb/message/1.0' as "esbmsg",
    default 'http://test.com'
  ),
  '/esbmsg:EsbMessage'
  passing xmltype(y.payload)  
  columns factext varchar2(10)
  path '/esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement'
) x;

FACTEXT   
----------
false

Для обновления вы можете сделать что-то вроде:

update cc_messagehistory y
set payload = XMLSerialize(document
  XMLQuery('declare default element namespace "http://test.com"; (: :)
    declare namespace esbmsg="http://www.test.com/esb/message/1.0"; (: :)
    copy $i := $xml modify (
      for $j in $i//esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement
      return replace value of node $j with $new
    )
    return $i'
    passing xmltype(y.payload) as "xml",
    'true' AS "new"
    returning content
  )
  indent size=2
)
where xmlexists('declare default element namespace "http://test.com"; (: :)
  declare namespace esbmsg="http://www.test.com/esb/message/1.0"; (: :)
  $xml//esbmsg:EsbMessage/esbmsg:Body/Transaction/test-element/finalElement[text()="false"]'
  passing xmltype(y.payload) as "xml");

, который преобразует этот исходный CLOB в:

<?xml version="1.0"?>
<esbmsg:EsbMessage xmlns:esbmsg="http://www.test.com/esb/message/1.0">
  <esbmsg:Body>
    <Transaction xmlns="http://test.com">
      <test-element>
        <finalElement>true</finalElement>
      </test-element>
    </Transaction>
  </esbmsg:Body>
</esbmsg:EsbMessage>

db <> fiddle (работает на 18c; ошибки на 11gR2, но уровни исправлений могут иметь значение; также успешно протестированы в других местах на 12cR1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...