1

これは、カンマ区切りの値でいっぱいの varchar を SQL Server の IN 関数に渡す の続きです。

カンマ区切りのテキストを分割したいのですが、カンマの埋め込みを許可する必要があります。

  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
4

3 に答える 3

4

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;
于 2012-05-23T05:59:54.833 に答える
0

これを行うための最良の方法は、関数に埋め込まれたコンマの特殊なケースを定義するためです。分割する場合は、文字列の先頭にある埋め込まれたコンマを確認し、その部分文字列を削除します。

于 2012-05-23T05:21:49.570 に答える