SQL - 使用映射替换字符,没有循环

时间:2017-09-13 13:51:42

标签: sql sql-server

有没有办法使用映射表从字符串中替换SQL Server中的字符,而不使用循环。

我的映射可以像这样:

a => b
b => c
...
z => a

此映射不是静态的,可以更改。 我尝试了https://stackoverflow.com/a/45202933/3161817https://stackoverflow.com/a/13051989/3161817的解决方案,但我最终只有一个字符串,就像'aaaaaaaa'

我目前的解决方案如下:

DECLARE @NextChar NCHAR(1)
DECLARE @Position int = 1
DECLARE @StrLength int = LEN(@str)
DECLARE @Result nvarchar(1000) = ''

WHILE (@Position <= @StrLength)
BEGIN
    SET @NextChar = SUBSTRING(@str, @Position, 1)

    SET @Result = @Result + ISNULL((SELECT ToChar FROM CharMapping
                                    WHERE @NextChar COLLATE Latin1_General_BIN = FromChar COLLATE Latin1_General_BIN
                                ), @NextChar)

    SET @Position= @Position + 1
END

但我正在寻找一种没有循环的可能解决方案。

4 个答案:

答案 0 :(得分:1)

DECLARE @t TABLE(
  src char
 ,dest char
)

INSERT INTO @t VALUES
 ('a', 'b')
,('b', 'c')
,('d', 'e')

DECLARE @TestString nvarchar(100) = 'aabbcdacbezzz';

WITH cte AS(
  SELECT 1 lvl, SUBSTRING(@TestString, 1, 1) AS TestPosChar, SUBSTRING(@TestString, 2, LEN(@TestString)-1) AS TestStringRemain
  UNION ALL
  SELECT lvl + 1, SUBSTRING(TestStringRemain, 1, 1), SUBSTRING(TestStringRemain, 2, LEN(TestStringRemain)-1)
    FROM cte
    WHERE LEN(TestStringRemain) >= 1
)
SELECT @TestString AS OldString
      ,SUBSTRING((SELECT ( '' + ISNULL(t.dest, TestPosChar))
                    FROM cte c
                    LEFT JOIN @t AS t ON t.src = c.TestPosChar
                    ORDER BY lvl
                    FOR XML PATH( '' )
                 ), 1, 1000 ) AS NewString

答案 1 :(得分:0)

我做了这个测试:

setup(
    …
    scripts=["main.py"],
    …
)

答案 2 :(得分:0)

尝试(并展开)以下查询,它使用XML PATH,一个计数表和一个解码表:

    CREATE TABLE #TTMMPP (ORIG CHAR(1), NEWC CHAR(1));
     /* add all values to shift */
      INSERT INTO #TTMMPP VALUES ('a','b'),('b','c'),('c','d'),('d','e'),('e','f')  /*, ....*/
  ;

    /* N as max len of your string */
     CREATE TABLE #TTMMPP2 (N smallint);
     DECLARE @I INT
     DECLARE @ROWS INT    
     SET @I = 1
     SET @ROWS = 1000
     WHILE @I < @ROWS
     BEGIN
     INSERT INTO #TTMMPP2 VALUES (@I)
     SET @I = @I + 1
     END

     ----------------------------------------    
     DECLARE @my_str VARCHAR(100) = 'abcd';

     SELECT  @my_str AS ORIGINAL, 
         (
            SELECT ''+C.NEWC
                    FROM (
                         SELECT N, SUBSTRING( @my_str, N,1) AS X, B.NEWC
                         FROM #TTMMPP2 A
                         INNER JOIN #TTMMPP B ON SUBSTRING(@my_str,A.N,1)= B.ORIG
                         WHERE N<=LEN(@my_str)
                         ) C
                         FOR XML PATH('')
                          ) AS SHIFTED;

输出:

ORIGINAL    SHIFTED
abcd    bcde

更新版本:如果您希望在解码表中找不到“标记”字符,则可以使用此项(对查询稍有更改:LEFT JOIN和COALESCE):

 DECLARE @my_str VARCHAR(100) = 'abcdefg'; 
SELECT  @my_str AS ORIGINAL, 
     (
        SELECT ''+C.NEWC
                FROM (
                     SELECT N, SUBSTRING( @my_str, N,1) AS X, COALESCE(B.NEWC,'*') AS NEWC
                     FROM #TTMMPP2 A
                     LEFT JOIN #TTMMPP B ON SUBSTRING(@my_str,A.N,1)= B.ORIG
                     WHERE N<=LEN(@my_str)                   
                     ) C
                     ORDER BY N
                     FOR XML PATH('')
                      ) AS SHIFTED;

输出(*在解码表中找不到替换字符):

ORIGINAL    SHIFTED
abcdefg bcde***

新更新(添加了上次评论):

SELECT  @my_str AS ORIGINAL, 
     (
        SELECT ''+C.NEWC
                FROM (
                     SELECT N, SUBSTRING( @my_str, N,1) AS X, COALESCE(B.NEWC,SUBSTRING(@my_str,A.N,1)) AS NEWC
                     FROM ##TTMMPP2 A
                     LEFT JOIN #TTMMPP B ON SUBSTRING(@my_str,A.N,1) COLLATE Latin1_General_BIN = B.ORIG COLLATE Latin1_General_BIN
                     WHERE N<=LEN(@my_str)                   
                     ) C
                     ORDER BY N
                     FOR XML PATH('')
                      ) AS SHIFTED

输出:

ORIGINAL    SHIFTED
abcdefgA    bcdeefgA

答案 3 :(得分:0)

SQL Server 2017引入了a TRANSLATE function,它类似于嵌套的REPLACE函数。您没有指定您正在使用的SQL Server版本,所以我不知道这是否是一个选项。

SELECT TRANSLATE(@SourceString, 'abcdefghijklmnopqrstuvwxyz', 'bcdefghijklmnopqrstuvwxyza');