Sql 替换两个分隔符之间的子字符串或直到字符串结束

Sql 替换两个分隔符之间的子字符串或直到字符串结束,sql,sql-server,string,sql-server-2008,Sql,Sql Server,String,Sql Server 2008,在SQLServer2008中的一个过程中,我需要替换两个标识符之间的子字符串。我不知道要替换的完整字符串,或者是否存在第二个标识符 如果终止符标识符不存在,则需要将字符串的结尾视为一个。此外,标识符可以是相同的 DECLARE @startIdenfier VARCHAR(10) = 'the' DECLARE @endIdenfier VARCHAR(10) = 'the' DECLARE @newString VARCHAR(20) = 'new string that' 输

在SQLServer2008中的一个过程中,我需要替换两个标识符之间的子字符串。我不知道要替换的完整字符串,或者是否存在第二个标识符

如果终止符标识符不存在,则需要将字符串的结尾视为一个。此外,标识符可以是相同的

DECLARE @startIdenfier VARCHAR(10) = 'the'
DECLARE @endIdenfier   VARCHAR(10) = 'the'
DECLARE @newString     VARCHAR(20) = 'new string that'
输入/输出示例:

'这是需要应用进程的旧字符串。'-> '这是进程需要应用于的新字符串。'

“这是旧字符串”-> '这是新字符串'

“这是我不喜欢的旧字符串”-> “这是我不喜欢的新字符串

这是一个通用的替换,我还没有找到正确的方法来完成它,因为replace函数不接受索引

编辑:这个社区太棒了。很抱歉,我无法选择多个可接受的解决方案,但我感谢大家的帮助。我将尝试所有已经发布的解决方案,除了已经接受的解决方案外,我还将分别测试和投票。

类似这样的解决方案

DECLARE @initialString   VARCHAR(32) = '1234567890123456789'
DECLARE @startIdentifier VARCHAR(32) = '34'
DECLARE @endIdentifier   VARCHAR(32) = '34'
DECLARE @newString       VARCHAR(32) = 'ABC'


DECLARE @headChars INT = CHARINDEX(@startIdentifier, @initialString, 1)

IF @headChars > 0
  SET @headChars = @headChars + LEN(@startIdentifier) - 1


DECLARE @bodyChars INT = CHARINDEX(@endIdentifier, @initialString, @headChars + 1)

IF @bodyChars > 0
  SET @bodyChars = LEN(@initialString) - @bodyChars + 1


SELECT
  LEFT(@initialString,  @headChars)
  + @newString
  + RIGHT(@initialString, @bodyChars)
例如

'1234567890123456789'
  '34'                => Start @ 1 => Found @  3 => keep chars 1->4
            '34'      => Start @ 5 => Found @ 13 => keep chars 13->end
像这样的

DECLARE @initialString   VARCHAR(32) = '1234567890123456789'
DECLARE @startIdentifier VARCHAR(32) = '34'
DECLARE @endIdentifier   VARCHAR(32) = '34'
DECLARE @newString       VARCHAR(32) = 'ABC'


DECLARE @headChars INT = CHARINDEX(@startIdentifier, @initialString, 1)

IF @headChars > 0
  SET @headChars = @headChars + LEN(@startIdentifier) - 1


DECLARE @bodyChars INT = CHARINDEX(@endIdentifier, @initialString, @headChars + 1)

IF @bodyChars > 0
  SET @bodyChars = LEN(@initialString) - @bodyChars + 1


SELECT
  LEFT(@initialString,  @headChars)
  + @newString
  + RIGHT(@initialString, @bodyChars)
例如

'1234567890123456789'
  '34'                => Start @ 1 => Found @  3 => keep chars 1->4
            '34'      => Start @ 5 => Found @ 13 => keep chars 13->end

你可以这样做:

/*Declare necessary variables*/
DECLARE @startIndex INT
DECLARE @endIndex INT
DECLARE @startReplace INT
DECLARE @lengthReplace INT
DECLARE @replaceString VARCHAR(500)

/*Get the index of the start/end idenfier*/
SELECT @startIndex = CHARINDEX ( @startIdenfier ,  @originalString)
SELECT @endIndex = CHARINDEX ( @startIdenfier ,  @originalString, @startIndex+1)  

/*In case the end idenfier doesn't exist*/
IF @endIndex = 0
    SET @endIndex = LEN(@originalString) + 1

SET @startReplace = @startIndex + len(@startIdenfier)
SET @lengthReplace = @endIndex - @startReplace

SELECT STUFF(@originalString, @startReplace, @lengthReplace, @newString)

你可以这样做:

/*Declare necessary variables*/
DECLARE @startIndex INT
DECLARE @endIndex INT
DECLARE @startReplace INT
DECLARE @lengthReplace INT
DECLARE @replaceString VARCHAR(500)

/*Get the index of the start/end idenfier*/
SELECT @startIndex = CHARINDEX ( @startIdenfier ,  @originalString)
SELECT @endIndex = CHARINDEX ( @startIdenfier ,  @originalString, @startIndex+1)  

/*In case the end idenfier doesn't exist*/
IF @endIndex = 0
    SET @endIndex = LEN(@originalString) + 1

SET @startReplace = @startIndex + len(@startIdenfier)
SET @lengthReplace = @endIndex - @startReplace

SELECT STUFF(@originalString, @startReplace, @lengthReplace, @newString)
全文:

DECLARE @startIdenfier Varchar(10)
SET @startIdenfier = 'the'
DECLARE @endIdenfier Varchar(10)
SET @endIdenfier = 'the'
DECLARE @newString Varchar(100)
SET @newString = 'new string that'

DECLARE @initialString VARCHAR(256) = 'this is the old string that the process needs to be applied on';

DECLARE @startIdx INT;
SET @startIdx = CHARINDEX(@startIdenfier, @initialString, 1) + LEN(@startIdenfier) + 1;

DECLARE @endIdx INT;
SET @endIdx= CHARINDEX(@endIdenfier, @initialString, @startIdx) - 1;
IF @endIdx = -1 SET @endIdx = LEN(@initialString) + 1;

DECLARE @results VARCHAR(256);
SET @results = STUFF(@initialString,  @startIdx, @endIdx - @startIdx, @newString);

SELECT @results
全文:

DECLARE @startIdenfier Varchar(10)
SET @startIdenfier = 'the'
DECLARE @endIdenfier Varchar(10)
SET @endIdenfier = 'the'
DECLARE @newString Varchar(100)
SET @newString = 'new string that'

DECLARE @initialString VARCHAR(256) = 'this is the old string that the process needs to be applied on';

DECLARE @startIdx INT;
SET @startIdx = CHARINDEX(@startIdenfier, @initialString, 1) + LEN(@startIdenfier) + 1;

DECLARE @endIdx INT;
SET @endIdx= CHARINDEX(@endIdenfier, @initialString, @startIdx) - 1;
IF @endIdx = -1 SET @endIdx = LEN(@initialString) + 1;

DECLARE @results VARCHAR(256);
SET @results = STUFF(@initialString,  @startIdx, @endIdx - @startIdx, @newString);

SELECT @results

我认为您需要合并PATINDEX函数,并使用开始和结束标识符创建模式。这将满足同时存在开始和结束标识符的条件

DECLARE @OldString nvarchar(max)
DECLARE @NewString nvarchar(max)
DECLARE @StartLocation bigint
DECLARE @Pattern nvarchar(200) = '%' + @StartIdentifier + ' % ' + @EndIdentifer + '%'
SELECT @StartLocation = PATINDEX(@Pattern, 'old complete string')
如果找到该模式,则可以通过将“旧完整字符串”替换为子字符串,从@StartLocation+位置@StartIdentifier+1的长度开始。要确定子字符串的长度,需要使用从@StartLocation+长度@StartIdentifier+1开始的旧完整字符串的CHARINDEX来定位@EndIdentifier的位置。从CHARINDEX的结果中减去@StartLocation+StartIdentifier的长度+1

SELECT @OldString = SUBSTRING('complete old string', @StartLocation + LEN(@StartIdentifier) + 1, CHARINDEX(' ' + @EndIdentifier, 'old complete string', @StartLocation + LEN(@StartIdentifier) + 1) - (@StartLocation + LEN(@StartIdentifier) + 1)))
此时,您可以直接进行替换以获得新字符串

SELECT @NewCompleteString = REPLACE('old complete string', @OldString, @NewString)
如果没有“终止符”标识符,则需要 字符串将被视为一个

如果没有找到初始模式,我们将返回搜索@StartIdentifier。为此,您可以重置模式以仅包含@StartIdentifier

SELECT @Pattern = '%' + @StartIdentifier + ' %'
SELECT @StartLocation = PATINDEX(@Pattern, 'old complete string')
如果找到了该模式,则可以将旧字符串替换为从@StartLocation+长度@StartIdentifier+1开始的子字符串,长度为'old complete string'长度-@StartLocation+长度@StartIdentifier+1

SELECT @OldString = SUBSTRING('old complete string', @StartLocation + LEN(@StartIdentifier) + 1, LEN('old complete string') - (@StartLocation + LEN(@StartIdentifier) + 1))
然后你可以替换

SELECT @NewCompleteString = REPLACE('old complete string', @OldString, @NewString)

我认为您需要合并PATINDEX函数,并使用开始和结束标识符创建模式。这将满足同时存在开始和结束标识符的条件

DECLARE @OldString nvarchar(max)
DECLARE @NewString nvarchar(max)
DECLARE @StartLocation bigint
DECLARE @Pattern nvarchar(200) = '%' + @StartIdentifier + ' % ' + @EndIdentifer + '%'
SELECT @StartLocation = PATINDEX(@Pattern, 'old complete string')
如果找到该模式,则可以通过将“旧完整字符串”替换为子字符串,从@StartLocation+位置@StartIdentifier+1的长度开始。要确定子字符串的长度,需要使用从@StartLocation+长度@StartIdentifier+1开始的旧完整字符串的CHARINDEX来定位@EndIdentifier的位置。从CHARINDEX的结果中减去@StartLocation+StartIdentifier的长度+1

SELECT @OldString = SUBSTRING('complete old string', @StartLocation + LEN(@StartIdentifier) + 1, CHARINDEX(' ' + @EndIdentifier, 'old complete string', @StartLocation + LEN(@StartIdentifier) + 1) - (@StartLocation + LEN(@StartIdentifier) + 1)))
此时,您可以直接进行替换以获得新字符串

SELECT @NewCompleteString = REPLACE('old complete string', @OldString, @NewString)
如果没有“终止符”标识符,则需要 字符串将被视为一个

如果没有找到初始模式,我们将返回搜索@StartIdentifier。为此,您可以重置模式以仅包含@StartIdentifier

SELECT @Pattern = '%' + @StartIdentifier + ' %'
SELECT @StartLocation = PATINDEX(@Pattern, 'old complete string')
如果找到了该模式,则可以将旧字符串替换为从@StartLocation+长度@StartIdentifier+1开始的子字符串,长度为'old complete string'长度-@StartLocation+长度@StartIdentifier+1

SELECT @OldString = SUBSTRING('old complete string', @StartLocation + LEN(@StartIdentifier) + 1, LEN('old complete string') - (@StartLocation + LEN(@StartIdentifier) + 1))
然后你可以替换

SELECT @NewCompleteString = REPLACE('old complete string', @OldString, @NewString)
只需使用STUFF和CHARINDEX。算出:

更换开始时的位置+长度的位置 更换结束的位置从上开始的位置参见 并减去位置以计算要替换的字符数

DECLARE @string VARCHAR(100) = 'This is the old string that the process needs to be applied on.'
DECLARE @replace VARCHAR(100) = 'NEW STRING THAT '
DECLARE @delim1 VARCHAR(100) = 'the '
DECLARE @delim2 VARCHAR(100) = 'the '

DECLARE @pos1 INT = CHARINDEX(@delim1, @string) + DATALENGTH(@delim1)
DECLARE @pos2 INT = ISNULL(NULLIF(CHARINDEX(@delim2, @string, @pos1), 0), DATALENGTH(@string) + 1)

SELECT STUFF(@string, @pos1, @pos2 - @pos1, @replace)

-- "This is the NEW STRING THAT the process needs to be applied on."

SET @delim2 = 'xxx'
SET @pos1 = CHARINDEX(@delim1, @string) + DATALENGTH(@delim1)
SET @pos2 = ISNULL(NULLIF(CHARINDEX(@delim2, @string, @pos1), 0), DATALENGTH(@string) + 1)

SELECT STUFF(@string, @pos1, @pos2 - @pos1, @replace)

-- "This is the NEW STRING THAT "
注意:空格应该是搜索分隔符的一部分,而不是逻辑。不应将它们与threfore匹配。

只需使用STUFF和CHARINDEX即可。算出:

更换开始时的位置+长度的位置 更换结束的位置从上开始的位置参见 并减去位置以计算要替换的字符数

DECLARE @string VARCHAR(100) = 'This is the old string that the process needs to be applied on.'
DECLARE @replace VARCHAR(100) = 'NEW STRING THAT '
DECLARE @delim1 VARCHAR(100) = 'the '
DECLARE @delim2 VARCHAR(100) = 'the '

DECLARE @pos1 INT = CHARINDEX(@delim1, @string) + DATALENGTH(@delim1)
DECLARE @pos2 INT = ISNULL(NULLIF(CHARINDEX(@delim2, @string, @pos1), 0), DATALENGTH(@string) + 1)

SELECT STUFF(@string, @pos1, @pos2 - @pos1, @replace)

-- "This is the NEW STRING THAT the process needs to be applied on."

SET @delim2 = 'xxx'
SET @pos1 = CHARINDEX(@delim1, @string) + DATALENGTH(@delim1)
SET @pos2 = ISNULL(NULLIF(CHARINDEX(@delim2, @string, @pos1), 0), DATALENGTH(@string) + 1)

SELECT STUFF(@string, @pos1, @pos2 - @pos1, @replace)

-- "This is the NEW STRING THAT "

注意:空格应该是搜索分隔符的一部分,而不是逻辑。不应该与它们匹配,因此。

您的定义相当稳健,但不幸的是,您需要更加稳健。例如:如果找不到startIdentifier,但找到EndIdentifier,该怎么办
r是什么?如果endIdentifier出现在startIdentifier之前,该怎么办?如果endIdentifier在startIdentifier等之后多次出现,该怎么办?一旦定义好了,开始使用CHARINDEX或类似工具来查找标识符的位置,然后使用子字符串开始选择要保留的位。因为这是正在进行的工作,目前我唯一要讨论的边界情况是endIdentifier是否丢失。其他边缘情况可以忽略。重要提示:如果开始和结束始终相同,请检查是否存在一对,如果只有1、3或11,则会丢失一些东西。在定义中,您是相当稳健的,但不幸的是,您需要更加稳健。例如:如果找不到startIdentifier,但找到endIdentifier,该怎么办?如果endIdentifier出现在startIdentifier之前,该怎么办?如果endIdentifier在startIdentifier等之后多次出现,该怎么办?一旦定义好了,开始使用CHARINDEX或类似工具来查找标识符的位置,然后使用子字符串开始选择要保留的位。因为这是正在进行的工作,目前我唯一要讨论的边界情况是endIdentifier是否丢失。其他边缘情况可以忽略重要提示:如果开始和结束始终相同,请检查是否存在一对,如果只有1个、3个或11个,那么一些东西丢失了,还需要覆盖找不到结束标识符的演员阵容,替换到演员阵容的结尾string@mat没有一个是一堆nullif无法修复的。还需要覆盖找不到结束标识符的强制转换,替换到string@mat没有什么比一堆废话更重要的了无法修复。谢谢您的帮助。A+1在这里和那里需要保留空间,但解决方案非常值得赞赏谢谢您的帮助。A+1在这里和那里需要保留空格,但这个解决方案非常值得注意。也许应该注意的是,这个答案可能会给出意外的结果,因为它当前将1添加到startIdx,并从endIdx中减去1,以保持前后空格对我公平,我在描述代码的注释中说过,加一表示空间,减一表示空间。如果将此代码放入生产系统,保留注释以解释神奇数字1可能是明智的。或者,将空格烘焙成开始/结束分隔符将允许您删除1。应该注意的是,这个答案可能会给出意外的结果,因为它当前将1添加到startIdx,并从endIdx中减去1,以保持前后空格对我公平,我在描述代码的注释中说过,加一表示空间,减一表示空间。如果将此代码放入生产系统,保留注释以解释神奇数字1可能是明智的。或者,将空格烘焙为开始/结束分隔符将允许您删除1