2012-02-10 13 views
6

Digamos que tengo los siguientes dos piezas de XML en mi base de datosLa fusión de XML en un servidor SQL

<!-- 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> 

Estos datos se almacenan en dos tablas separadas utilizando el tipo de datos XML, además, esta columna XML está vinculada a una esquema que describe el formato de la esperada por ejemplo, XML

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

dentro de un procedimiento/función almacenada me gustaría fusionar estas dos estructuras XML en lo siguiente:

artículos

a, b 

de la segunda pieza de XML que hemos tomado::

<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> 

artículos Así, a partir de la primera pieza de XML que hemos tomado

c, d, e 

en cuenta que las dos piezas de XML tener un elemento común con una clave de:

c 

en este escenario, el valor de xml 2 se debe utilizar en el fusionada xml (descartando el valor de xml 1). Otro caso es que XML 1 o 2 podrían ser NULL, por lo que el proceso de fusión debería manejar esto y simplemente devolver el otro. O ambos podrían ser NULL, en cuyo caso se devuelve NULL.

Como un aparte, en nuestra implementación actual estamos devolviendo ambos documentos XML de la base de datos y haciendo la fusión en el código. Sin embargo, preferiríamos hacer esta fusión dentro de la base de datos ya que varios procesos no relacionados están llamando a este proceso.

+0

La respuesta depende del almacenamiento de datos. (por ejemplo, su fuente es una tabla, una columna xml o una cadena de caracteres). Sería bueno si puedes proporcionar más información. –

+0

Saludos por el comentario, pregunta actualizada. – MrEyes

Respuesta

5

Uso:

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') 

de salida:

<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') 
+0

Eso funciona a la perfección, solo una pequeña pregunta sobre cómo voy a modificar eso para que esté seleccionando de tablas en lugar de vars declarados. – MrEyes

+0

@MrEyes, actualicé mi respuesta. –

1

Ejemplo con tablas:

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