2012-05-23 108 views
1

這是從Passing a varchar full of comma delimited values to a SQL Server IN function開始的。在SQL Server中拆分帶引號的分隔符的分隔文本

我想分割一些逗號分隔的文字,但我需要允許嵌入的逗號:

DECLARE @text NVARCHAR(1000) = 'abc,def,"ghi,jkl",mno'; 

我期待的結果是:

abc 
    def 
    ghi,jkl 
    mno 

這是我使用的功能分割CSV文本。

它使用一個循環,所以如果性能是一個問題,你可以在這裏使用建議適應它:https://stackoverflow.com/a/878964/482595

CREATE FUNCTION uf_Split 
( 
    @Text NVARCHAR(MAX), 
    @Delimiter CHAR(1), 
    @Quote CHAR(1) 
) 
RETURNS @Result TABLE 
( 
    [Index] INT NOT NULL IDENTITY(1, 1), 
    [Value] NVARCHAR(4000) NULL, 
    [CharPos] INT 
) 
AS 
BEGIN 
    DECLARE @start BIGINT; SET @start = 1 
    DECLARE @end BIGINT; SET @end = 1 

    IF @Text is null 
    BEGIN 
     RETURN 
    END 

    WHILE 1=1 
    BEGIN 
     SET @end = 
      CASE 
       WHEN CHARINDEX(@Quote, @Text, @start) = @start THEN CHARINDEX(@Quote + @Delimiter, @Text, @start + 1) 
       ELSE CHARINDEX(@Delimiter, @Text, @start) 
      END 

     IF ISNULL(@end, 0) = 0 
     BEGIN 
      -- Delimiter could not be found in the remainder of the text: 
      INSERT @Result([Value], [CharPos]) VALUES(SUBSTRING(@Text, @start, DATALENGTH(@Text)), @start) 
      BREAK 
     END 
     ELSE IF (CHARINDEX(@Quote, @Text, @start) = @start) AND (CHARINDEX(@Quote + @Delimiter, @Text, @start + 1) = @end) 
     BEGIN 
      INSERT @Result([Value], [CharPos]) VALUES(SUBSTRING(@Text, @start + 1, @end - @start - 1), @start) 
      SET @start = @end + 2 
     END 
     ELSE 
     BEGIN 
      INSERT @Result([Value], [CharPos]) VALUES(SUBSTRING(@Text, @start, @end - @start), @start) 
      SET @start = @end + 1 
     END 
    END 

    RETURN 
END 
GO 
+0

在大多數語言中這是一個不平凡的主張。使用正則表達式非常困難。您通常最擅長使用專門用於處理分割CSV格式的代碼/函數。這可能是可行的;但它可能不會很有趣。 –

回答

3

我在t-sql中使用了一個兩階段分割的鏡頭。我非常有興趣看看其他人如何接近這一點。如果這些字符串很大,或者如果您想處理大型行集,我會查看其他選項,可能是BULK INSERT或CLR。

declare @data nvarchar(1000) = 'abc,def,"ghi,jkl",mno,"yak","yak,123"'; 


declare @x xml; 
select @x = cast('<d>' + replace(@data, '"', '</d><d>') + '</d>' as xml); 

;with c(d,i) 
as ( select p.n.value('.', 'nvarchar(max)') AS data, 
       case 
        when left(p.n.value('.', 'nvarchar(max)'), 1) = ',' then 1 
        when right(p.n.value('.', 'nvarchar(max)'), 1) = ',' then 1 
        else 0 
       end 
     from @x.nodes('/d') p(n) 
    )  
select d 
from c 
where i = 0 and len(d) > 0 
union all 
select p.n.value('.', 'nvarchar(max)') 
from ( select cast('<d>' + replace(d, ',', '</d><d>') + '</d>' as xml) 
      from c 
      where i=1 
     ) d(x) 
cross 
apply d.x.nodes('/d')p(n) 
where len(p.n.value('.', 'nvarchar(max)')) > 0; 
+0

該解決方案實際上表現比我的解決方案好得多 - 在5秒內拆分17,000個物品。 – sean

+0

如果您將用於基於數字表格的方法(如鏈接中)的XML方法進行了交換,您可能會獲得更好的性能。 –

0

最好的方式做到這一點在你的函數定義特殊情況下嵌入的逗號,當你正在分割檢查字符串開頭的嵌入逗號並刪除該子字符串。