【问题标题】:Insert multiple grouped xml documents into a single xml document with SQL使用 SQL 将多个分组的 xml 文档插入到单个 xml 文档中
【发布时间】:2023-03-15 22:15:01
【问题描述】:

我有两张桌子

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 实现吗?如果可以,如何实现?

【问题讨论】:

  • Addresses 中预先存在哪些其他内容?
  • @Shnugo 元素等一堆地址相关数据。我对其进行了编辑,因为我认为它与手头的问题无关。

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


【解决方案1】:

您是对的,您一次只能使用.modify() 执行一项操作...

以下代码有一些假设:

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

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

现在我们可以使用修改,一次将所有组合的地址条目插入到一个操作中:

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>

更新地址未嵌套

试试这个:

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>

【讨论】:

  • 这很接近,但是,我需要它的地址不被嵌套。
【解决方案2】:

您绝对正确,您不应该像字符串一样连接 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 中的源,具体取决于您的需要。

【讨论】:

  • 我认为,OP 想要将几个 Address XML 插入到另一个表中预先存在的 Addresses XML 中。你的方法只适用于一张桌子,但是 - 至少据我所知 - 它并没有解决问题......
猜你喜欢
  • 1970-01-01
  • 2018-04-11
  • 2013-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-17
相关资源
最近更新 更多