2013-10-31 59 views
1

我有一個字典,我在C#中序列化並存儲在MSSQL服務器上的XML列中。序列化的XML如下所示:查詢XML列中的序列化字典

<ArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> 
    <KeyValueOfstringanyType> 
    <Key>code</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">WFR 052</Value> 
    </KeyValueOfstringanyType> 
    <KeyValueOfstringanyType> 
    <Key>type</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">Newsletter</Value> 
    </KeyValueOfstringanyType> 
</ArrayOfKeyValueOfstringanyType> 

最終,我想獲取值,其中密鑰是「代碼」。我採取的第一步是獲取第一個值,而不管關鍵。

SELECT [xml_column].value('(/ArrayOfKeyValueOfstringanyType/KeyValueOfstringanyType/Value)[1]','varchar(255)') as val 
FROM [my_table] 

返回空值。我知道它與命名空間有關,因爲當我嘗試刪除命名空間的同一個查詢時,我得到一個值。我已經看到了一些名稱空間的其他場景,但是我的XML格式有點不同,我正在努力尋找正確的語法。

這裏是我看着另一個問題:

XML Field - Query

回答

2

您所遇到的問題是由於您的XML模式規範。如果XML文檔中的節點是架構的一部分,則在查詢該節點時必須指定該架構。或者,您可以爲模式規範使用通配符。但是,在沒有模式的情況下指定節點名稱不起作用(正如你所經歷的那樣)。

因此,讓我們來看一個例子:

SQL Fiddle

MS SQL Server 2008的架構設置

CREATE TABLE dbo.Tbl(id INT IDENTITY(1,1) PRIMARY KEY CLUSTERED, dict XML); 

INSERT INTO dbo.Tbl(dict) 
VALUES('<ArrayOfKeyValueOfstringanyType xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> 
     <KeyValueOfstringanyType> 
     <Key>code</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">WFR 052</Value> 
     </KeyValueOfstringanyType> 
     <KeyValueOfstringanyType> 
     <Key>type</Key><Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:string">Newsletter</Value> 
     </KeyValueOfstringanyType> 
    </ArrayOfKeyValueOfstringanyType>'); 

dbo.Tbl與剛剛兩列創建一個身份id列和XML的dict列。

爲了讓您的第一個查詢工作,指定使用通配符每個節點的架構:

查詢1:返回

SELECT dict.value('/*:ArrayOfKeyValueOfstringanyType[1]/*:KeyValueOfstringanyType[1]/*:Key[1]','NVARCHAR(MAX)') 
FROM dbo.Tbl; 

導致第一Key

Results

| COLUMN_0 | 
|----------| 
|  code | 

現在,您希望返回Key ='code'處的所有鍵值對的Value節點。你可以在xquery中進行過濾,但我通常更喜歡用SQL進行過濾。爲此,我們首先需要獲取所有對。該XML節點功能會讓我們更接近了一步:

查詢2

SELECT id,key_value.query('.') 
    FROM dbo.Tbl 
CROSS APPLY dict.nodes('/*:ArrayOfKeyValueOfstringanyType/*:KeyValueOfstringanyType') AS N(key_value); 

它返回每一個行KeyValueOfstringanyType節點:

Results

| ID |                                                                          COLUMN_1 | 
|----|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 
| 1 | <p1:KeyValueOfstringanyType xmlns:p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><p1:Key>code</p1:Key><p1:Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="d3p1:string">WFR 052</p1:Value></p1:KeyValueOfstringanyType> | 
| 1 | <p1:KeyValueOfstringanyType xmlns:p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays"><p1:Key>type</p1:Key><p1:Value xmlns:d3p1="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="d3p1:string">Newsletter</p1:Value></p1:KeyValueOfstringanyType> | 

使用那我們可以去KeyValue使用XML.value功能: 查詢3

SELECT id, 
     key_value.value('./*:Key[1]','NVARCHAR(MAX)') AS [key], 
     key_value.value('./*:Value[1]','NVARCHAR(MAX)') AS [value] 
    FROM dbo.Tbl 
CROSS APPLY dict.nodes('/*:ArrayOfKeyValueOfstringanyType/*:KeyValueOfstringanyType') AS N(key_value); 

現在我們必須爲每個鍵值對的行與鍵和在單獨的列的值:

Results

| ID | KEY |  VALUE | 
|----|------|------------| 
| 1 | code | WFR 052 | 
| 1 | type | Newsletter | 

WHERE子句中可以很容易地應用額外的過濾器:

查詢4

WITH KeyValues AS(
SELECT id, 
     key_value.value('./*:Key[1]','NVARCHAR(MAX)') AS [key], 
     key_value.value('./*:Value[1]','NVARCHAR(MAX)') AS [value] 
    FROM dbo.Tbl 
CROSS APPLY dict.nodes('/*:ArrayOfKeyValueOfstringanyType/*:KeyValueOfstringanyType') AS N(key_value) 
) 
SELECT * 
    FROM KeyValues 
WHERE [Key] = 'code'; 

Results

| ID | KEY | VALUE | 
|----|------|---------| 
| 1 | code | WFR 052 | 
+0

這是很清楚的,謝謝。 – emarcee

+0

+1好的詳細答案,仍然我會添加按鍵過濾節點()函數 –

0

塞巴斯蒂安MEINE很好的回答,雖然做這樣的查詢時,我更喜歡以濾除XPATH內部節點的數據( )功能,如下所示:

select 
    a.c.value('*:Value[1]','nvarchar(max)') as [value] 
from Table1 as t 
    outer apply t.Data.nodes(' 
     *:ArrayOfKeyValueOfstringanyType/*:KeyValueOfstringanyType[*:Key="code"]' 
    ) as a(c) 

它通常比解析完整的xml更快,然後通過where子句過濾所需的密鑰。

sql fiddle example