2009-10-09 46 views
6

我在用於存儲xml數據的表中有一個varchar列。是的,我知道有一個我應該使用的xml數據類型,但我認爲這是在xml數據類型可用之前設置的,所以現在我必須使用varchar。 :)在varchar字段中解析SQL Server xml字符串

存儲的數據看起來類似於以下內容:

<xml filename="100100_456_484351864768.zip" 
    event_dt="10/5/2009 11:42:52 AM"> 
    <info user="TestUser" /> 
</xml> 

我需要解析的文件名,以獲得兩個下劃線在這種情況下將是「456」的數字。文件名的第一部分「不應該」改變長度,但中間數字會改變。我需要一個解決方案,如果第一部分的長度發生變化(你知道它會改變,因爲「不應該改變」總是意味着它會改變)。

對於我現在所擁有的,我使用XQuery來提取文件名,因爲我認爲這可能比直接字符串操作更好。我將字符串轉換爲xml來執行此操作,但我不是XQuery專家,所以當然我遇到了問題。我找到了一個XQuery函數(substring-before),但無法使其正常工作(我甚至不確定該函數是否適用於SQL Server)。可能有一個XQuery函數很容易做到這一點,但如果有我不知道它。

所以,我從桌上的文件名類似於下面的查詢:

select CAST(parms as xml).query('data(/xml/@filename)') as p 
from Table1 

從這個我認爲我能夠施放此回字符串,然後做一些instring或charindex函數來計算出下劃線的位置,以便我可以將所有這些內容封裝在子字符串函數中以挑選出我需要的部分。不用太過分,我很確定我最終可以這樣做,但我知道必須有一個更簡單的方法。這種方式會使SQL語句中的一個巨大的不可讀的字段,即使我將它移動到一個函數中,仍然會混淆,試圖找出發生了什麼。

我敢肯定有一個比這更容易,因爲它似乎是簡單的字符串操作。也許有人可以指出我正確的方向。謝謝

+1

什麼版本的SQL Server? – 2009-10-10 01:39:03

+0

對不起,直到現在我纔看到這個評論。我們現在正在使用SQL Server 2008。 – Dusty 2009-10-12 20:53:00

回答

5

您可以使用XQuery此 - 只是改變你的語句:

SELECT 
    CAST(parms as xml).value('(/xml/@filename)[1]', 'varchar(260)') as p 
FROM 
    dbo.Table1 

這就給了你一個VARCHAR(260),長到足以容納任何有效的文件名和路徑 - 現在你有一個字符串,可以在其與SUBSTRING等

馬克工作

+0

我很欣賞你的迴應,但我能夠在我的文章中使用.query替代.value查詢。我一直在尋找解析出文件名的最佳方法。但是,現在我們討論了這個問題,是使用.query還是.value的首選方法? – Dusty 2009-10-12 14:09:16

+1

'query()'返回一個完整的XDM結果樹作爲'XML'數據類型的實例; 'value()'要求您的查詢僅返回一個XDM值,並將其轉換爲某種SQL類型。因此,一般情況下,如果實際需要返回XML文檔或片段,或者至少需要一個節點集,則需要返回前者;對於後者,只需返回單個值即可。 – 2009-10-12 18:37:06

+0

謝謝。這就說得通了。雖然它沒有給你任何觀點,但我贊成你的評論。 :) – Dusty 2009-10-12 20:51:55

1

不幸的是,SQL Server不是一致的XQuery實現 - 相反,它是XQuery spec草稿版本的一個相當有限的子集。它不僅沒有fn:substring-before,它也沒有fn:index-of自己使用fn:substringfn:string-to-codepoints。所以,據我所知,你在這裏遇到了SQL。

+0

+1謝謝,我擔心SQL Server只有XQuery的有限子集。看起來像我將不得不使用SQL Server中的子字符串函數來做到這一點,就像我在想,並且像史蒂夫卡斯回答的那樣。 – Dusty 2009-10-12 14:46:23

4

直接的方法是使用SUBSTRING和CHARINDEX。假設(聰明與否)的文件名的第一部分不改變長度,但你仍然要使用XQuery來查找文件名,這裏是一個簡短的攝製,你想要做什麼:

declare @t table (
    parms varchar(max) 
); 
insert into @t values ('<xml filename="100100_456_484351864768.zip" event_dt="10/5/2009 11:42:52 AM"><info user="TestUser" /></xml>'); 

with T(fName) as (
    select cast(cast(parms as xml).query('data(/xml/@filename)') as varchar(100)) as p 
    from @t 
) 
    select 
    substring(fName,8,charindex('_',fName,8)-8) as myNum 
    from T; 

有是使用其他字符串函數(如REPLACE和PARSENAME或REVERSE)的偷偷摸摸的解決方案,但沒有一個可能更有效或可讀。需要考慮的一種可能性是編寫一個將正則表達式處理帶入SQL的CLR例程。順便說一下,如果你的xml總是這麼簡單,那麼沒有什麼特別的理由可以讓我看到使用XQuery。這裏有兩個查詢會提取你想要的數字。如果你沒有過額外的空白區域控制在你的XML字符串或覆蓋文件名的第一部分將改變長度的可能性,二是更安全:

select 
    substring(parms,23,charindex('_',parms,23)-23) as myNum 
    from @t; 

    select 
    substring(parms,charindex('_',parms)+1,charindex('_',parms,charindex('_',parms)+1)-charindex('_',parms)-1) as myNum 
    from @t; 
+0

+1它看起來像我將不得不做我認爲我會使用SQL Server子字符串來解析它。感謝您的迴應,併爲我完成大部分工作。我想我會創建一個類似於你的第一篇文章的函數,但是在這種情況下,你發佈的第二個代碼示例可以工作,但我寧願使用XQuery在進行字符串操作之前拔出文件名。再次感謝您的幫助,我會將其標記爲答案。 – Dusty 2009-10-12 14:50:01