我有这个功能(信用:searchsqlserver):
CREATE FUNCTION dbo.fnSplit(
@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)
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
END
IF LEN(@sInputList)> 0
INSERT INTO @List SELECT @sInputList -- Put the last item in
RETURN
END
GO
它将参数作为字符串和分隔符,并逐个返回分隔元素。
select * from fnSplit('1,22,333', ',') -- returns 1 22 333
我承认我是SQL的新手,我根本无法遵循这个功能背后的整个逻辑。我想要实现的是一个具有第三个参数(索引)的函数,并返回索引提到的位置上的元素。例如:
select * from fnSplit('1 22 333 444 5555 666', ' ' , 2 ) -- 333
select * from fnSplit('1 22 333 444 5555 666', ' ' , 0 ) -- 1
答案 0 :(得分:2)
首先,循环拆分效率不高。
使用索引过滤器的示例
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
使用了UDF
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','||')
答案 1 :(得分:2)
使用多规则表值UDF和循环来解析字符串是非常低效的。 更好的方法:Split strings the right way – or the next best way
无论如何,如果你想调整你的功能,可以为表变量设置IDENTITY
列,然后根据第三个参数进行过滤:
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
的 LiveDemo
强>
答案 2 :(得分:1)
您可以更改分割字符串函数以包含行号:
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