1

我正在尝试构建一个 SQL 查询或过程来从多个表构建一个复杂的 XML 结果。这是在 SQL Server 2008 R2 中。

所以我想要返回的 XML 是

<requests>
  <request>
    <field one/>
    <field two/>
    <person>
      <personinfo/>
      <roleinfo/>
      <addrinfo/>
      <!-- don't want <item> elements here -->
    </person>
    <person>
      <personinfo/>
      <roleinfo/>
      <addrinfo/>
      <!-- don't want <item> elements here -->
    </person>
    <item><iteminfo/></item> <- i want <item> elements to show up here
    <item><iteminfo/></item>
    <item><iteminfo/></item>
  </request>
  <request>
    ...
  </request>
<requests>

我可以让它在没有<item/>行的情况下工作,但是当我尝试将<item/>行加入最终结果时,它将它们加入<person/>元素而不是<request/>元素。这可能是我对连接的理解或使用的问题,但此时我正在踩水。

创建没有<item/>元素的 XML 的 SQL 如下所示。

select actor-fields, person-fields, role-fields, address-fields
into #tempperson from actor
left join person on actor.personid = person.personid
left join address on address.personid = person.personid
left join role on role.personid = person.personid
order by personid

select request-fields
into #tempreq from request
order by requestid

select *
from #tempreq as request
left join #tempperson as person on person.requestid = request.requestid
order by request.requestid
for xml auto, root('requests'), elements;

我需要的是返回所需 XML 的 SQL。如果我向上述 SQL 添加另一个连接,它会在<item/>节点内添加<person/>节点,这不是我想要的。

我读过关于 XML AUTO 的文章,但这些示例没有返回这样的嵌套结构。也许我正在处理这一切都是错误的。对此有何指导?

4

2 回答 2

0

实际上,至少在这种情况下,似乎效果最好的方法是使用XML AUTO, TYPE. 下面是一个非常简单的示例,没有JOINs(这里WHEREs似乎可以解决问题)。(老实说,在我正在处理的实际问题中,我有这个加上JOINs工作还可以,但它的微妙之处JOIN仍然让我感到困惑,特别是当与这类问题结合时。)

CREATE TABLE #Person ( PerID int identity, FullName varchar(20))
CREATE TABLE #Orders ( OrdID int identity, PerID int, OrdDt varchar(32))
CREATE TABLE #Items ( ItemID int identity, OrdID int, IDesc varchar(32), Amt int)
CREATE TABLE #Addresses ( AddrID int identity, PerID int, FullAddr varchar(50))

insert into #Person values ('Brett Doe')
insert into #Person values ('Sandy Sue')
insert into #Orders values (1, '1/1')
insert into #Orders values (1, '3/1')
insert into #Orders values (2, '1/1')
insert into #Orders values (2, '2/1')
insert into #Items values (1, 'Horse', 1000)
insert into #Items values (2, 'Hat', 10)
insert into #Items values (2, 'Boots', 100)
insert into #Items values (3, 'Belt', 20)
insert into #Items values (4, 'Pistol', 500)
insert into #Items values (4, 'Ammo', 100)
insert into #Addresses values (1, '123 Main, Somewhere, TX')
insert into #Addresses values (2, '345 Oak, Somewhere Else, TX')

SELECT Person.PerID
    , FullName
    , (SELECT OrdDt
        , (SELECT IDesc
            , Amt, Items.OrdID
            FROM #Items as Items
            WHERE Items.OrdID = Orders.OrdID
            FOR XML AUTO, TYPE
            )
        FROM #Orders AS Orders
        WHERE Person.PerID = Orders.PerID
        FOR XML AUTO, TYPE, ELEMENTS
    )
    , (SELECT FullAddr
        FROM #Addresses AS Addresses
        WHERE Person.PerID = Addresses.PerID
        FOR XML AUTO, TYPE, ELEMENTS
    )
FROM #Person AS Person
FOR XML AUTO, TYPE, ELEMENTS

DROP TABLE #Person
DROP TABLE #Orders
DROP TABLE #Items
DROP TABLE #Addresses

输出是

<Person>
  <PerID>1</PerID>
  <FullName>Brett Doe</FullName>
  <Orders>
    <OrdDt>1/1</OrdDt>
    <Items IDesc="Horse" Amt="1000" OrdID="1" />
  </Orders>
  <Orders>
    <OrdDt>3/1</OrdDt>
    <Items IDesc="Hat" Amt="10" OrdID="2" />
    <Items IDesc="Boots" Amt="100" OrdID="2" />
  </Orders>
  <Addresses>
    <FullAddr>123 Main, Somewhere, TX</FullAddr>
  </Addresses>
</Person>
<Person>
  <PerID>2</PerID>
  <FullName>Sandy Sue</FullName>
  <Orders>
    <OrdDt>1/1</OrdDt>
    <Items IDesc="Belt" Amt="20" OrdID="3" />
  </Orders>
  <Orders>
    <OrdDt>2/1</OrdDt>
    <Items IDesc="Pistol" Amt="500" OrdID="4" />
    <Items IDesc="Ammo" Amt="100" OrdID="4" />
  </Orders>
  <Addresses>
    <FullAddr>345 Oak, Somewhere Else, TX</FullAddr>
  </Addresses>
</Person>

我通过搜索然后在此处关注链接或相关问题(例如FOR XML EXPLICIT )找到了这一点。

链接的 MSDN 文章FOR XML Query 与 Nested FOR XML Query的比较很有帮助。

于 2013-03-18T16:32:55.980 回答
0

问题在于数据在 XML 中的呈现方式在对其进行建模时具有与常规 SQL 不同的行为。要记住的是,您可以使用“对于 xml 路径...”自己定位节点,但是...如果您要加入一个表,该表使用具有显示子项的关系的连接引用。当您不想要 XML 元素时,SQL 可能会尝试将它们强加给您。如果数据很复杂,您可以通过以下几种方式处理此嵌套问题:

  1. 将其转储到临时表中,从而使任何假设关系 SQL 考虑您的数据。现在它认为这是一个完整的数据集,并且可以随心所欲地使用它。你不关心关系,你把它们扔掉并决定手动建模。

  2. 做嵌套选择该范围到更大的主体。您也可以将嵌套选择放在更大的 xml 正文中。我也用过这个。

试试这个自解压示例:

declare @Person Table ( personID int identity, person varchar(8));

insert into @Person values ('Brett'),('Sean'),('Chad'),('Michael'),('Ray'),('Erik'),('Queyn');

declare @Orders table ( OrderID int identity, PersonID int, Desciption varchar(32), Amount int);

insert into @Orders values (1, 'Shirt', 20),(1, 'Shoes', 50),(2, 'Shirt', 22),(2, 'Shoes', 52),(3, 'Shirt', 20),(3, 'Shoes', 50),(3, 'Hat', 20),(4, 'Shirt', 20),(5, 'Shirt', 20),(5, 'Pants', 30),
(6, 'Shirt', 20),(6, 'RunningShoes', 70),(7, 'Shirt', 22),(7, 'Shoes', 40),(7, 'Coat', 80)

Select 
    p.person as "@Person"
,   o.Desciption as "Order/@Description"
,   o.Amount as "Order/*"
from @Person p
    join @Orders o on p.personID = o.PersonID
for xml path('Person'), root('People')
-- this will present my data nice but you may have more complex data than this

if object_id('tempdb..#Temp') is not null
    drop table #temp

Select 
    p.person 
,   o.Desciption
,   o.Amount
into #Temp
from @Person p
    join @Orders o on p.personID = o.PersonID

Select
    person as "@Person"
,   Desciption as "Order/@Description"
,   Amount as "Orders"
from #Temp
for xml path('Person'), root('People')

对于更复杂的嵌套选择原理,在更大的 xml 生成体中执行 xml。我不记得为什么,但“TYPE”语句基本上告诉 SQL 引擎它可以嵌套。如果您忘记了它并将选择的 xml 嵌套在其他 xml 中,它可能看起来像垃圾。

-- Maybe I need to nest XMl inside of OTHER XML
Select 
    p.person as "@Person"
,   (
    select
        o.Desciption 
    ,   o.Amount
    from @Orders o 
    where o.PersonID = p.personID
    for xml path('Order'), root('Orders'), type
    ) 
from @Person p 
for xml path('Person'), root('People')
于 2013-03-15T22:45:02.793 回答