我在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
它可以按预期工作,但是要进行数千行操作时效率很低。
是否有更好的方法或这样做或至少加快了功能。
答案 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的隐藏形式))。
它首先在引号上分开,然后在逗号不加引号的地方分开。最后,它使用“旧”的STUFF
和FOR 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
不提供顺序位置,因此您应该无法保证重建订单。)