Using T-SQL, return nth delimited element from a string

后端 未结 11 949
半阙折子戏
半阙折子戏 2020-11-22 14:45

I have a need to create a function the will return nth element of a delimited string.

For a data migration project, I am converting JSON audit records stored in a S

相关标签:
11条回答
  • 2020-11-22 15:17

    How about:

    CREATE FUNCTION dbo.NTH_ELEMENT (@Input NVARCHAR(MAX), @Delim CHAR = '-', @N INT = 0)
    RETURNS NVARCHAR(MAX)
    AS
    BEGIN
    RETURN (SELECT VALUE FROM STRING_SPLIT(@Input, @Delim) ORDER BY (SELECT NULL) OFFSET @N ROWS FETCH NEXT 1 ROW ONLY)
    END
    
    0 讨论(0)
  • 2020-11-22 15:17

    I would rather create a temp table with an identity column and fill it up with output from the SPLIT function.

      CREATE TABLE #tblVals(Id INT IDENTITY(1,1), Val NVARCHAR(100))
      INSERT INTO #tblVals (Val)
      SELECT [value] FROM STRING_SPLIT('Val1-Val3-Val2-Val5', '-')
      SELECT * FROM #tblVals
    

    Now you can easily do something like below.

    DECLARE @val2 NVARCHAR(100) = (SELECT TOP 1 Val FROM #tblVals WHERE Id = 2)
    

    See the snapshot below:

    0 讨论(0)
  • 2020-11-22 15:17

    I don't have enough reputation to comment, so I am adding an answer. Please adjust as appropriate.

    I have a problem with Gary Kindel's answer for cases where there is nothing between the two delimiters

    If you do select * from dbo.GetSplitString_CTE('abc^def^^ghi','^',3) you get ghi instead of an empty string

    If you comment out the WHERE LEN([value]) > 0 line, you get the desired result

    0 讨论(0)
  • 2020-11-22 15:18

    you can put this select into UFN. if you need you can customize it for specifying delimiter as well. in that case your ufn will have two input. number Nth and delimiter to use.

        DECLARE @tlist varchar(max)='10,20,30,40,50,60,70,80,90,100'
        DECLARE @i INT=1, @nth INT=3
        While len(@tlist) <> 0
        BEGIN
                IF @i=@nth
                BEGIN
                  select Case when charindex(',',@tlist) <> 0 Then LEFT(@tlist,charindex(',',@tlist)-1)
                              Else @tlist
                        END
                END
    
                  Select @tlist = Case when charindex(',',@tlist) <> 0 Then substring(@tlist,charindex(',',@tlist)+1,len(@tlist))
                              Else ''
                              END
    
                SELECT @i=@i+1
        END
    
    0 讨论(0)
  • 2020-11-22 15:20

    In a rare moment of lunacy I just thought that split is far easier if we use XML to parse it out for us:

    (Using the variables from @Gary Kindel's answer)

    declare @xml xml
    set @xml = '<split><el>' + replace(@list,@Delimiter,'</el><el>') + '</el></split>'
    
    select
        el = split.el.value('.','varchar(max)')
    from  @xml.nodes('/split/el') split(el))
    

    This lists all elements of the string, split by the specified character.

    We can use an xpath test to filter out empty values, and a further xpath test to restrict this to the element we're interested in. In full Gary's function becomes:

    alter FUNCTION dbo.GetSplitString_CTE
    (
       @List       VARCHAR(MAX),
       @Delimiter  VARCHAR(255),
       @ElementNumber int
    )
    RETURNS VARCHAR(max)
    AS
    BEGIN
           -- escape any XML https://dba.stackexchange.com/a/143140/65992  
           set @list = convert(VARCHAR(MAX),(select @list for xml path(''), type));
    
           declare @xml xml
           set @xml = '<split><el>' + replace(@list,@Delimiter,'</el><el>') + '</el></split>'
    
           declare @ret varchar(max)
           set @ret = (select
                  el = split.el.value('.','varchar(max)')
           from  @xml.nodes('/split/el[string-length(.)>0][position() = sql:variable("@elementnumber")]') split(el))
    
           return @ret
    
    END
    
    0 讨论(0)
提交回复
热议问题