Слияние XML в SQL Server - PullRequest
       6

Слияние XML в SQL Server

7 голосов
/ 10 февраля 2012

Допустим, в моей базе данных есть следующие два фрагмента XML

<!-- XML 1 -->
<pairs>
    <item key="a">xml 1 a value</item>
    <item key="b">xml 1 b value</item>
    <item key="c">xml 1 c value</item>
</pairs>

<!-- XML 2 -->    
<pairs>
    <item key="c">xml 2 c value</item>
    <item key="d">xml 2 d value</item>
    <item key="e">xml 1 e value</item>
</pairs>

Эти данные хранятся в двух отдельных таблицах с использованием типа данных XML, кроме того, этот столбец XML связан со схемой, которая описывает формат ожидаемого xml, например,

[PairData] [xml](CONTENT [foo].[Pairs]) NULL

Внутри хранимой процедуры / функции я хотел бы объединить эти две XML-структуры в следующее:

<pairs>
    <item key="a">xml 1 a value</item>
    <item key="b">xml 1 b value</item>
    <item key="c">xml 2 c value</item>
    <item key="d">xml 2 d value</item>
    <item key="e">xml 2 e value</item>
</pairs>

Итак, из первого куска XML мы взяли элементы:

a, b

из второго куска XML мы взяли предметы:

c, d, e  

Обратите внимание, что два фрагмента XML имеют общий элемент с ключом:

c

В этом сценарии значение из xml 2 должно использоваться в объединенном xml (исключая значение из xml 1). Другой случай - XML ​​1 или 2 может быть NULL, поэтому процесс слияния должен обрабатывать это и просто возвращать другой. Или оба могут иметь значение NULL, и в этом случае возвращается NULL.

Кроме того, в нашей текущей реализации мы возвращаем оба XML-документа из БД и выполняем слияние в коде. Однако мы бы предпочли, чтобы это слияние выполнялось в БД, так как несколько не связанных процессов вызывают этот процесс.

Ответы [ 2 ]

5 голосов
/ 10 февраля 2012

Использование:

declare @x1 xml ='<pairs>
    <item key="a">xml 1 a value</item>
    <item key="b">xml 1 b value</item>
    <item key="c">xml 1 c value</item>
</pairs>'

declare @x2 xml ='<pairs>
    <item key="c">xml 2 c value</item>
    <item key="d">xml 2 d value</item>
    <item key="e">xml 2 e value</item>
</pairs>'

select *
from
(
    select isnull(t2.a, t1.a) [@key], isnull(t2.b, t1.b) [text()]
    from
    (
        select t.c.value('@key', 'nvarchar(max)') [a], t.c.value('.', 'nvarchar(max)') [b]
        from @x1.nodes('/*/item') t(c)
    )t1
    full join
    (
        select t.c.value('@key', 'nvarchar(max)') [a], t.c.value('.', 'nvarchar(max)') [b]
        from @x2.nodes('/*/item') t(c)
    )t2 on t2.a = t1.a
)t
for xml path('item'), root('pairs')

Выход:

<pairs>
  <item key="a">xml 1 a value</item>
  <item key="b">xml 1 b value</item>
  <item key="c">xml 2 c value</item>
  <item key="d">xml 2 d value</item>
  <item key="e">xml 2 e value</item>
</pairs>

UPDATE:

declare @x1 xml ='<pairs>
    <item key="a">xml 1 a value</item>
    <item key="b">xml 1 b value</item>
    <item key="c">xml 1 c value</item>
</pairs>'

declare @x2 xml ='<pairs>
    <item key="c">xml 2 c value</item>
    <item key="d">xml 2 d value</item>
    <item key="e">xml 2 e value</item>
</pairs>'

declare @t1 table(id int, data xml)
insert @t1 values(1, @x1)

declare @t2 table(id int, data xml)
insert @t2 values(1, @x2)

select isnull(t2.a, t1.a) [@key], isnull(t2.b, t1.b) [text()]
from
(
    select t.c.value('@key', 'nvarchar(max)') [a], t.c.value('.', 'nvarchar(max)') [b]
    from @t1 ta
    cross apply ta.data.nodes('/*/item') t(c)
)t1
full join
(
    select t.c.value('@key', 'nvarchar(max)') [a], t.c.value('.', 'nvarchar(max)') [b]
    from @t2 ta
    cross apply ta.data.nodes('/*/item') t(c)
)t2 on t2.a = t1.a
for xml path('item'), root('pairs')
1 голос
/ 10 февраля 2012

Пример с таблицами:

CREATE TABLE #x1 (row_key int, source_xml xml)
CREATE TABLE #x2 (row_key int, source_xml xml)

DECLARE @x1 xml = 
'<pairs>
    <item key="a">xml 1 a value</item>
    <item key="b">xml 1 b value</item>
    <item key="c">xml 1 c value</item>
</pairs>'


DECLARE @x2 xml =
'<pairs>
    <item key="c">xml 2 c value</item>
    <item key="d">xml 2 d value</item>
    <item key="e">xml 1 e value</item>
</pairs>'

INSERT INTO #x1 VALUES (1, @x1)
INSERT INTO #x2 VALUES (1, @x2)

SELECT
    ISNULL(a.item_key, b.item_key) [@key]
    ,ISNULL(b.item_value, a.item_value) [text()]
FROM
(
SELECT
    b.value('@key', 'char(1)') item_key, b.value('.', 'nvarchar(100)') item_value
FROM
    #x1 cross apply #x1.source_xml.nodes('./pairs/item') a(b)
WHERE
    row_key = 1
) a
FULL JOIN
(   
SELECT
    b.value('@key', 'char(1)') item_key, b.value('.', 'nvarchar(100)') item_value
FROM
    #x2 cross apply #x2.source_xml.nodes('pairs/item') a(b)
WHERE
    row_key = 1
) b
ON
    a.item_key = b.item_key
ORDER BY
    ISNULL(a.item_key, b.item_key)
FOR XML PATH ('item'), ROOT ('pairs')

DROP TABLE #x1
DROP TABLE #x2
...