使用SQL将多个分组的xml文档插入到单个xml文档中

时间:2017-04-18 05:18:24

标签: sql sql-server xml tsql xml-dml

我有两张桌子

tmpEntityAddress

EntityId   Address
________   _______
5          <Address />
5          <Address />
7          <Address />

tmpEntityAddresses

EntityId   XML
________   _______
5          <Addresses />
5          <Addresses />

我想将各种地址文档分组并插入第二个表中的单个地址文档。粗略的基本架构看起来像:

<Addresses>
  <Address>
    <Street />
    <PostCode />
  </Address>
  <Address>
    <Street />
    <PostCode />
  </Address>
</Addresses>

我无法完全理解如何使用XML DML语言功能在SQL中执行此操作,例如XML插入等https://docs.microsoft.com/en-us/sql/t-sql/xml/xml-data-modification-language-xml-dml

我在想我可以做以下事情:

update tmpEntityAddresses
set
  XML.modify('insert sql:column("Address") into (/Addresses)[1]'
from
  tmpEntityAddresses
  join #tmpEntityAddresses on tmpEntityAddresses.EntityId = tmpEntityAddress.EntityId

但似乎只从#tmpEntityAddress添加一行,这不是我想要的,因为我需要整个集合。

这可能与SQL有关吗?如果是这样,怎么能实现呢?

2 个答案:

答案 0 :(得分:1)

你是对的,你可以一次只使用.modify()一个动作......

以下代码有一些假设:

  1. 在您的示例中,Addresses中的第二行应该有EntityId=7
  2. 表格XML
  3. 中都有预先存在的内容

    您可以使用可更新的CTE 。此CTE将选择Addresses列,并从Address表中为给定ID添加所有XML的计算列。

    现在我们可以使用modify,一次性在一个动作中插入所有组合的地址条目:

    DECLARE @address TABLE (ID INT,[Address] XML);
    
    INSERT INTO @address VALUES
     (5, N'<Address id="5a" ><Street>Some Street</Street></Address>')
    ,(5, N'<Address id="5b" ><Street>Some Other</Street></Address>')
    ,(7, N'<Address id="7" ><Street>One More</Street></Address>');
    
    DECLARE @addresses TABLE (ID INT,AddrXML XML);
    
    INSERT INTO @addresses VALUES
     (5, N'<Addresses><PreexistingContent>Blah</PreexistingContent></Addresses>')
    ,(7, N'<Addresses><PreexistingContent>Booh</PreexistingContent></Addresses>');
    
    WITH CombinedAddress AS
    (
        SELECT adrs.ID
              ,(
                SELECT adr.[Address]
                FROM @address AS adr
                WHERE adr.ID=adrs.ID
                FOR XML PATH(''),TYPE
               ) AS Combined
              ,adrs.AddrXML
        FROM @addresses AS adrs
    )
    UPDATE CombinedAddress
    SET AddrXML.modify(N'insert sql:column("Combined") as last into (/Addresses)[1]');
    
    SELECT * FROM @addresses 
    

    ID = 5的结果

    <Addresses>
      <PreexistingContent>Blah</PreexistingContent>
      <Address>
        <Address id="5a">
          <Street>Some Street</Street>
        </Address>
      </Address>
      <Address>
        <Address id="5b">
          <Street>Some Other</Street>
        </Address>
      </Address>
    </Addresses>
    

    UPDATE地址未嵌套

    试试这个:

    WITH CombinedAddress AS
    (
        SELECT adrs.ID
              ,(
                SELECT adr.[Address] AS [*]
                FROM @address AS adr
                WHERE adr.ID=adrs.ID
                FOR XML PATH(''),TYPE
               ) AS Combined
              ,adrs.AddrXML
        FROM @addresses AS adrs
    )
    UPDATE CombinedAddress
    SET AddrXML.modify(N'insert sql:column("Combined") as last into (/Addresses)[1]');
    

    结果

    <Addresses>
      <PreexistingContent>Blah</PreexistingContent>
      <Address id="5a">
        <Street>Some Street</Street>
      </Address>
      <Address id="5b">
        <Street>Some Other</Street>
      </Address>
    </Addresses>
    

答案 1 :(得分:0)

你绝对正确,你不应该像字符串一样连接XML。这是通过相关子查询正确完成的方法:

declare @t table (
    Id int not null,
    Address xml not null
);

insert into @t (Id, Address)
values
    (5, N'<Address Val="1" />'),
    (5, N'<Address Val="2" />'),
    (7, N'<Address Val="7" />');


select sq.Id, (
    select t.Address
    from @t t
    where t.Id = sq.Id
    for xml path(''), type, root('Addresses')
    )
from (select distinct i.Id from @t i) sq
order by sq.Id;

您可以根据需要在insertupdate中将结果输出用作来源。