2011-12-01 75 views
2

考慮XML和SQL:匹配一個屬性,另一個使用XPath/XQuery的SQL Server 2008中

declare @xml xml = ' 
<root> 
    <person id="11272"> 
     <notes for="107">Some notes!</notes> 
     <item id="107" selected="1" /> 
    </person> 
    <person id="77812"> 
     <notes for="107"></notes> 
     <notes for="119">Hello</notes> 
     <item id="107" selected="0" /> 
     <item id="119" selected="1" /> 
    </person> 
</root>' 

select Row.Person.value('data(../@id)', 'int') as person_id, 
     Row.Person.value('data(@id)', 'int') as item_id, 
     Row.Person.value('data(../notes[@for=data(@id)][1])', 'varchar(max)') as notes 
from @xml.nodes('/root/person/item') as Row(Person) 

我結束了:

person_id item_id  notes 
----------- ----------- ------- 
77812  107   NULL 
77812  119   NULL 
11272  107   NULL 

我要的是 '備註' 欄根據當前item的@id屬性進行拉取。如果我將[@for=data(@id)]替換爲[@for=107],當然我會在最後一條記錄中得到值Some notes!。是否有可能用XPath/XQuery來做到這一點,還是我在這裏咆哮錯誤的樹?我認爲問題在於,

XML是有點尷尬,是的,但我不能真的改變它,我害怕。

我發現了一種可行的解決方案,但對於這樣的事情感覺非常沉重。

select Item.Person.value('data(../@id)', 'int') as person_id, 
     Item.Person.value('data(@id)', 'int') as item_id, 
     Notes.Person.value('text()[1]', 'varchar(max)') as notes 
from @xml.nodes('/root/person/item') as Item(Person) 
     inner join @xml.nodes('/root/person/notes') as Notes(Person) on 
      Notes.Person.value('data(@for)', 'int') = Item.Person.value('data(@id)', 'int') 
      and 
      Notes.Person.value('data(../@id)', 'int') = Item.Person.value('data(../@id)', 'int') 

更新!

我想通了!我在XQuery的新的,但這個工作,所以我給它完成任務:)我改變了查詢的音符:

Item.Person.value(' 
    let $id := data(@id) 
    return data(../notes[@for=$id])[1] 
', 'varchar(max)') as notes 

回答

1

我會建議你做一個cross apply而不是做../找到一個父節點。根據查詢計劃,它要快得多。

select P.X.value('data(@id)', 'int') as person_id, 
     I.X.value('data(@id)', 'int') as item_id, 
     I.X.value('let $id := data(@id) 
        return data(../notes[@for=$id])[1]', 'varchar(max)') as notes 
from @xml.nodes('/root/person') as P(X) 
    cross apply P.X.nodes('item') as I(X) 

,你甚至可以用一個額外的交叉刪除../在FLWOR所適用獲得多一點。

select P.X.value('@id', 'int') as person_id, 
     TI.id as item_id, 
     P.X.value('(notes[@for = sql:column("TI.id")])[1]', 'varchar(max)') as notes 
from @xml.nodes('/root/person') as P(X) 
    cross apply P.X.nodes('item') as I(X) 
    cross apply (select I.X.value('@id', 'int')) as TI(id) 

比較查詢相互之間我的67%在您的查詢17%在我的第一次和16%在第二。注意:這些數字僅僅給你一個關於什麼查詢實際上會更快的暗示。根據您的數據測試以確定地知道。

相關問題