2012-11-21 201 views
4

我假設我的問題的答案將是簡單的,我不知道自己。下面是這種情況:選擇XML節點作爲屬性

我使用SQL Server 2008 R2中,其中一個表有其中數據被保存在以下格式的XML列:

<Person> 
    <firstName>John</firstName> 
    <lastName>Lewis</lastName> 
</Person> 

Person節點可以有任意數量的兒童安全元素名稱可能不同的節點(事先不知道)。我正在查找一個查詢來返回一個XML,它將所有節點的值作爲屬性。

所以輸出爲上述XML應該是:

<Person firstName="John" lastName="Lewis"/> 

我想不出一個查詢來獲取上述輸出。我不想使用查詢像

Select 
     PersonColumn.value('(/Person/firstName)[1]', 'varchar(100)') AS '@firstName' 
    , PersonColumn.value('(/Person/lastName)[1]', 'varchar(100)') AS '@lastName' 
FROM MyTable 
WHERE MyTable.MyPrimaryKey=1 
FOR XML PATH('Person'), TYPE 

,因爲我不知道會出現什麼節點Person節點下。

+0

你說「* Person節點可以有任何數量的名字可能不同的後代*」。請提供一個例子(具有不同名稱的多個後代),以及您期望的結果。你提供的單一後代的例子是沒有用的。 – RBarryYoung

+0

我的意思是Person節點可能不只有firstName和lastName。它可以有更多的節點,但沒有一個節點會重複,即firstName只會出現一次。我希望這更清楚。 Descendant這個詞可能會讓你感到困惑。我的例子顯示了2個後代人是名字和姓氏。也許更合適的術語應該是兒童節點。 – Wiz

+0

啊,你想知道*元素*的名字是未知的嗎? – RBarryYoung

回答

2

我試圖做到這一點

select 
    PersonColumn.query(' 
     element Person { 
      for $i in /Person/* 
      return attribute {local-name($i)} {string($i)} 
     } 
    ') 
from MyTable 

但事實證明,這是不可能使用動態屬性名

XQuery [MyTable.PersonColumn.query()]: Only constant expressions are supported for the name expression of computed element and attribute constructors.: select PersonColumn.query(' element Person { for $i in /Person/* return attribute {local-name($i)} {string($i)} } ') from MyTable 

所以最好我能到目前爲止做的是

select 
    cast(
     '<Person ' + 
     (
      select 
       PersonColumn.query(' 
       for $i in /Person/* 
       return concat(local-name($i), "=""", data($i), """") 
       ').value('.', 'nvarchar(max)') 
      for xml path('') 
     ) + '/>' 
    as xml) 
from MyTable 

也可以這樣做

select 
    cast(
     '<Person ' + 
     PersonColumn.query(' 
      for $i in /Person/* 
      return concat(local-name($i), "=""", data($i), """") 
     ').value('.', 'nvarchar(max)') + 
     '/>' 
     as xml) 
from MyTable 

但是如果你的數據包含像<>

+1

+1:你的「最好的遠「實際上相當不錯。我的最愛之一,永遠。 – RBarryYoung

+0

這似乎很接近。我會試一試。謝謝 – Wiz

+0

這很好。對於我使用的場景,不會有任何'<' or '>'。謝謝。 – Wiz

0

看起來你基本上要PIVOT上是人節點的直接子元素的名稱某些字符將無法正常工作。如果您必須在TSQL中執行此操作,則必須動態構建查詢。請參閱How do I Pivot on an XML column's attributes in T-SQL以獲取靈感。在這種情況下,pivot表達式也是一個屬性值,而在你的情況下它是一個元素名稱。我覺得有必要指出明顯的 - 這樣的解決方案很可能表現不佳,結果很難消耗(因爲列名和計數是未知的),並可能容易受到SQL注入攻擊的影響,具體取決於上下文。

+1

一個普通的PIVOT不能做到這一點,它只能用一個動態的PIVOT。考慮到你仍然不得不將它從XML碎片化到SQL虛擬表,執行PIVOT,然後將它重新編寫回XML,這裏沒有實際的例子,這裏似乎有太多的手搖。 – RBarryYoung