SSMS替换字符串中引号之外的所有逗号

时间:2018-08-09 06:13:52

标签: sql sql-server string ssms

我在SSMS中编写了以下函数,用|||||代替引号之外的任何逗号:

CREATE FUNCTION dbo.fixqualifier (@string nvarchar(max))


returns nvarchar(max)
as begin

DECLARE @STRINGTOPAD NVARCHAR(MAX)
DECLARE @position int = 1,@newstring nvarchar(max) ='',@QUOTATIONMODE INT = 0
WHILE(LEN(@string)>0)
BEGIN

SET @STRINGTOPAD = SUBSTRING(@string,0,IIF(@STRING LIKE '%"%',CHARINDEX('"',@string),LEN(@STRING)))

SET @newstring = @newstring + IIF(@QUOTATIONMODE = 1, REPLACE(@STRINGTOPAD,',','||||'),@STRINGTOPAD)

SET @QUOTATIONMODE = IIF(@QUOTATIONMODE = 1,0,1)
set @string = SUBSTRING(@string,1+IIF(@STRING LIKE '%"%',CHARINDEX('"',@string),LEN(@STRING)),LEN(@string))

END

return @newstring

end

该功能的想法是找到第一个“,替换所有',',然后再切换至报价模式1,以便知道不替换,直到遇到第二个时返回报价模式0”。等等。

例如字符串:

qwer,tyu,io,asd,"edffs,asdfgh","jjkzx",kl

将成为:

qwer||||tyu||||io||||asd||||"edffs,asdfgh"||||"jjkzx"||||kl

它可以按预期工作,但是要进行数千行操作时效率很低。

是否有更好的方法或这样做或至少加快了功能。

2 个答案:

答案 0 :(得分:3)

通过模量

做一个简单的技巧
DECLARE @VAR VARCHAR(100) = 'qwer,tyu,io,asd,"edffs,asdfgh","jjkzx",kl'
    ,@OUTPUT VARCHAR(100) = '';

SELECT @OUTPUT = @OUTPUT + CASE WHEN (LEN(@OUTPUT) - LEN(REPLACE(@OUTPUT, '"', ''))) % 2 = 0
            THEN REPLACE(VAL, ',', '||||') ELSE VAL END
FROM (
    SELECT SUBSTRING(@VAR, NUMBER, 1) VAL
    FROM master.dbo.spt_values
    WHERE type = 'P'
        AND NUMBER BETWEEN 1 AND LEN(@VAR)
    ) A

PRINT @OUTPUT

结果:

qwer||||tyu||||io||||asd||||"edffs,asdfgh"||||"jjkzx"||||kl

通过此LEN(@OUTPUT) - LEN(REPLACE(@OUTPUT, '"', ''))表达式,您将获得"的计数。通过取计数%2的模量,如果even为零,则可以替换逗号,否则将保留它们。

答案 1 :(得分:0)

这使用DelimitedSplit8k并完全避免使用任何RBAR方法(例如WHILE@Variable = @Variable +...(这是RBAR的隐藏形式))。

它首先在引号上分开,然后在逗号不加引号的地方分开。最后,它使用“旧”的STUFFFOR XML PATH方法将字符串重新放回一起:

USE Sandbox;
DECLARE @String varchar(8000) = 'qwer,tyu,io,asd,"edffs,asdfgh","jjkzx",kl';

WITH Splits AS(
    SELECT QS.ItemNumber AS QuoteNumber, CS.ItemNumber AS CommaNumber, ISNULL(CS.Item, '"' + QS.Item + '"') AS DelimitedItem
    FROM dbo.DelimitedSplit8K(@string,'"') QS
         OUTER APPLY (SELECT *
                      FROM dbo.DelimitedSplit8K(QS.Item,',')
                      WHERE QS.ItemNumber % 2 = 1) CS
    WHERE QS.Item <> ',')
SELECT STUFF((SELECT '||||' + S.DelimitedItem
              FROM Splits S
              ORDER BY S.QuoteNumber, S.CommaNumber
              FOR XML PATH('')),1,1,'') AS DelimitedList;

(注意,DelimitedSplit8K不能接受超过8,000个字符。如果您超过了8,000个字符,则SQL Server确实不是正确的工具。STRING_SPLIT不提供顺序位置,因此您应该无法保证重建订单。)