Заменить одну линию сгустка - PullRequest
0 голосов
/ 17 февраля 2020

У меня есть переменная clob в Oracle SQL, содержащая что-то вроде этого.

<catalog>
   <book id="bk101">
      <author>Joe</author>
       <genre>Fantasy</genre>
      <title>XML Developer  Guide</title>
      <price>44.95</price>
   </book>
   <book id="bk102">
      <author>Gregor</author>
      <genre>Fantasy</genre>
      <title>Midnight Rain</title>
      <price>5.95</price>
   </book>
</catalog>

Я хочу изменить Fantasy на что-то другое, только когда автора зовут Грегор. Я думаю, что функция REGEXP_REPLACE подойдет для этого, но не знаю, как правильно использовать ее в этом случае. Можете ли вы помочь мне с этим?

1 Ответ

0 голосов
/ 18 февраля 2020

После того, как я проделал всю эту работу, я обнаружил страницу переполнения стека с более кратким ответом. Проверьте Oracle -XMLTYPE: как обновить значение .

Я включаю два метода, метод замены методом грубой силы с использованием прямой SQL с последующим преобразованием CLOB из XML в строку / столбец, выполнить замену и преобразовать ее обратно в XML.

Грубая сила SQl

DECLARE
-- This probably isn't what you want as it converts all "Fantasy" to "Something Else"
-- if author Gregory appears anywhere in the XML
-- Define clob for test
l_clob                   CLOB;
-- Define text including string to replace
c_text          CONSTANT VARCHAR2( 512 ) := '<catalog>
<book id="bk101">
  <author>Joe</author>
   <genre>Fantasy</genre>
  <title>XML Developer  Guide</title>
  <price>44.95</price>
</book>
<book id="bk102">
  <author>Gregor</author>
  <genre>Fantasy</genre>
  <title>Midnight Rain</title>
  <price>5.95</price>
</book>
</catalog>';
-- Define text to replace
c_replace       CONSTANT VARCHAR2( 100 ) := '<genre>Fantasy</genre>';
--Define text to replace string
c_replacewith   CONSTANT VARCHAR2( 100 ) := '<genre>Something Else</genre>';
-- Define search string
c_search        CONSTANT VARCHAR2( 100 ) := '<author>Gregor</author>';
BEGIN
    -- Initialize l_clob
    DBMS_LOB.createtemporary( l_clob, TRUE );
    l_clob   := c_text;

    -- replace the text
    -- replace function works on strings and clobs
    IF DBMS_LOB.INSTR( l_clob, c_search ) > 0
    THEN
        l_clob   :=
            REPLACE( l_clob
                   , c_replace
                   , c_replacewith );
    END IF;

    -- Write the replace string out.
    -- put_line only outputs first 20,000 characters
    DBMS_OUTPUT.put_line( l_clob );
    DBMS_LOB.freetemporary( l_clob );
END;

XML до таблицы XML

-- Create table with clob
CREATE TABLE deleteme_table
(
    xml_data    CLOB
);

-- Insert XML into table
INSERT INTO deleteme_table
     VALUES ( '<catalog>
   <book id="bk101">
      <author>Joe</author>
       <genre>Fantasy</genre>
      <title>XML Developer  Guide</title>
      <price>44.95</price>
   </book>
   <book id="bk102">
      <author>Gregor</author>
      <genre>Fantasy</genre>
      <title>Midnight Rain</title>
      <price>5.95</price>
   </book>
</catalog>' );


-- Do the conversion
WITH
    aset AS
        (-- convert xml value to row/column
         SELECT xt.*
           FROM deleteme_table  x
              , XMLTABLE( '/catalog/book'
                          PASSING xmltype( x.xml_data )
                          COLUMNS id VARCHAR2( 10 ) PATH '@id'
                                , author VARCHAR2( 30 ) PATH 'author'
                                , genre VARCHAR2( 30 ) PATH 'genre'
                                , title VARCHAR2( 30 ) PATH 'title'
                                , price NUMBER PATH 'price' ) xt),
    bset AS
        ( -- replace the value
         SELECT id
              , author
              , CASE WHEN author = 'Gregor' THEN 'Something Else' ELSE genre END     AS genre
              , title
              , price
           FROM aset)
-- convert results back to XML
SELECT XMLELEMENT( "catalog"
                 , XMLELEMENT( "book"
                             , xmlattributes( bset.id AS "id" )
                             , XMLELEMENT( "author", bset.author )
                             , XMLELEMENT( "genre", bset.genre )
                             , XMLELEMENT( "title", bset.title )
                             , XMLELEMENT( "price", bset.price ) ) )
  FROM bset;
...