Split function equivalent in T-SQL?

后端 未结 15 1850
深忆病人
深忆病人 2020-11-21 07:23

I’m looking to split \'1,2,3,4,5,6,7,8,9,10,11,12,13,14,15...\' (comma delimited) into a table or table variable.

Does anyone have a function that returns each one

相关标签:
15条回答
  • 2020-11-21 08:03

    This is most like .NET, for those of you who are familiar with that function:

    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'
    
    0 讨论(0)
  • 2020-11-21 08:03

    here is the split function that u asked

    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
    

    execute the function like this

    select * from dbo.split('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15',',')
    
    0 讨论(0)
  • 2020-11-21 08:04
    /* *Object:  UserDefinedFunction [dbo].[Split]    Script Date: 10/04/2013 18:18:38* */
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    ALTER FUNCTION [dbo].[Split]
    (@List varchar(8000),@SplitOn Nvarchar(5))
    RETURNS @RtnValue table
    (Id int identity(1,1),Value nvarchar(100))
    AS
    BEGIN
        Set @List = Replace(@List,'''','')
        While (Charindex(@SplitOn,@List)>0)
        Begin
    
        Insert Into @RtnValue (value)
        Select
        Value = ltrim(rtrim(Substring(@List,1,Charindex(@SplitOn,@List)-1)))
    
        Set @List = Substring(@List,Charindex(@SplitOn,@List)+len(@SplitOn),len(@List))
        End
    
        Insert Into @RtnValue (Value)
        Select Value = ltrim(rtrim(@List))
    
        Return
    END
    go
    
    Select *
    From [Clv].[Split] ('1,2,3,3,3,3,',',')
    GO
    
    0 讨论(0)
  • 2020-11-21 08:04

    You write this function in sql server after that problem will be solved.

    http://csharpdotnetsol.blogspot.in/2013/12/csv-function-in-sql-server-for-divide.html

    0 讨论(0)
  • 2020-11-21 08:05

    This is another version which really does not have any restrictions (e.g.: special chars when using xml approach, number of records in CTE approach) and it runs much faster based on a test on 10M+ records with source string average length of 4000. Hope this could help.

    Create function [dbo].[udf_split] (
        @ListString nvarchar(max),
        @Delimiter  nvarchar(1000),
        @IncludeEmpty bit) 
    Returns @ListTable TABLE (ID int, ListValue nvarchar(1000))
    AS
    BEGIN
        Declare @CurrentPosition int, @NextPosition int, @Item nvarchar(max), @ID int, @L int
        Select @ID = 1,
       @L = len(replace(@Delimiter,' ','^')),
                @ListString = @ListString + @Delimiter,
                @CurrentPosition = 1 
        Select @NextPosition = Charindex(@Delimiter, @ListString, @CurrentPosition)
       While @NextPosition > 0 Begin
       Set  @Item = LTRIM(RTRIM(SUBSTRING(@ListString, @CurrentPosition, @NextPosition-@CurrentPosition)))
       If      @IncludeEmpty=1 or LEN(@Item)>0 Begin 
         Insert Into @ListTable (ID, ListValue) Values (@ID, @Item)
         Set @ID = @ID+1
       End
       Set  @CurrentPosition = @NextPosition+@L
       Set  @NextPosition = Charindex(@Delimiter, @ListString, @CurrentPosition)
      End
        RETURN
    END
    
    0 讨论(0)
  • 2020-11-21 08:07

    I am tempted to squeeze in my favourite solution. The resulting table will consist of 2 columns: PosIdx for position of the found integer; and Value in integer.

    
    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
    

    It works by using recursive CTE as the list of positions, from 1 to 100 by default. If you need to work with string longer than 100, simply call this function using 'option (maxrecursion 4000)' like the following:

    
    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)
    
    0 讨论(0)
提交回复
热议问题