2013-03-15 100 views
1

我想構建一個SQL查詢或過程來從幾個表中構建一個複雜的XML結果。這是在SQL Server 2008 R2中。SQL和XML和複雜的JOIN

所以我想返回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; 

我需要的是SQL將返回所需的XML。如果我在上面的SQL中添加另一個連接,它會在<person/>節點內添加<item/>節點,這不是我想要的。

我已閱讀過有關XML AUTO的文章,但這些示例不會返回像這樣的嵌套結構。也許我正在談論這一切都是錯誤的。有關於此的任何指導?

+0

你在哪裏選擇項目? – Byron 2013-03-15 21:58:09

+0

對不起@Byron,是的,我在那裏的SQL從我工作的(沒有項目)中得到了。由於我沒有適用於物品的SQL,因此我沒有包含任何物品。我希望,我會編輯更清晰的問題。謝謝。 – 2013-03-16 19:11:39

回答

0

問題在於如何在XML中呈現數據時,它具有與對常規SQL進行建模時不同的行爲。需要記住的是,您可以使用'For xml path ...'來定位節點。但是,如果您正在加入一個表格,並且該表格會與具有顯示子項的關係的聯接一起引用。當你不需要它們時,SQL可能試圖強制你的XML元素。如果數據是複雜的,你可以有幾種方法解決這個問題的嵌套:

  1. 它轉儲到一個臨時表從而使MOOT任何ASSUMED關係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') 
+0

謝謝。但是,我在SQL Server中工作,而你的腳本沒有。我沒有修改插入,但它抱怨'SELECT AS'#Person'' – 2013-03-16 20:01:07

+0

你正在別名臨時表'#Person',我在那裏做了一個表變量'@Person'。我的代碼應該像在SQL Server 2005,2008或2012中一樣工作。第二部分可以取出代碼部分並在執行插入操作的初始語句後粘貼。關鍵是要知道'for xml path ...'會把東西放在元素中,除非你描述節點樹。選擇「@(something)」表示屬性,「*」表示文本,「path/subpath/...」表示節點。您也可以爲xml語句嵌套多個選項,但您可能需要在其後面添加',type'。 – djangojazz 2013-03-18 02:07:31

0

事實上,這似乎是工作最好的,在這種情況下,至少辦法,就是用的XML AUTO, TYPE變種。作爲一個非常簡單的例子,沒有JOINsWHEREs似乎在這裏做的伎倆),下面。 (老實說,在我正在處理的實際問題中,我有這個加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 Compared to Nested FOR XML Query很有幫助。