2017-09-13 56 views
0

有没有一种方法可以使用映射表替换SQL Server中的字符,而不使用循环。SQL - 使用映射替换字符,无循环

我有映射,可以是这样的:

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 

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

+0

我会说你可以创建这个作为UDF – LONG

+0

我应该补充说,任何字符不是在映射表应保持原样。 abcdef-zz => bcdefg-aa 此外,我需要使用COLLATION,以便使用映射正确替换大写/小写。 – pdube

回答

2
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

我做了这个测试:

declare @MyTab table(
letter char 
) 

declare @MyTab2 table(
letter char 
) 

insert into @MyTab 
select substring(a.b, v.number+1, 1) 
from (select 'ABCDEFGHZZZ' b) a 
join master..spt_values v on v.number < len(a.b) 
where v.type = 'P' 

insert into @MyTab2 
select NewLetter 
from (
select case letter when 'Z' then 'A' 
    when 'z' then 'a' 
    else char(ascii(letter)+1) end NewLetter 
from @MyTab 
) MyView 

select stuff(
(select ''+letter from @MyTab2 
for xml path('')),1,0,'') 
1

尝试(扩大)下面的查询,使用XML路径,理货数字表和解码表:

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 
1

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

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

使用SQL 2012. – pdube

+0

@Dan你的意思是TRANSLATE()..你写了REPLACE – etsa

+0

@etsa,是的,谢谢你的收获。 –