2016-06-28 74 views
2

從XML數據我旁邊XML:SQL Server 2008中查詢,選擇與參數

SET @MyXML = 
' 
<pairs> 
    <p> 
    <Name>France</Name> 
    <Val>Paris</Val> 
    </p> 
    <p> 
    <Name>England</Name> 
    <Val>London</Val> 
    </p> 
    <p> 
    <Name>Spain</Name> 
    <Val>Madrid</Val> 
    </p> 
</pairs> 
' 

我需要用這種方式從這個XML中獲取數據 - 我已經設置參數「英格蘭」,並獲得「倫敦」。我的代碼是下一個,但它不工作:

SELECT 
    Tab.Col.query('p/.[(Val)[1] cast as xs:string? = "England"]') AS [Capital] 
FROM 
    @MyXML.nodes('//pairs') Tab(Col) 

我想念什麼?謝謝!

回答

2

您的XQuery對象構造不正確。這會得到<p>,其中<name>"England",然後返回<Val>標記。

SELECT 
    Tab.Col.value('((p[Name="England"]/Val/text())[1])', 'varchar(max)') AS [Capital] 
FROM 
    @MyXML.nodes('//pairs') Tab(Col) 
+0

這有效!謝謝!我怎樣才能得到'倫敦',而不是'倫敦'? –

+0

@ViktorUnderoath在幾個答案中指出,您應該使用'.value()'而不是'.query()'。第二個將返回一個(部分)XML樹,第一個返回值就是這個值。如果你只對一個特定的值感興趣,根本就不需要'.nodes()'... – Shnugo

+0

@ViktorUnderoath檢查編輯..如果它工作,PLZ upvote並標記爲答案 –

2

你嘗試有點複雜:

DECLARE @MyXML XML = 
N'<pairs> 
    <p> 
    <Name>France</Name> 
    <Val>Paris</Val> 
    </p> 
    <p> 
    <Name>England</Name> 
    <Val>London</Val> 
    </p> 
    <p> 
    <Name>Spain</Name> 
    <Val>Madrid</Val> 
    </p> 
</pairs>'; 

DECLARE @param NVARCHAR(100)=N'England'; 

SELECT 
    Tab.Col.query('(p[Name=sql:variable("@param")]/Val)[1]') AS [Capital] 
FROM 
    @MyXML.nodes('/pairs') Tab(Col) 

更妙

SELECT 
    p.value('Val[1]','nvarchar(max)') AS [Capital] 
FROM 
    @MyXML.nodes('/pairs/p[Name=sql:variable("@param")]') One(p) 

或者作爲一個襯墊

SELECT @MyXml.value('(/pairs/p[Name=sql:variable("@param")]/Val)[1]','nvarchar(max)') AS [Capital] 
1

你可以做到這一點,即使沒有複雜的XPath查詢,如這個:

select Tab.Col.value('Val[1]', 'nvarchar(max)') AS [Capital] 
from @MyXML.nodes('/pairs/p') as Tab(Col) 
where Tab.Col.value('Name[1]', 'nvarchar(max)') = 'England' 
+0

如果讀取所有節點並在'WHERE'子句中執行過濾器,這將導致大量額外工作。用一個大的XML(或者一次輸入很多條目),性能可能會非常糟糕。 *複雜的XPath查詢*只允許返回所需的元素... – Shnugo

0

您可以在節點路徑中隔離<p>標記並簡化SELECT。 這給所有國家和首都的名單:

SELECT 
    T.c.value('(Name)[1]','nvarchar(100)') AS Country 
,T.c.value('(Val)[1]','nvarchar(100)') AS Capital 
FROM 
    @MyXML.nodes('/pairs/p') T(c) 

的語法是WHERE子句中沒有什麼不同,所以你可以申請一個參數有:

declare @param nvarchar(100) = 'England' 
SELECT 
    T.c.value('(Val)[1]','nvarchar(100)') AS Capital 
FROM 
    @MyXML.nodes('/pairs/p') T(c) 
WHERE T.c.value('(Name)[1]','nvarchar(100)') = @Param 

下面是一個完整的測試腳本這兩者都有。

declare @MyXML xml; 
SET @MyXML = 
' 
<pairs> 
    <p> 
    <Name>France</Name> 
    <Val>Paris</Val> 
    </p> 
    <p> 
    <Name>England</Name> 
    <Val>London</Val> 
    </p> 
    <p> 
    <Name>Spain</Name> 
    <Val>Madrid</Val> 
    </p> 
</pairs> 
' 
SELECT 
    T.c.value('(Name)[1]','nvarchar(100)') AS Country 
,T.c.value('(Val)[1]','nvarchar(100)') AS Capital 
FROM 
    @MyXML.nodes('/pairs/p') T(c) 

declare @param nvarchar(100) = 'England' 
SELECT 
    T.c.value('(Val)[1]','nvarchar(100)') AS Capital 
FROM 
    @MyXML.nodes('/pairs/p') T(c) 
WHERE T.c.value('(Name)[1]','nvarchar(100)') = @Param 
+0

我不會在'WHERE'子句中應用過濾器......如果讀完所有節點並在末尾執行過濾器,它將導致大量額外的工作。用一個大的XML(或者一次輸入很多條目),性能可能會非常糟糕。 – Shnugo

+0

@Shnugo我建議在使用大型XML數據集時,最好的方法是將展平的數據集放到臨時表中,在那裏工作,然後在最後轉換回XML。對於<10k行的套件,這種方法對我來說幾乎是即時的。 – JosephStyons

+0

我同意,如果XML很容易被扁平化,並且您要一次執行幾個步驟。但我不同意,如果你只想讀一次價值。想象一張包含數千個XML的表格,並且我想選擇名稱爲「England」的那些表格。你必須將它們全部弄平,以便過濾一些微小的信息...... – Shnugo