sql - 替换交替出现的子字符串

标签 sql sql-server sql-server-2012

我的输入字符串如下:

  1. A 或 B 或 C 或 D 或 E 或 F
  2. A 或 B 或 C 或 D 或 E 或 F

预期输出:'A 或 B' OR 'C 或 D' OR 'E 或 F'

outputString = '''' + REPLACE(@inputValue COLLATE Latin1_General_CS_AS, ' OR ' COLLATE Latin1_General_CS_AS, ''' OR ''') + ''''

我尝试使用 SQL Replace 函数,上面的语句对于第一个字符串可以正常工作,并且我得到了所需的输出,但是对于第二个字符串,因为我们所有的 OR 都是大写的,所以它失败并返回 'A' OR “B”或“C”或“D”或“E”或“F”

我使用的是 SSMS 15.0。

如何解决这个问题?任何帮助将不胜感激。

最佳答案

这是一个使用 UDF 的解决方案。

该函数将模式上的字符串拆分为结果集。
(与 STRING_SPLIT 函数类似,但具有模式)

FOR XML然后使用技巧从分割的部分构造一个字符串,并添加引号。

DECLARE @vchNewValue VARCHAR(100), @result VARCHAR(100);
SET @vchNewValue = 'A OR B or C OR D or E OR F';

SET @result = LTRIM(RTRIM((
       SELECT
         CASE WHEN match = 1
         THEN ' '+quotename(ltrim(rtrim(replace(value,' OR ',' or ') )),'''')+' ' 
         ELSE UPPER(value)
         END
       FROM dbo.fnPattern_Split(' '+@vchNewValue+' ', ' % OR % ') AS spl
       ORDER BY ordinal
       FOR XML PATH(''), TYPE).value(N'./text()[1]', N'nvarchar(max)')
    ));

SELECT @result AS result;
<表类=“s-表”> <标题> 结果 <正文> “A 或 B”或“C 或 D”或“E 或 F”

测试db<> fiddle here

UDF

使用 PATINDEX 查找字符串中给定模式的每个下一个起始位置。

然后找到该模式仍然有效的最近的结束位置。
所以这有点像正则表达式中的惰性搜索。

然后使用这些位置将零件插入到返回的表中。

CREATE FUNCTION dbo.fnPattern_Split
(
  @str     VARCHAR(MAX),
  @pattern VARCHAR(100)
)
RETURNS @tbl TABLE (
 ordinal INT,
 value VARCHAR(MAX),
 match BIT
)
WITH SCHEMABINDING
AS
BEGIN
  DECLARE @value NVARCHAR(MAX)
        , @splitvalue NVARCHAR(MAX)
        , @startpos INT = 0
        , @endpos INT = 0
        , @ordinal INT = 0
        , @foundend BIT = 0
        , @patminlen INT = ISNULL(NULLIF(LEN(REPLACE(@pattern,'%','')),0),1);
  WHILE (LEN(@str) > 0)
  BEGIN
    
    SET @startpos = ISNULL(NULLIF(PATINDEX('%'+@pattern+'%', @str),0), LEN(@str)+1);
    
    IF @startpos < LEN(@str)
    BEGIN
        SET @foundend = 0;
        SET @endpos = @startpos+@patminlen-1;
        
        WHILE @endpos < LEN(@str) AND @foundend = 0
        BEGIN
          IF SUBSTRING(@str, @startpos, 1+@endpos-@startpos) LIKE @pattern
            SET @foundend = 1;
          ELSE
            SET @endpos += 1;
        END
    END
    ELSE SET @endpos = LEN(@str);
    
    IF @startpos > 1
    BEGIN
      SET @ordinal += 1;
      SET @value = LEFT(@str, @startpos-1);
      INSERT INTO @tbl (ordinal, value, match)
                VALUES (@ordinal, @value, 0);
    END
    
    IF @endpos >= @startpos
    BEGIN
      SET @ordinal += 1;
      SET @splitvalue = SUBSTRING(@str, @startpos, 1+@endpos-@startpos);
      INSERT INTO @tbl (ordinal, value, match)
                VALUES (@ordinal, @splitvalue, 1);
    END
    
    SET @str = SUBSTRING(@str, @endpos+1, LEN(@str));
  END;
  RETURN;
END;

关于sql - 替换交替出现的子字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70797700/

相关文章:

mysql - 内连接如何嵌套?

c# - .Net 开发与 SQLServer 的配对在 ORM 方面有什么优势?

sql - 如何使用 SQL Server 从当前日期减去 30 天

sql-server - 如何在 SQL Server 2012 中自动终止或终止挂起的任务?

mysql - 我有一个Sum(),其中a.name = b.name,我想选择最高的Sum() : How?的名称

mysql - SQL命令根据插入的数据自动创建表

mysql - 如何使用用户lastActivity获取用户空闲了多少分钟?

php - 将 mssql 日期时间对象转换为 PHP 字符串

sql-server - 是否可以使用 SQL Server 空间数据类型生成泰森 (Voronoï) 多边形?

sql - 为什么对具有 blob 的表进行 Select SQL 查询很慢,即使未选择 blob 也是如此?