T-SQL 同时替换字符串中的两个值

Posted

技术标签:

【中文标题】T-SQL 同时替换字符串中的两个值【英文标题】:T-SQL replace two values in a string simultaneously 【发布时间】:2021-10-13 10:28:55 【问题描述】:

我有一大段文本字符串 @originalCommand,我想在其中替换值 $tablelist@dms

目前我设法低于工作,但有些行是重复动作。

SET @originalCommand    = '$tablelist='table_1', $dms='dms_1''

PRINT '*** Original command text:';
PRINT @originalCommand;

--replace variables' values in ps script
SET @replaceStart       = PATINDEX('%$tablelist=''%', @originalCommand) + LEN('$tablelist=''');
SET @replaceLength      = PATINDEX('%''%', SUBSTRING(@originalCommand, @replaceStart, LEN(@originalCommand)));
IF @tableList = ''
    SET @replaceString = CONCAT(@schemaName, '.', @tableName)
ELSE
    SET @replaceString = @tableList;

SET @newCommand         = REPLACE(@originalCommand, SUBSTRING(@originalCommand, @replaceStart, @replaceLength - 1), @replaceString);


SET @replaceStart       = PATINDEX('%$dms=''%', @newCommand) + LEN('$dms=''');
SET @replaceLength      = PATINDEX('%''%', SUBSTRING(@newCommand, @replaceStart, LEN(@newCommand)));
SET @replaceString = @dms;
SET @newCommand         = REPLACE(@newCommand, SUBSTRING(@newCommand, @replaceStart, @replaceLength - 1), @replaceString);

PRINT '';
PRINT '*** New command text:';
PRINT @newCommand;

预期的结果是有效的,但我试图在不重复 replace 代码行的情况下实现它:

SET @dms = 'dms_new';
SET @tableName      = 'table_new';
'$tablelist='table_new', $dms='dms_new''

【问题讨论】:

为什么这必须在 T-SQL 中完成?它的字符串处理是出了名的薄弱,你肯定可以使用其他语言或工具,这会更简单。 【参考方案1】:

您可以利用 SQL Server 的特性,在涉及多行的 select 语句中设置变量值时,可以对变量进行多次更改。

使用此方法,您可以通过向marker“值表”添加条目来进行任意数量的替换。

原始命令文本中的记号可以按任意顺序出现,但每个记号只能出现一次。

declare @sqlCommand nvarchar(100) = '$tablelist=''table_1'', $dms=''dms_1'''
       ,@tableList  nvarchar(100) = 'table_new'
       ,@schemaName nvarchar(100) = 'fu'
       ,@tableName  nvarchar(100) = 'bar'
       ,@dms        nvarchar(100) = 'dms_new'
;

-- Compile a table holding all the info necessary to make the substitutions
declare @swap table (pos int, numChars int, newVal nvarchar(100));

insert into @swap
    select pos.beg,pos.numChars,marker.newVal
    from (values
         ('$tablelist=''',coalesce(nullif(@tableList,''),concat(@schemaName,'.',@tableName)))
        ,(      '$dms=''',@dms)
        -- add more rows here if necessary
         ) marker(token,newVal)
         cross apply (
        select pos.beg
              ,charindex('''',@sqlCommand,pos.beg+1) - pos.beg
        from (values (charindex(marker.token,@sqlCommand) + len(marker.token))) pos(beg)
         ) pos(beg,numChars)
;

/*
   Here's where the magic happens.
   The variable will be updated once for each row in the table.
   Note that we do them from the back of the string to the front,
   so that the string positions remain valid after each substitution.

   And use stuff() rather than replace() to guarantee
   that we make exactly the substitutions we want and no more.
*/
select @sqlCommand = stuff(@sqlCommand,pos,numChars,newVal)
from @swap
order by pos desc
;

print @sqlCommand;

【讨论】:

你真的不应该使用那种聚合方法,它是多行的未定义行为,请参阅dba.stackexchange.com/a/132709/220697。而是使用STRING_AGGFOR XML @Charlieface:我只使用过string_aggfor xml 来连接字符串。你能说明如何使用这两个函数在一个字符串中进行多次替换吗?

以上是关于T-SQL 同时替换字符串中的两个值的主要内容,如果未能解决你的问题,请参考以下文章

t-sql 用户定义函数,用表中的查找替换文本

t-sql 合并两个表并替换空值

替换 T-SQL 中的 Unicode 字符

java中如何同时替换字符串中两个或者多个字符, 例如吧ABCDEF替换成A1C2EF?

同时替换多个值 - 为了将字符串转换为数字

t-sql 替换双引号