在游标内使用动态 SQL 拆分和更新字符串

Splitting and updating strings using dynamic SQL inside a cursor

下面的代码采用包含分隔文本的单个字段并将其拆分并根据分隔符的数量将其放置在相邻字段中。

Example of the delimited text: OFFR0048|OFFR0046|OFFR0044|OFFR0042|OFFR0040|OFFR0038|OF03993|

代码 运行 很好,但是需要相当长的时间才能完成。

下面这个过程可以更有效地执行吗?

--create procedure variables
declare @CONS varchar(150), @SINGLE varchar(20), @BCC int, @SQLText nvarchar(1000), @Count int
--create cursor
declare String_Split CURSOR for
    select ADD_BARCODE from ADD_BARCODES --where (LEN(ADD_BARCODE) - LEN(REPLACE(ADD_BARCODE,'|',''))) >= 7 

open String_Split --open cursor

fetch next from String_Split INTO @CONS --set cursor to the first row

WHILE @@FETCH_STATUS = 0 --start procedure
begin
  set @BCC = 1 --set the string field to 1
  while LEN(@cons) > 0 --start while there are addition codes to split
  begin
    if CHARINDEX('|',@CONS) > 0 --checks if there are strings to split
    begin --begin compound statement 1
      set @SINGLE = SUBSTRING(@cons,0,CHARINDEX('|',@CONS)) --use delimiter to split the string
      set @SQLText = 'update ADD_BARCODES set ADD_BC' + CAST(@BCC as varchar)+' = 
                      ''' + @SINGLE + ''' WHERE CURRENT OF String_Split' --create dynamic query to update relevant string column  
      exec sp_executesql @SQLText --execute dynamic query
      set @BCC = @BCC + 1 --increment string field with 1
      set @CONS = SUBSTRING(@CONS, LEN(@SINGLE + '|') + 1,len(@CONS)) --set the remaining string to the @cons varianble for further processing
    end --end compound statement 1
    else --if there are not strings to split
    begin --begin compound statement 2
      set @SINGLE = @CONS --set @cons variable equal to the @single variable
      set @CONS = null --execute dynamic query
      set @SQLText = 'update ADD_BARCODES set ADD_BC' + CAST(@BCC as varchar)+' = 
                      ''' + @SINGLE + ''' WHERE CURRENT OF String_Split' --create dynamic query to update relevant string column  
      exec sp_executesql @SQLText --execute dynamic query
    end --end compound statement 2
  end --end while there are addition codes to split
  fetch next from String_Split INTO @CONS --fetch next entry in cursor
end --end procedure

close String_Split --close cursor
deallocate String_Split --deallocate cursor memory

没试过,但可能会快很多:

  1. 首先将数据拆分成行,例如 DelimitedSplit8k
  2. 从数据构建一个枢轴。我假设您的 table 中有固定数量的列,因此您可以使用固定数量的列
  3. 例如在 CTE 中使用数据透视表将数据更新为最终 table。

也许您可以使用解析器函数,然后在一个带有连接的语句中应用您的更新。我怀疑一个更新语句会比构造和执行 7(在这种情况下)

更有效
Declare @DelStr varchar(max) = 'OFFR0048|OFFR0046|OFFR0044|OFFR0042|OFFR0040|OFFR0038|OF03993|'

Select * from [dbo].[udf-Str-Parse](@DelStr,'|') Where Key_Value<>'' Order by 1

Returns

Key_PS  Key_Value
1       OFFR0048
2       OFFR0046
3       OFFR0044
4       OFFR0042
5       OFFR0040
6       OFFR0038
7       OF03993

有数百万种变体(有些 better/some 更糟),但这是我的解析器

CREATE FUNCTION [dbo].[udf-Str-Parse] (@String varchar(max),@delimeter varchar(10))
--Usage: Select * from [dbo].[udf-Str-Parse]('Dog,Cat,House,Car',',')
--       Select * from [dbo].[udf-Str-Parse]('John Cappelletti was here',' ')
--       Select * from [dbo].[udf-Str-Parse]('id26,id46|id658,id967','|')

Returns @ReturnTable Table (Key_PS int IDENTITY(1,1) NOT NULL , Key_Value varchar(max))

As

Begin
   Declare @intPos int,@SubStr varchar(max)
   Set @IntPos = CharIndex(@delimeter, @String)
   Set @String = Replace(@String,@delimeter+@delimeter,@delimeter)
   While @IntPos > 0
      Begin
         Set @SubStr = Substring(@String, 0, @IntPos)
         Insert into @ReturnTable (Key_Value) values (@SubStr)
         Set @String = Replace(@String, @SubStr + @delimeter, '')
         Set @IntPos = CharIndex(@delimeter, @String)
      End
   Insert into @ReturnTable (Key_Value) values (@String)
   Return 
End