Sql 如何通过索引从分隔字符串中获取元素?
我有这个功劳:: 我承认我是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 首先,循环拆分没有效率 带有索引过滤器的示例 返回 没有索引过滤器的示例 返回 使
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