【问题标题】:SQL - Replacing all "ASCII/special characters" in a stringSQL - 替换字符串中的所有“ASCII/特殊字符”
【发布时间】:2023-03-12 03:53:01
【问题描述】:

编辑:我有大约 80 个字符导致我的应用程序出现问题,所以我不想为每个字符硬编码一个 REPLACE。我认为创建一个包含两列“特殊字符”和“替换字符”的单独表会更容易,我将从包含“StringTest”列的原始表中删除这些列。我的目标是弄清楚如何使用字符表来替换字符串表中的字符。

我试图在 SQL Server 中将所有“特殊字符”(即 À、Æ、Ç)替换为“MappedCharacters”(A、AE、C)。我尝试了两种不同的技术,一种使用光标,一种不使用光标,以搜索字符串并将所有特殊字符替换为映射字符。我的每个方法只替换它们与字符串在同一行中的字符。 之前的例子:

num   SpecialCharacter    MappedCharacter    StringTest
 1           À                   A             StringÀÆ
 2           Æ                   AE            ÆStringÆ
 3           Ç                   C             StrÇÀing

之后的示例:

num   SpecialCharacter    MappedCharacter    StringTest
 1           À                   A             StringAÆ
 2           Æ                   AE            AEStringAE
 3           Ç                   C             StrCÀing

首选输出:

num   SpecialCharacter    MappedCharacter    StringTest
 1           À                   A             StringAAE
 2           Æ                   AE            AEStringAE
 3           Ç                   C             StrCAing

所以你可以看到我想替换 StringTest 中的所有“特殊字符”,但只有同一行中的字符被替换。

我还没有完全弄清楚如何做到这一点。

这是我一直在尝试修改的两个 SQL 代码(我只需要一个即可)

第一种方法:

              DECLARE @cASCIINum INT;
              DECLARE @cSpecialChar VARCHAR(50);
              DECLARE @cMappedChar VARCHAR(50);
              DECLARE @cStringTest VARCHAR(50);

              DECLARE @mapCursor as CURSOR;

              SET @mapCursor = CURSOR FOR
              SELECT [ASCIINum]
                    ,[SpecialChar]
                    ,[MappedChar]
                    ,[StringTest]
              FROM [intranet].[dbo].[CharMapTestTab]; 

              OPEN @mapCursor;
              FETCH NEXT FROM @mapCursor INTO @cASCIINum,
                                              @cSpecialChar,
                                              @cMappedChar,
                                              @cStringTest;

                WHILE @@FETCH_STATUS = 0
                BEGIN

                  UPDATE [intranet].[dbo].[CharMapTestTab]
                  SET StringTest = REPLACE(StringTest, SpecialChar, MappedChar)
                  WHERE SpecialChar <> MappedChar

                END

                CLOSE @mapCursor;
                DEALLOCATE @mapCursor;

第二种方法:

            DECLARE @ASCIINum INT = 0

            WHILE (1 = 1) 
            BEGIN  

              SELECT @ASCIINum = ASCIINum
              FROM [intranet].[dbo].[CharMapTestTab]
              WHERE ASCIINum > @ASCIINum 
              ORDER BY ASCIINum

              IF @@ROWCOUNT = 0 BREAK;

                  UPDATE [intranet].[dbo].[CharMapTestTab]
                  SET StringTest = REPLACE(StringTest, SpecialChar, MappedChar)
                  WHERE SpecialChar <> MappedChar


              SELECT TOP 1000 [ASCIINum]
                  ,[SpecialChar]
                  ,[MappedChar]
                  ,[StringTest]
              FROM [intranet].[dbo].[CharMapTestTab]



            END

【问题讨论】:

  • 哪个数据库?甲骨文? SQL 服务器? MySQL?等
  • 您还需要在循环中使用 Fetch Next。就像在 Fetch first while @@FetchStatus = 0 做某事 FetchNext end
  • 这是在 SQL Server Thit Lwin Oo 中
  • 这两个都是光标

标签: sql tsql replace cursor special-characters


【解决方案1】:

试试这个,它比循环更好,因为只有 1 个更新:

-- create test table vc
create table vc(StringTest varchar(20))
insert vc values('StringÀÆ'), ('ÆStringÆ')
go

-- create test table CharacterMapping
create table CharacterMapping(SpecialCharacter char(1), MappedCharacter varchar(2))
insert CharacterMapping values('À', 'A'),('Æ', 'AE'), ('Ç', 'C')
go

--build the varchar for updating
declare @x varchar(max) = 'StringTest'
select @x = 'replace('+@x+', ''' + SpecialCharacter + ''','''+MappedCharacter+''')'  
from CharacterMapping
set @x = 'update vc set StringTest=' + @x +' from vc'

exec (@x)

select * from vc

结果:

StringAAE
AEStringAE

【讨论】:

  • 哇——太酷了!我不知道你可以在一个简单的 SELECT 中递归地构建一个 REPLACE 字符串。不知道可以串起多少个REPLACE命令有什么限制吗?顺便说一句,如果您在示例中使用临时表,则人们更容易运行代码而不会弄乱他们的开发。带表格的数据库... ;-)
【解决方案2】:

我会制作一个单独的映射表,其中包含坏字符及其对应的好字符,每行一组。然后循环遍历该表并对每个字符集进行替换。

DECLARE @map TABLE (
    id INT,
    badChar CHAR,
    goodChar CHAR
)

DECLARE @strings TABLE (
    searchString VARCHAR(50)
)

INSERT INTO @map 
VALUES 
(1, 'y', 'a'),
(2, 'z', 'b')

DECLARE @curRow INT, @totalRows INT
SET @curRow = 1
SELECT @totalRows = COUNT(*) FROM @map

INSERT INTO @strings
VALUES
('zcccyccz'),
('cccyccz')

WHILE @curRow <= @totalRows
BEGIN
    UPDATE @strings 
    SET searchString = REPLACE(searchString, badChar, goodChar) 
    FROM @map 
    WHERE id = @curRow

    SET @curRow = @curRow + 1
END

SELECT * FROM @strings

--Output
--bcccaccb
--cccaccb

【讨论】:

    【解决方案3】:

    了解您的表中有多少行以及您估计有多少行具有“特殊字符”会很有帮助。另外,只有3个特殊字符吗?如果你有 40 个或更少的特殊字符,它可能看起来很荒谬,但我会嵌套尽可能多的 REPLACE() 调用,就像你有特殊字符一样:

    UPDATE YourTable SET YourColumn = REPLACE(
                                      REPLACE(
                                      REPLACE(YourColumn,'Ç','C')
                                      ,'Æ','AE')
                                  ,'À','A')
    

    如果大多数行都有特殊字符,我会跳过任何WHERE。如果只有几行有特殊字符,我会使用 CTE 来识别它们:

    ;WITH AllSpecialRows AS
    (
    SELECT PrimaryKey FROM YourTable WHERE YourColumn LIKE '%À%'
    UNION 
    SELECT PrimaryKey FROM YourTable WHERE YourColumn LIKE '%Æ%'
    UNION 
    SELECT PrimaryKey FROM YourTable WHERE YourColumn LIKE '%Ç%'
    )
    UPDATE y
        SET YourColumn = REPLACE(
                         REPLACE(
                         REPLACE(YourColumn,'Ç','C')
                         ,'Æ','AE')
                         ,'À','A')
        FROM YourTable                  y
            INNER JOIN AllSpecialRows   s ON y.PrimaryKey =s.PrimaryKey
    

    【讨论】:

    • 我可能会使用近 100 个字符,所以我认为使用“特殊字符”和“替换字符”创建一个单独的表会更容易,我将从中删除这些列包含字符串的表。我将根据该场景研究如何替换字符。
    • 即使有 100 个,我也会将它们硬编码在嵌套的 REPLACE() 中。如果这是对表的一次性“修复”,只需完成它,您不需要任何花哨或复杂的东西。
    【解决方案4】:
    update table  
    set column = REPLACE(column,'À','A') 
    where column like ('%À%') 
    update table  
    set column = REPLACE(column,'Æ','AE') 
    where column like ('%Æ%') 
    

    我会把第三个留给你

    或者这样可能更有效

    update table  
    set column = REPLACE(REPLACE(column,'À','A'),'Æ','AE')
    where column like ('%À%') 
       or column like ('%Æ%')
    

    如果你真的想处理一个映射字符列表,那么这不是一个正确的答案

    【讨论】:

    • QA 已经知道如何替换字符。问题是一个示例,可能需要替换一组不同的字符。这可能会随着时间而改变。所以你的解决方案不好。
    • @t-clausen.dk 好的,这是一个没有光标的示例。我喜欢你回答 +1。
    【解决方案5】:

    @t-clausen.dk 回答表变量和临时表,只是为了避免人们用额外的表弄乱他们的开发数据库。

    表变量:

    -- Create test table variable @CharacterMapping
    DECLARE @CharacterMapping TABLE (SpecialCharacter char(1), MappedCharacter varchar(2))
    INSERT @CharacterMapping VALUES('À', 'A'), ('Æ', 'AE'), ('Ç', 'C')
    
    --Build the varchar for updating
    DECLARE @x varchar(max) = 'StringTest'
    SELECT @x = 'replace('+@x+', ''' + SpecialCharacter + ''',''' + MappedCharacter + ''')'  
    FROM @CharacterMapping
    SET @x = 'DECLARE @vc TABLE(StringTest varchar(20));'
            + ' insert @vc values(''StringÀÆ''), (''ÆStringÆ'');'
            + 'update @vc set StringTest=' + @x +' from @vc;' 
            + 'SELECT * FROM @vc;'
    
    Exec (@x)
    GO
    

    带临时表:

    -- Create test temp table #vc
    CREATE TABLE #vc(StringTest varchar(20))
    INSERT #vc VALUES('StringÀÆ'), ('ÆStringÆ')
    
    -- Create test table CharacterMapping
    DECLARE @CharacterMapping TABLE (SpecialCharacter char(1), MappedCharacter varchar(2))
    INSERT @CharacterMapping VALUES('À', 'A'), ('Æ', 'AE'), ('Ç', 'C')
    
    --Build the varchar for updating
    DECLARE @x varchar(max) = 'StringTest'
    SELECT @x = 'replace('+@x+', ''' + SpecialCharacter + ''',''' + MappedCharacter + ''')'  
    FROM @CharacterMapping
    SET @x = 'update #vc set StringTest=' + @x +' from #vc'
    
    -- Execute
    EXEC (@x)
    
    -- Select the results 
    SELECT * FROM #vc;
    
    -- Drop temp table
    DROP TABLE #vc;
    
    GO
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-31
      • 1970-01-01
      • 1970-01-01
      • 2012-11-06
      • 1970-01-01
      • 2014-12-07
      相关资源
      最近更新 更多