1

複数のテーブルから複雑な XML 結果を作成する SQL クエリまたはプロシージャを作成しようとしています。これは 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/>

要素なしで XML を作成する SQL は<item/>、次のようになります。

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 Compare to Nested FOR XML Queryが役に立ちました。

于 2013-03-18T16:32:55.980 に答える
0

問題は、XML でのデータの表示方法が、モデル化する際に通常の SQL とは異なる独自の動作をすることにあります。覚えておくべきことは、子を示す関係を持つ結合で参照されるテーブルに結合している場合は、「For xml path...」でノードを自分で配置できることです。SQL は、必要のない XML 要素を強制しようとする場合があります。データが複雑な場合、このネストの問題をいくつかの方法で処理できます。

  1. それを一時テーブルにダンプして、データについてSQLが考えた想定された関係をMOOTにします。これで、すべてが 1 つのデータセットであり、必要に応じてそれを処理する機が熟したと見なされます。あなたは関係を気にせず、それらを捨てて、手動でモデル化することにしました。

  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 を実行する入れ子になった select のより複雑な原則について。理由は思い出せませんが、「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 に答える