我在互联网上找到了这个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 is nvarchar(MAX(包含700+个项,但它只返回一个包含280行的表。
这是我提到的XML解决方案。。。
我不清楚您是如何生成@string
变量的,但该方法需要更改。
以<M>
开始@string
,以</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
尝试此函数。。。我没有时间检查你的函数逻辑。。
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