SQL server:split string函数只返回字符串的一部分

时间:2014-07-04 17:56:36

标签: sql sql-server string

我在互联网上发现了这个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行的表。

2 个答案:

答案 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