[sql] T-SQL에서 동등한 함수 분할?

‘1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 …'(쉼표로 구분)를 테이블 또는 테이블 변수로 분할하려고합니다. .

누구든지 각 행을 하나씩 반환하는 함수가 있습니까?



답변

다음은 다소 구식 해결책입니다.

/*
    Splits string into parts delimitered with specified character.
*/
CREATE FUNCTION [dbo].[SDF_SplitString]
(
    @sString nvarchar(2048),
    @cDelimiter nchar(1)
)
RETURNS @tParts TABLE ( part nvarchar(2048) )
AS
BEGIN
    if @sString is null return
    declare @iStart int,
            @iPos int
    if substring( @sString, 1, 1 ) = @cDelimiter
    begin
        set @iStart = 2
        insert into @tParts
        values( null )
    end
    else
        set @iStart = 1
    while 1=1
    begin
        set @iPos = charindex( @cDelimiter, @sString, @iStart )
        if @iPos = 0
            set @iPos = len( @sString )+1
        if @iPos - @iStart > 0
            insert into @tParts
            values  ( substring( @sString, @iStart, @iPos-@iStart ))
        else
            insert into @tParts
            values( null )
        set @iStart = @iPos+1
        if @iStart > len( @sString )
            break
    end
    RETURN

END

SQL Server 2008에서는 .NET 코드를 사용하여 동일한 결과를 얻을 수 있습니다. 어쩌면 더 빨리 작동 할 수도 있지만 분명히이 접근법은 관리하기가 더 쉽습니다.


답변

이 시도

DECLARE @xml xml, @str varchar(100), @delimiter varchar(10)
SET @str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15'
SET @delimiter = ','
SET @xml = cast(('<X>'+replace(@str, @delimiter, '</X><X>')+'</X>') as xml)
SELECT C.value('.', 'varchar(10)') as value FROM @xml.nodes('X') as X(C)

또는

DECLARE @str varchar(100), @delimiter varchar(10)
SET @str = '1,2,3,4,5,6,7,8,9,10,11,12,13,14,15'
SET @delimiter = ','
;WITH cte AS
(
    SELECT 0 a, 1 b
    UNION ALL
    SELECT b, CHARINDEX(@delimiter, @str, b) + LEN(@delimiter)
    FROM CTE
    WHERE b > a
)
SELECT SUBSTRING(@str, a,
CASE WHEN b > LEN(@delimiter)
    THEN b - a - LEN(@delimiter)
    ELSE LEN(@str) - a + 1 END) value
FROM cte WHERE a > 0

쉼표로 구분 된 문자열을 분할하는 방법 은 다음과 같습니다 .


답변

이 SQL Server 2008에 태그를 지정했지만 나중에이 질문에 대한 방문자 (SQL Server 2016 이상 사용)에 대해 알고 싶어 할 것 STRING_SPLIT입니다.

이 새로운 내장 기능을 사용하면 이제 바로 사용할 수 있습니다

SELECT TRY_CAST(value AS INT)
FROM   STRING_SPLIT ('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15', ',') 

이 기능에 대한 몇 가지 제한 사항과 성능 테스트 결과는 Aaron Bertrand의 블로그 게시물에 있습니다.


답변

이것은 해당 기능에 익숙한 사람들을 위해 .NET과 가장 비슷합니다.

CREATE FUNCTION dbo.[String.Split]
(
    @Text VARCHAR(MAX),
    @Delimiter VARCHAR(100),
    @Index INT
)
RETURNS VARCHAR(MAX)
AS BEGIN
    DECLARE @A TABLE (ID INT IDENTITY, V VARCHAR(MAX));
    DECLARE @R VARCHAR(MAX);
    WITH CTE AS
    (
    SELECT 0 A, 1 B
    UNION ALL
    SELECT B, CONVERT(INT,CHARINDEX(@Delimiter, @Text, B) + LEN(@Delimiter))
    FROM CTE
    WHERE B > A
    )
    INSERT @A(V)
    SELECT SUBSTRING(@Text,A,CASE WHEN B > LEN(@Delimiter) THEN B-A-LEN(@Delimiter) ELSE LEN(@Text) - A + 1 END) VALUE
    FROM CTE WHERE A >0

    SELECT      @R
    =           V
    FROM        @A
    WHERE       ID = @Index + 1
    RETURN      @R
END

SELECT dbo.[String.Split]('121,2,3,0',',',1) -- gives '2'


답변

여기 u가 요청한 스플릿 기능이 있습니다.

CREATE FUNCTION [dbo].[split](
          @delimited NVARCHAR(MAX),
          @delimiter NVARCHAR(100)
        ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
        AS
        BEGIN
          DECLARE @xml XML
          SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'

          INSERT INTO @t(val)
          SELECT  r.value('.','varchar(MAX)') as item
          FROM  @xml.nodes('/t') as records(r)
          RETURN
        END

이 같은 기능을 실행

select * from dbo.split('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15',',')


답변

DECLARE
    @InputString NVARCHAR(MAX) = 'token1,token2,token3,token4,token5'
    , @delimiter varchar(10) = ','

DECLARE @xml AS XML = CAST(('<X>'+REPLACE(@InputString,@delimiter ,'</X><X>')+'</X>') AS XML)
SELECT C.value('.', 'varchar(10)') AS value
FROM @xml.nodes('X') as X(C)

이 응답의 출처 :
http://sqlhint.com/sqlserver/how-to/best-split-function-tsql-delimited


답변

내가 좋아하는 솔루션을 짜고 싶은 유혹을 느낀다. 결과 테이블은 2 개의 열로 구성됩니다. 발견 된 정수의 위치에 대한 PosIdx; 그리고 정수 값.


create function FnSplitToTableInt
(
    @param nvarchar(4000)
)
returns table as
return
    with Numbers(Number) as
    (
        select 1
        union all
        select Number + 1 from Numbers where Number < 4000
    ),
    Found as
    (
        select
            Number as PosIdx,
            convert(int, ltrim(rtrim(convert(nvarchar(4000),
                substring(@param, Number,
                charindex(N',' collate Latin1_General_BIN,
                @param + N',', Number) - Number))))) as Value
        from
            Numbers
        where
            Number <= len(@param)
        and substring(N',' + @param, Number, 1) = N',' collate Latin1_General_BIN
    )
    select
        PosIdx,
        case when isnumeric(Value) = 1
            then convert(int, Value)
            else convert(int, null) end as Value
    from
        Found

기본적으로 1에서 100 사이의 위치 목록으로 재귀 CTE를 사용하여 작동합니다. 100보다 긴 문자열로 작업해야하는 경우 다음과 같이 ‘option (maxrecursion 4000)’을 사용하여이 함수를 호출하십시오.


select * from FnSplitToTableInt
(
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0, ' +
    '9, 8, 7, 6, 5, 4, 3, 2, 1, 0'
)
option (maxrecursion 4000)