如何使用 Oracle 在 SQL/XML 的 XML 类型列中插入 XML 行?

How to insert an XML row in XML type column in SQL/XML using Oracle?

我正在尝试在 Oracle SQL Developer 中编写一个 SQL/XML 查询来更新数据库 table 中的特定行。数据库具有以下结构,

属性 "Translations" 是 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"节点。我的意思是我想添加显示

的行
<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 行而不是 1 行,因为它被放置在两个版本中,这是错误的。怎么只输入第二版的行?

看起来您已经完成了困难的部分 - 您只需向 UPDATE 语句添加一个条件,该条件在 EDITION 中指定单行而不是两行。我建议用 SELECT 语句测试你的 WHERE 子句,以确保你得到你想要的行,例如

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

这 returns 您当前正在更新的 2 行,对吗?

紧接着

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

你可以添加

AND Edition.ID = '18'

,或者您可以添加

AND Edition.Year = '2001'

如果您想要一个更 general-purpose 的解决方案来始终更新最新版本,您可以执行子查询以确保您选择的是最新版本:

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

一旦你有一个 WHERE 子句来选择你想要的行,将它添加回你的 UPDATE 语句:

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'

如果您只想更新 second 版本,则编写子查询以查找第二个 id 并在 in 子句中使用此子查询。我使用 id 进行排序,但您也可以使用 year。如果您想要年份,请在 rownumber 中的 order by 中使用它。

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 demo