Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何通过索引从分隔字符串中获取元素?_Sql_Sql Server_Tsql - Fatal编程技术网

Sql 如何通过索引从分隔字符串中获取元素?

Sql 如何通过索引从分隔字符串中获取元素?,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有这个功劳:: 我承认我是SQL新手,我不能完全理解这个函数背后的逻辑。我试图实现的是一个函数,它有第三个参数索引,并返回索引中提到的位置上的元素。例如: select * from fnSplit('1 22 333 444 5555 666', ' ' , 2 ) -- 333 select * from fnSplit('1 22 333 444 5555 666', ' ' , 0 ) -- 1 首先,循环拆分没有效率 带有索引过滤器的示例 返回 没有索引过滤器的示例 返回 使

我有这个功劳::

我承认我是SQL新手,我不能完全理解这个函数背后的逻辑。我试图实现的是一个函数,它有第三个参数索引,并返回索引中提到的位置上的元素。例如:

select * from fnSplit('1 22 333 444 5555 666', ' ' , 2 ) --  333

select * from fnSplit('1 22 333 444 5555 666', ' ' , 0 ) --  1

首先,循环拆分没有效率

带有索引过滤器的示例

返回

没有索引过滤器的示例

返回

使用的UDF


您可以将拆分字符串函数更改为包含行号:

    CREATE FUNCTION dbo.fnSplit2(
    @sInputList VARCHAR(8000)             -- List of delimited items
    , @sDelimiter VARCHAR(8000) = ','     -- delimiter that separates items
 ) RETURNS @List TABLE (item VARCHAR(8000))
     BEGIN
     DECLARE @sItem VARCHAR(8000),
             @RowNumber int

     set @RowNumber = 0

     WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
         BEGIN


             SELECT
             @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,
                @sInputList,0)-1))),
             @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,
                @sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
             IF LEN(@sItem) > 0
                INSERT INTO @List SELECT @sItem, @RowNumber

            set @RowNumber = @RowNumber + 1
         END

     set @RowNumber = @RowNumber + 1

     IF LEN(@sInputList)> 0
     INSERT INTO @List SELECT @sInputList, @RowNumber -- Put the last item in
     RETURN
     END

使用带循环的多状态表值UDF解析字符串效率非常低。 更好的方法:

无论如何,若要调整函数,可以为表变量设置标识列,然后根据第三个参数进行筛选:

CREATE FUNCTION dbo.fnSplit(
    @sInputList VARCHAR(8000)             -- List of delimited items
    , @sDelimiter VARCHAR(8000) = ','     -- delimiter that separates items
    ,@num INT
 ) RETURNS @List TABLE ( item VARCHAR(8000))
     BEGIN
     DECLARE @ListHelper AS TABLE(id INT IDENTITY(1,1), item VARCHAR(8000));
     DECLARE @sItem VARCHAR(8000)
     WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
         BEGIN
         SELECT
         @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,
            @sInputList,0)-1))),
         @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,
            @sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
         IF LEN(@sItem) > 0
            INSERT INTO @ListHelper SELECT @sItem
         END

     IF LEN(@sInputList)> 0
     INSERT INTO @ListHelper SELECT @sInputList -- Put the last item in
     INSERT INTO @List
     SELECT item
     FROM @ListHelper
     WHERE id = @num
     RETURN
     END
 GO

select * from fnSplit('1 22 333 444 5555 666', ' ' , 3 );
--333

如果您是SQL新手,那么首先学习如何正确存储值。带分隔符的字符串不是存储值列表的SQLish方式。我无法完全理解此函数背后的逻辑,使用多状态表值函数解析字符串效率不高。无论如何,要存储值列表,我将使用table/temp table/@table变量DECLARE@array TABLEIntValue INT;插入@array IntValue值10、20;或者xmlex:DECLARE@xxml='1020'@lad2025将它作为一个答案,我将它标记为解决方案
Select * 
 From [dbo].[udf-Str-Parse-8K]('1 22 333 444 5555 666', ' '  )
 Where RetSeq=3
RetSeq  RetVal
3       333
Select * 
 From [dbo].[udf-Str-Parse-8K]('1 22 333 444 5555 666', ' '  )
RetSeq  RetVal
1       1
2       22
3       333
4       444
5       5555
6       666
CREATE FUNCTION [dbo].[udf-Str-Parse-8K] (@String varchar(max),@Delimiter varchar(25))
Returns Table 
As
Return (  
    with   cte1(N)   As (Select 1 From (Values(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) N(N)),
           cte2(N)   As (Select Top (IsNull(DataLength(@String),0)) Row_Number() over (Order By (Select NULL)) From (Select N=1 From cte1 a,cte1 b,cte1 c,cte1 d) A ),
           cte3(N)   As (Select 1 Union All Select t.N+DataLength(@Delimiter) From cte2 t Where Substring(@String,t.N,DataLength(@Delimiter)) = @Delimiter),
           cte4(N,L) As (Select S.N,IsNull(NullIf(CharIndex(@Delimiter,@String,s.N),0)-S.N,8000) From cte3 S)

    Select RetSeq = Row_Number() over (Order By A.N)
          ,RetVal = LTrim(RTrim(Substring(@String, A.N, A.L)))
    From   cte4 A
);
--Orginal Source http://www.sqlservercentral.com/articles/Tally+Table/72993/
--Select * from [dbo].[udf-Str-Parse-8K]('Dog,Cat,House,Car',',')
--Select * from [dbo].[udf-Str-Parse-8K]('John||Cappelletti||was||here','||')
    CREATE FUNCTION dbo.fnSplit2(
    @sInputList VARCHAR(8000)             -- List of delimited items
    , @sDelimiter VARCHAR(8000) = ','     -- delimiter that separates items
 ) RETURNS @List TABLE (item VARCHAR(8000))
     BEGIN
     DECLARE @sItem VARCHAR(8000),
             @RowNumber int

     set @RowNumber = 0

     WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
         BEGIN


             SELECT
             @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,
                @sInputList,0)-1))),
             @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,
                @sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
             IF LEN(@sItem) > 0
                INSERT INTO @List SELECT @sItem, @RowNumber

            set @RowNumber = @RowNumber + 1
         END

     set @RowNumber = @RowNumber + 1

     IF LEN(@sInputList)> 0
     INSERT INTO @List SELECT @sInputList, @RowNumber -- Put the last item in
     RETURN
     END
CREATE FUNCTION dbo.fnSplit(
    @sInputList VARCHAR(8000)             -- List of delimited items
    , @sDelimiter VARCHAR(8000) = ','     -- delimiter that separates items
    ,@num INT
 ) RETURNS @List TABLE ( item VARCHAR(8000))
     BEGIN
     DECLARE @ListHelper AS TABLE(id INT IDENTITY(1,1), item VARCHAR(8000));
     DECLARE @sItem VARCHAR(8000)
     WHILE CHARINDEX(@sDelimiter,@sInputList,0) <> 0
         BEGIN
         SELECT
         @sItem=RTRIM(LTRIM(SUBSTRING(@sInputList,1,CHARINDEX(@sDelimiter,
            @sInputList,0)-1))),
         @sInputList=RTRIM(LTRIM(SUBSTRING(@sInputList,CHARINDEX(@sDelimiter,
            @sInputList,0)+LEN(@sDelimiter),LEN(@sInputList))))
         IF LEN(@sItem) > 0
            INSERT INTO @ListHelper SELECT @sItem
         END

     IF LEN(@sInputList)> 0
     INSERT INTO @ListHelper SELECT @sInputList -- Put the last item in
     INSERT INTO @List
     SELECT item
     FROM @ListHelper
     WHERE id = @num
     RETURN
     END
 GO

select * from fnSplit('1 22 333 444 5555 666', ' ' , 3 );
--333