2012-05-23 2 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에서 2 단계 스플릿을 사용하여 촬영했습니다. 나는 분명히 다른 사람들이 어떻게이 문제에 접근하는지 보는 것에 관심이있다. 이 문자열이 크거나 큰 행 집합을 처리하려는 경우 다른 옵션 (아마도 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

가장 좋은 방법은 함수에 포함 된 쉼표는 특별한 경우를 정의하기 위해이 작업을 수행 할 때를 문자열의 시작 부분에 쉼표가 있는지 검사하고 그 부분 문자열을 제거합니다.

관련 문제