Как вставить строку XML в столбец типа XML в SQL / XML с помощью Oracle? - PullRequest
0 голосов
/ 09 мая 2019

Я пытаюсь написать запрос SQL / XML в Oracle SQL Developer, чтобы обновить определенную строку в таблице базы данных. База данных имеет следующую структуру: enter image description here

атрибут «Переводы» имеет тип XML. Например, у меня есть книга с названием "Encore une fois" и OriginalLanguage "French" и ID "11". Эта книга имеет 2 издания следующим образом 1:

ID "17", Year "1997", Price "120", Book "11"
Translations:  <Translations>
                  <Translation Language="English" Price="120"/>
                  <Translation Language="Russian" Price="110"/>
               </Translations>

второе издание:

ID "18", Year "2001", Price "150", Book "11"
Translations:  <Translations>
                  <Translation Language="English" Publisher="Pels And Jafs" Price="180"/>
                  <Translation Language="Russian" Price="140"/>
               </Translations>

Я хочу вставить новый узел «Перевод» во втором издании. Я хочу добавить строку с надписью

<Translation Language="Norwegian" Publisher="KLC" Price="200"/>

Я написал следующий запрос

UPDATE BOOKDB.EDITION
SET Translations = XMLQUERY('copy $res := $t
                             modify insert node element Translation {attribute Language {"Norwegian"}, attribute Publisher {"KLC"}, attribute Price {200}} 
                             as last into $res/Translations
                             return $res'
                            PASSING Translations AS "t" RETURNING CONTENT)
WHERE Edition.Book in (SELECT ID FROM BOOKDB.Book WHERE Title = 'Encore une fois')

но я обновляю 2 строки вместо одной, потому что она помещена в обе версии, что неправильно Как мне ввести строку только во втором издании?

Ответы [ 2 ]

1 голос
/ 09 мая 2019

Если вы хотите обновить только второе издание, напишите подзапрос, который находит второй идентификатор, и используйте этот подзапрос в предложении in. Я использовал id для заказа, но вы также можете использовать year. Если вы хотите год, используйте его в order by в rownumber.

UPDATE EDITION
  SET Translations = XMLQUERY('copy $res := $t
                               modify insert node element Translation {attribute Language {"Norwegian"}, attribute Publisher {"KLC"}, attribute Price {200}} 
                               as last into $res/Translations
                               return $res'
                               PASSING Translations AS "t" RETURNING CONTENT)
  where (book, id) in (
    select book, id 
      from (
        select book.id book, edition.id, 
               row_number() over (partition by book.id order by edition.id) rn 
          from book join edition on book.id = edition.book where title = 'Encore une fois')
      where rn = 2);

Демоверсия dbfiddle

1 голос
/ 09 мая 2019

Похоже, что вы уже выполнили сложную часть - вам просто нужно добавить условие в инструкцию UPDATE, которая задает одну строку в EDITION вместо двух строк.Я бы порекомендовал протестировать ваше предложение WHERE с помощью оператора SELECT, чтобы убедиться, что вы получаете именно те строки, которые вам нужны, например:

SELECT *
FROM BOOKDB.EDITION
WHERE Edition.Book in (SELECT ID FROM BOOKDB.Book WHERE Title = 'Encore une fois')

Это возвращает 2 строки, которые вы обновляете в настоящее время, верно?

Так сразу после

WHERE Edition.Book in (SELECT ID FROM BOOKDB.Book WHERE Title = 'Encore une fois')

вы можете добавить

AND Edition.ID = '18'

, или вы можете добавить

AND Edition.Year = '2001'

Если вы хотите более общего назначенияРешение всегда обновлять самую последнюю версию, вы можете сделать подзапрос, чтобы убедиться, что вы выбираете последнюю версию:

AND not exists (select 1 from BOOKDB.Edition e 
                where e.Book = Edition.Book 
                 and e.Year > Edition.Year)

Как только у вас есть предложение WHERE, которое выбирает нужные вам строки, добавьте его обратнона ваше заявление ОБНОВЛЕНИЕ:

UPDATE BOOKDB.EDITION
SET Translations = XMLQUERY('copy $res := $t
                         modify insert node element Translation {attribute Language {"Norwegian"}, attribute Publisher {"KLC"}, attribute Price {200}} 
                         as last into $res/Translations
                         return $res'
                        PASSING Translations AS "t" RETURNING CONTENT)
WHERE Edition.Book in (SELECT ID FROM BOOKDB.Book WHERE Title = 'Encore une fois')
  AND Edition.ID = '18'
...