如何在SQLServer2008中合并2个XML变量
假设在SQLServer2008中有2个XML变量,其中包含以下XML如何在SQLServer2008中合并2个XML变量,xml,sql-server-2008,tsql,xquery,Xml,Sql Server 2008,Tsql,Xquery,假设在SQLServer2008中有2个XML变量,其中包含以下XML DECLARE @FIRST XML = '<DBPerson> <firstname>John</firstname> <lastname>Bob</lastname> </DBPerson>',
DECLARE @FIRST XML = '<DBPerson>
<firstname>John</firstname>
<lastname>Bob</lastname>
</DBPerson>',
@Second XML = '<FromUI>
<lastname>New Bob</lastname>
<age>39</age>
</FromUI>';
但我不知道如何从这里开始。我知道我必须在某个地方使用sql:column来构建一个表,首先根据AllFields只获取节点名称及其值,然后我可以使用XML路径'DBPerson'来形成最终的XML,但有点不确定sql:column的用法
非常感谢您的帮助
更新:
我将其归结为以下问题:
DECLARE @FIRST XML = '<DBPerson><firstname>John</firstname><lastname>Bob</lastname></DBPerson>',
@Second XML = '<FromUI><lastname>New Bob</lastname><age>39</age></FromUI>';
WITH ALLFields AS
(
SELECT
x.y.value('local-name(.)','varchar(50)') As Element
FROM @Second.nodes('FromUI/*') AS x(y)
UNION
SELECT
x.y.value('local-name(.)','varchar(50)') As Element
FROM @FIRST.nodes('DBPerson/*') AS x(y)
), Filtered AS
(
SELECT
Element
, @FIRST.value('(DBPerson/*[local-name()=sql:column("Element")])[1]','varchar(max)') AS F
, @Second.value('(FromUI/*[local-name()=sql:column("Element")])[1]','varchar(max)') AS S
FROM ALLFields AF
), FinalValues AS
(
SELECT
Element
, CASE
WHEN S IS NULL THEN F
ELSE S
END AS V
FROM Filtered
)
SELECT * FROM FinalValues
这个查询为我提供了一个表,其中包含一列中的所有元素以及另一列中元素的数据。现在,我如何生成最终的XML,如下所示:
WITH ALLFields AS
(
SELECT
x.y.value('local-name(.)','varchar(50)') As Element
FROM @Second.nodes('FromUI/*') AS x(y)
UNION
SELECT
x.y.value('local-name(.)','varchar(50)') As Element
FROM @FIRST.nodes('DBPerson/*') AS x(y)
)
SELECT * FROM ALLFields AF
<DBPerson><firstname>John</firstname><lastname>New Bob</lastname><age>39</age></DBPerson>
比我更了解XML分解的人可能能够在XML分解级别解决这个问题,但在这里,我将对更新的查询执行动态透视。首先,我将把finalvalue写入一个staging表,以便动态SQL可以访问它:
DECLARE @FIRST XML = '<DBPerson><firstname>John</firstname><lastname>Bob</lastname></DBPerson>',
@Second XML = '<FromUI><lastname>New Bob</lastname><age>39</age></FromUI>';
WITH ALLFields AS
(
SELECT
x.y.value('local-name(.)','varchar(50)') As Element
FROM @Second.nodes('FromUI/*') AS x(y)
UNION
SELECT
x.y.value('local-name(.)','varchar(50)') As Element
FROM @FIRST.nodes('DBPerson/*') AS x(y)
), Filtered AS
(
SELECT
Element
, @FIRST.value('(DBPerson/*[local-name()=sql:column("Element")])[1]','varchar(max)') AS F
, @Second.value('(FromUI/*[local-name()=sql:column("Element")])[1]','varchar(max)') AS S
FROM ALLFields AF
), FinalValues AS
(
SELECT
Element
, CASE
WHEN S IS NULL THEN F
ELSE S
END AS V
FROM Filtered
)
SELECT [age],[firstname],[lastname] FROM
FinalValues
PIVOT (
MAX(V)
FOR Element IN ([age],[firstname],[lastname])
) AS p
FOR XML PATH('DBPerson');
/* Commenting out the dynamic piece to show the straight pivot above
SELECT *
INTO FinalValues_Staging
FROM FinalValues;
GO
DECLARE @sql NVARCHAR(MAX)
, @col NVARCHAR(MAX);
SELECT @col = COALESCE(@col, '') + QUOTENAME(Element) + ','
FROM
(
SELECT DISTINCT Element
FROM FinalValues_Staging
) AS x;
SET @col = LEFT(@col, LEN(@col)-1);
SET @sql = N'SELECT <COL> FROM
dbo.FinalValues_Staging
PIVOT (
MAX(V)
FOR Element IN (<COL>)
) AS p
FOR XML PATH(''DBPerson'')';
SET @sql = REPLACE(@sql, '<COL>', @col);
EXEC sp_executeSQL @sql;
PRINT @sql;
GO
-- DROP TABLE FinalValues_Staging
*/
结果:
<DBPerson>
<age>39</age>
<firstname>John</firstname>
<lastname>New Bob</lastname>
</DBPerson>
可以使用XQuery返回序列的第一个元素,例如
DECLARE @first XML = '<DBPerson>
<firstname>John</firstname>
<lastname>Bob</lastname>
</DBPerson>',
@second XML = '<FromUI>
<lastname>New Bob</lastname>
<age>39</age>
</FromUI>';
DECLARE @xml XML
-- Combine the two XMLs
SET @xml = ( SELECT @first AS "*", @second AS "*" FOR XML PATH(''))
SELECT @xml.query('<DBPerson>
{(FromUI/firstname, DBPerson/firstname)[1]}
{(FromUI/lastname, DBPerson/lastname)[1]}
{(FromUI/age, DBPerson/age)[1]}
</DBPerson>
')
我们不需要使用动态SQL字符串生成吗?我打算将返回的xml保存在同一存储过程中的xml变量中,并用该xml更新数据库中的一列。是的,您只需用pivot查询替换最终查询,如我的编辑中所示。同样的结果,只是硬编码的列。但是没有特定的节点列表,如firstname、lastname、age等。。我的意思是带有2个xml的节点名称是动态的。
select isnull(S.N.query('.'),F.N.query('.')) as '*'
from @First.nodes('/DBPerson/*') as F(N)
full outer join @Second.nodes('/FromUI/*') as S(N)
on F.N.value('local-name(.)', 'nvarchar(100)') = S.N.value('local-name(.)', 'nvarchar(100)')
for xml path(''), root('DBPerson')
DECLARE @first XML = '<DBPerson>
<firstname>John</firstname>
<lastname>Bob</lastname>
</DBPerson>',
@second XML = '<FromUI>
<lastname>New Bob</lastname>
<age>39</age>
</FromUI>';
DECLARE @xml XML
-- Combine the two XMLs
SET @xml = ( SELECT @first AS "*", @second AS "*" FOR XML PATH(''))
SELECT @xml.query('<DBPerson>
{(FromUI/firstname, DBPerson/firstname)[1]}
{(FromUI/lastname, DBPerson/lastname)[1]}
{(FromUI/age, DBPerson/age)[1]}
</DBPerson>
')