SQLSERVER 字符串处理

情景描述:

项目中有个地方需要向数据库中插入几条数据,由此引发的一系列问题~

项目要求:

1、使用存储过程

2、代码和数据库相关业务分离

以下为几种方案:

1、最初的方案是存储过程中插入一条数据,代码中循环调用存储过程进行插入(被PASS,原因是多次调用影响效率)

2、代码中拼接成一条SQL语句,然后传给存储过程,执行一次操作即可(被PASS,要实现业务分离)

3、通过文件批量插入(暂不考虑,因为数据量不大,又考虑文件上传等因素,有点大材小用)

4、确定方案:其实根据两个要求就能确定,只能把数据一次性发给存储过程,然后进行插入。所以需要现在代码中对数据进行拼接,组合成字符串当做参数传给存储过程,然后存储过程反解析,最后进行插入(游标、事务、循环等)

代码中最后传出的字符串格式为:

"1,101,2.35;1,102,2;1,103,3.50"

即1,101,2.35为一组,每一组用;分割,每个组之间用,分割

所以需要在存储过程中进行字符串分割

1、初始方案,直接拆分

DECLARE @arr VARCHAR(128)
DECLARE @Tlist1 VARCHAR(64)
DECLARE @posStart INT
DECLARE @posCur INT
DECLARE @TID INT
 
SET @posStart = 1
SET @posCur = 1
 
SET @arr = '4,401,1;4,402,2;4,403,3;4,404,4'
SET @posCur = CHARINDEX(';',@arr,@posStart)
set @Tlist1=cast (SUBSTRING(@arr,@posStart ,@posCur-@posStart)  as varchar(64))
PRINT @Tlist1 
--二次拆分 4,401,1 拆分为4 401 1
SET @posStart = @posCur
 
WHILE (@posStart+1 < LEN(@arr))
    Begin
       Set  @posCur=CharIndex( ';',@arr, @posStart+1)
       if(@posCur> 0)
       Begin
            set @Tlist1=cast (SUBSTRING(@arr,@posStart+1 ,@posCur-@posStart-1)  as varchar(64))
            PRINT @Tlist1
            --二次拆分
           SET @posStart =  @posCur
      End 
       else
            Break
    End 
set @Tlist1=cast (SUBSTRING(@arr,@posStart+1 ,LEN(@arr)-@posStart+1)  as varchar(64))
PRINT @Tlist1
--二次拆分

遇到问题:

一次拆分(拆分为每组)没问题,但是如果要进行二次拆分(每组拆分为3个)就需要在3个地方再进行一遍,虽然也能解决问题,但是太麻烦并且代码不友好,PASS

2、论坛求助到了一个字符串拆分函数,如下(剩余的方案都是基于这个函数) by吉普赛的歌

IF OBJECT_ID('[dbo].[Fun_String2ToStringArray]') IS NOT NULL 
    DROP FUNCTION [dbo].[Fun_String2ToStringArray]
GO
CREATE FUNCTION [dbo].[Fun_String2ToStringArray](@str NVARCHAR(MAX), @split NVARCHAR(10))
RETURNS @table TABLE ([item] NVARCHAR(max))
AS
BEGIN
    IF LEN(@split) = 0
      BEGIN
        SET @split = N','
      END
  
    DECLARE @xml XML;
    SET @xml = CONVERT(XML, '<x><![CDATA[' + replace(CONVERT(VARCHAR(MAX), @str), @split, ']]></x><x><![CDATA[') + ']]></x>')
  
    INSERT INTO @table
      SELECT item
      FROM   (SELECT c.value('text()[1]', 'nvarchar(4000)') [item]
              FROM   @xml.nodes('/x') t(c)) t
      WHERE  item IS NOT NULL
  
    RETURN
END

select item from dbo.Fun_String2ToStringArray(@stringArr,@split)即可进行一次拆分

然后遇到问题,二次拆分怎么办?游标还是循环呢?

3、期间有人提供了parsename的解决方案 by  IEEE_China

declare @s nvarchar(100)
declare @split nvarchar(10)
set @s='4,401,1;4,402,2;4,403,3;4,404,4'
set @split=';'
 
set @s=REPLACE (@s,',','.')
 
select PARSENAME(item,3) as ColA,
    PARSENAME(item,2) as ColB,
    PARSENAME(item,1) as ColC
 from dbo.Fun_String2ToStringArray(@s,@split)

我自己是挺中意这种方案的,简单高效。不过这个不适合带 . 的字符串,很不幸,我这里有浮点数,扼腕叹息!

4、继续挠头中,挠出了又一个方法

declare @list varchar(50)
set @list=''
    while 1=1
    begin
    /*一级拆分*/
        select top 1 @list=item from (select item from dbo.Fun_String2ToStringArray('4,401,1;4,402,2;4,403,3;4,404,4',';')as list where item>@list order by item 
        if @@ROWCOUNT=0
            break
        /*二级拆分*/
        select item from dbo.Fun_String2ToStringArray(@list,',')
    end

终于得出了最末级的每个元素,欢呼ing,并喝杯水庆祝了下。

然后。。。

这对于最后的插入表来说并没有什么用!

5、在又挠掉仅有的几根头发后,最终方法终于蹒跚而来。原来我只要拆分一级就可以,获取到的集合直接插入到多个字段就行!

declare @list varchar(50)
set @list=''
    while 1=1
    begin
    /*一级拆分*/
        select top 1 @list=item from (select item from dbo.Fun_String2ToStringArray('4,401,1;4,402,2;4,403,3;4,404,4',';')as list where item>@list order by item 
        if @@ROWCOUNT=0
            break
        
        set @Sql = 'insert into table (co1,co2,co3) values (' + @list + ')'
        exec (@Sql)
    end

最后,奉劝各位客官一句:三思而后行!

猜你喜欢

转载自blog.csdn.net/zhao3132453/article/details/81319035
今日推荐