我在互联网上发现了这个SQL分裂字符串函数,但是当我传递一个包含700多个项目的字符串,用逗号分隔时,它只生成一个包含280行的表变量,有些可以帮我识别出问题所在吗?
代码:
ALTER FUNCTION [dbo].[fn_Split](@text nvarchar(MAX), @delimiter varchar(20) = ' ')
RETURNS @Strings TABLE
(
position int IDENTITY PRIMARY KEY,
value nvarchar(MAX)
)
AS
BEGIN
DECLARE @index int
SET @index = -1
WHILE (LEN(@text) > 0)
BEGIN
SET @index = CHARINDEX(@delimiter , @text)
IF (@index = 0) AND (LEN(@text) > 0)
BEGIN
INSERT INTO @Strings VALUES (@text)
BREAK
END
IF (@index > 1)
BEGIN
INSERT INTO @Strings VALUES (LEFT(@text, @index - 1))
SET @text = RIGHT(@text, (LEN(@text) - @index))
END
ELSE
SET @text = RIGHT(@text, (LEN(@text) - @index))
END
RETURN
END
这是我用来测试它的代码:
SELECT * FROM fn_Split(@string,',');
@String是nvarchar(MAX)包含700多个项目,但它只返回一个包含280行的表。
答案 0 :(得分:1)
以下是我提到的XML解决方案......
我不清楚您是如何生成@string
变量的,但该方法需要更改。
使用@string
开始<M>
,并以</M>
结束。然后,不要使用','来分隔您的值,而是使用</M><M>
代替。
我在SSMS中对此进行了测试,通过复制/粘贴我的字符串值并保持粘贴,直到我的行号超过20K。第一个LEN()
实际上返回的长度超过19K。我也在展示xml的datalength()
,这只是为了演示。
我使用此方法处理供应商应用程序数据库中csv类型列中的数据,并将其转换为可用数据列。我也使用了你上面显示的方法。这种方法比我尝试过的任何其他方法都要快得多。
编辑:如果这没有帮助 - 告诉我们更多。你是如何生成这个@string的,也许我们可以提出一个比在csv字符串中填充更好的选项。
希望这有帮助,这里是:
DECLARE @string XML
SET @string = '<M>hello</M><M>world</M><M>hello</M><M>world</M><M>hello</M><M>world</M>'
SELECT LEN(CAST(@string AS NVARCHAR(MAX)))
SELECT DATALENGTH(@string)
SELECT Split.a.value('.', 'VARCHAR(MAX)') AS StringVal
FROM (SELECT @string AS String) AS A
CROSS APPLY String.nodes ('/M') AS Split(a)
--WHERE LEN(Split.a.value('.', 'VARCHAR(MAX)'))>1
如果您的原始变量是VARCHAR,以防其他人在将来遇到此答案,那么它是如何工作的。
declare @string2 varchar(max)
set @string2 = 'hello,world,hello,world,hello,world'
SELECT Split.a.value('.', 'VARCHAR(max)') AS String
FROM (SELECT CAST ('<M>' + REPLACE(CAST(@string2 AS VARCHAR(MAX)), ',', '</M><M>') + '</M>' AS XML) AS String) AS A
CROSS APPLY String.nodes ('/M') AS Split(a)
--WHERE LEN(Split.a.value('.', 'VARCHAR(max)'))>1
如果您在列中持有csv,则使用以下内容:
SELECT DISTINCT A.UserID,
Split.a.value('.', 'VARCHAR(max)') AS String
FROM (SELECT UserID,
CAST ('<M>' + REPLACE(CAST(someCSVListColumn AS VARCHAR), ',', '</M><M>') + '</M>' AS XML) AS String
FROM #someTable) AS A
CROSS APPLY String.nodes ('/M') AS Split(a)
--WHERE LEN(Split.a.value('.', 'VARCHAR(max)'))>1
答案 1 :(得分:0)
试试这个功能...... 我没时间检查你的功能逻辑..
Create FUNCTION [dbo].[UDF_Split](@String varchar(8000), @Delimiter char(1))
returns @temptable TABLE (ID int Identity(1,1),Value varchar(8000))
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(Value) values(@slice)
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end