2015-01-13 60 views
1

我的目標是SQL字符串在','和'|'上分割sql字符串

'element1|value,element2|value2,element3|value3' 

轉換成

'<element1>value</element1> 
<element2>value2</element1> 
<element3>value3</element1>' 

我的想法是

declare @test as varchar(max) = 'element1|value1,element2|value2,element3|value3' 

SELECT CHARINDEX(',',@test) 

SELECT SUBSTRING(@test,0,CHARINDEX(',',@test)) 

我遇到的問題是,我不是很familar與SQL,是有一個列表功能或我可以用來將它分成3個塊,然後解剖每個塊?

+1

是否必須在SQL中完成? SQL不是爲分割字符串而設計的。有另一個層可以解析嗎? –

+0

@DStanley你不知道我多麼希望這可能是其他地方 – DidIReallyWriteThat

+0

是你想要的輸出每行輸入多行像你的樣本? –

回答

3

可以使用XML功能解析字符串:

;WITH cte AS (SELECT testString = 'element1|value,element2|value2,element3|value3' 
       UNION SELECT 'test,1,2,3' 
      ) 
    ,SplitString AS (SELECT testString, 
          CONVERT(XML,'<String><Section>'+ REPLACE(REPLACE(testString ,'|',','),',', '</Section><Section>') + '</Section></String>') AS xmlString 
         FROM cte 
        )  
SELECT xmlString.value('/String[1]/Section[1]','varchar(100)') AS Col1 
     ,xmlString.value('/String[1]/Section[2]','varchar(100)') AS Col2 
     ,xmlString.value('/String[1]/Section[3]','varchar(100)') AS Col3 
     ,xmlString.value('/String[1]/Section[4]','varchar(100)') AS Col4 
FROM SplitString 

在這裏,我只是改變了你的|,並做好了所有的分裂一舉,但如果它不是全部,甚至對你能做到這一點分兩步進行,首先分拆|,然後分入,

你也可以看看PARSENAME()但它僅限於4個部分,或者你可以創建一個PARSE功能,如:

/******************************************************************************************** 
     Create Parse Function 
********************************************************************************************/ 
CREATE FUNCTION dbo.FN_PARSE(@chunk VARCHAR(4000), @delimiter CHAR(1), @index INT) 
RETURNS VARCHAR(1000) 
AS 
BEGIN 
    DECLARE 
     @curIndex INT = 0, 
     @pos INT = 1, 
     @prevPos INT = 0, 
     @result VARCHAR(1000) 
    WHILE @pos > 0 
    BEGIN 
     SET @pos = CHARINDEX(@delimiter, @chunk, @prevPos); 
     IF(@pos > 0) 
     BEGIN -- Characters between position and previous position 
      SET @result = SUBSTRING(@chunk, @prevPos, @[email protected]) 
     END 
     ELSE 
     BEGIN -- Last Delim 
      SET @result = SUBSTRING(@chunk, @prevPos, LEN(@chunk)) 
     END 
     IF(@index = @curIndex) 
     BEGIN 
      RETURN @result 
     END 
     SET @prevPos = @pos + 1 
     SET @curIndex = @curIndex + 1; 
    END 
    RETURN '' -- Else Empty 
END 

然後被簡稱:

;WITH cte AS (SELECT testString = 'element1|value,element2|value2,element3|value3' 
       UNION SELECT 'test,1,2,3' 
      ) 
SELECT dbo.FN_PARSE(testString ,'|', 0) AS Col1 
     ,dbo.FN_PARSE(testString ,'|', 1) AS Col2 
     ... 
FROM cte 

注意索引該部分在上述函數中以0開始。

我很喜歡目前的XML版本,但沒有做太多的比較測試。

+0

我真的很喜歡這個。另外,將SELECT結束更改爲一個SELECT xmlString.query('/')將返回爲xml文檔,這非常棒。我現在正在尋找組合看起來像一個根節點下的名稱/值對xml文檔 – DidIReallyWriteThat

0

只是有選擇:-),如果最終目標是將輸入字符串轉換爲XML,則可以使用正則表達式替換來執行此操作,並且它不會受限於任何數量的元素:

DECLARE @Sample NVARCHAR(500), 
     @ElementBasedXML NVARCHAR(500), 
     @AttributeBasedXML NVARCHAR(500); 

SELECT @Sample = N'element1|value,element2|value2,element3|value3', 
     @ElementBasedXML = N'<$2>$3</$2>' + NCHAR(10), 
     @AttributeBasedXML = N'<row $2="$3" />' + NCHAR(10); 

SELECT SQL#.RegEx_Replace4k(@Sample, N'(([^|,]+)\|([^|,]+)),?', @ElementBasedXML, 
          -1, 1, Null) AS [ElementBased], 
     SQL#.RegEx_Replace4k(@Sample, N'(([^|,]+)\|([^|,]+)),?', @AttributeBasedXML, 
          -1, 1, Null) AS [AttributeBased]; 

返回:

ElementBased 
------------ 
<element1>value</element1> 
<element2>value2</element2> 
<element3>value3</element3> 

AttributeBased 
-------------- 
<row element1="value" /> 
<row element2="value2" /> 
<row element3="value3" /> 

或者,您也可以拆分在CTE內部的逗號的字符串(給由管道符號分隔的鍵值對的數量不受限制),然後拆分他們的單一的對分隔符:

DECLARE @Sample2 NVARCHAR(500); 

SELECT @Sample = N'element1|value,element2|value2,element3|value3'; 

;WITH kvpairs AS 
(
    SELECT split.SplitVal, 
     CHARINDEX(N'|', split.SplitVal) AS [PipeLocation], 
     LEN(split.SplitVal) AS [PairLength] 
    FROM SQL#.String_Split4k(@Sample2, N',', 1) split 
), pieces AS 
(
    SELECT LEFT(kvpairs.SplitVal, (kvpairs.PipeLocation - 1)) AS [Key], 
     RIGHT(kvpairs.SplitVal, (kvpairs.PairLength - kvpairs.PipeLocation)) 
       AS [Value] 
    FROM kvpairs 
) 
SELECT CONVERT(XML, N'<' + pieces.[Key] + N'>' 
       + pieces.[Value] 
       + N'</' + pieces.[Key] + N'>') 
FROM pieces 
FOR XML PATH(''); 

請注意:

  • 兩個例子都利用SQL#庫,這是SQLCLR功能和特效集合(這是我寫的,但是這裏顯示的功能在免費版本)。

  • RegEx方法沒有問題,因爲在針對表的SELECT語句中使用RegEx方法時,將列作爲要評估的表達式傳遞。 Split/CTE方法需要放入函數(內聯TVF)中,以便通過CROSS APPLY在查詢中使用。

  • 第二個例子,做拆分,不必使用SQLCLR;它可以使用純粹的T-SQL拆分器,使用內聯計數表或XML。

+0

,而我沒有任何問題,不幸的SQL#庫不可用於我。 – DidIReallyWriteThat

+0

@CalvinSmith沒有SQLCLR策略?無論哪種方式,只是想我會提到這種可能性。第二個例子,做拆分,仍然是一個選擇,因爲您可以使用純粹的T-SQL拆分器使用內聯計數表或XML。所以你仍然不會受到元素數量的限制。選項#2不必使用SQLCLR。 –