Matching ein Attribut zu einem anderen mit XPath / XQuery in SQL server 2008

Betrachten Sie das XML und SQL:

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) 

Ich komme mit:

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

Was ich will, ist die Spalte "Notizen", die auf der Grundlage des @id-Attributs des aktuellen item . Wenn ich [@for=data(@id)] im selector mit [@for=107] ersetze, bekomme ich natürlich den Wert Some notes! in der letzten Platte. Ist es möglich, dies mit XPath / XQuery zu machen, oder bin ich hier den falschen tree? Ich denke, das Problem ist das

Das XML ist ein bisschen peinlich, ja, aber ich kann es nicht wirklich ändern. Ich habe Angst.

Ich habe eine Lösung gefunden, die funktioniert, aber es fühlt sich schrecklich schwer für so etwas.

 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') 

Aktualisieren!

Ich habe es herausgefunden! Ich bin neu bei XQuery aber das funktioniert, also rufe ich es Job gemacht 🙂 Ich habe die Abfrage für die Notizen geändert:

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

Ich würde vorschlagen, dass Sie ein cross apply anstatt zu tun ../ , um einen Elternknoten zu finden. Nach Abfrageplan ist es viel schneller.

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

Sie können sogar die ../ in der flwor mit einem zusätzlichen Kreuz zu entfernen, um etwas mehr zu gewinnen.

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

Vergleicht man die Abfragen gegeneinander, bekomme ich 67% auf deine Abfrage 17% auf meine erste und 16% auf die zweite. Anmerkung: Diese Zahlen geben Ihnen nur einen Hinweis darauf, welche Abfrage tatsächlich in der Realität schneller sein wird. Testen Sie gegen Ihre data, um sicher zu wissen.