反转字符串的字符而不改变 T-SQL 中数值的位置

ann*_*nna 3 sql-server t-sql string

使用 T-SQL,我试图找到最简单的方法来反转字符串的字符而不改变数值的位置。

所以对于字符串:

abc223de11 
Run Code Online (Sandbox Code Playgroud)

edc223ba11
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 7

我对此并不感到自豪,但您可以在 T-SQL 中做到这一点。这个内联表值函数将字符串分解为一组字符,并将行号仅应用于字符串值,以便您可以颠倒设置。

CREATE FUNCTION dbo.SortString
(
  @s varchar(64)
)
RETURNS TABLE WITH SCHEMABINDING
AS
  RETURN 
  ( -- get a sequence number for every character in @s
    WITH n AS 
    (
      SELECT n = 1 UNION ALL SELECT n + 1 FROM n WHERE n < LEN(@s)
    ),
    s AS 
    ( -- break out each character, apply sequence number, test numeric
      SELECT n, s = SUBSTRING(@s, n, 1), isn = ISNUMERIC(SUBSTRING(@s, n, 1))
      FROM n
    ),
    s2 AS
    ( -- apply reverse match pointers, but only for strings
      SELECT n,s, 
        rn1 = CASE WHEN isn = 0 THEN ROW_NUMBER() OVER 
              (PARTITION BY isn ORDER BY n ASC) END,
        rn2 = CASE WHEN isn = 0 THEN ROW_NUMBER() OVER 
              (PARTITION BY isn ORDER BY n DESC) END
      FROM s
    )
    SELECT s2.n, New = COALESCE(s3.s, s2.s), Original = s2.s
        FROM s2 LEFT OUTER JOIN s2 AS s3
        ON s2.rn2 = s3.rn1
  );
GO
Run Code Online (Sandbox Code Playgroud)

以下调用:

DECLARE @str varchar(64) = 'abc223de11'; 
SELECT Original, New FROM dbo.SortString(@str) ORDER BY n;
Run Code Online (Sandbox Code Playgroud)

产生以下结果:

Original  New
--------  ---
a         e
b         d
c         c
2         2
2         2
3         3
d         b
e         a
1         1
1         1
Run Code Online (Sandbox Code Playgroud)

在 SQL Server 2017 中,您可以使用STRING_AGG()以下命令将字符串以可预测的顺序打包在一起:

DECLARE @str varchar(64) = 'abc223de11'; 

SELECT 
  OriginalString = @str, 
  QuasiReversed = STRING_AGG(New,'') WITHIN GROUP (ORDER BY n) 
FROM dbo.SortString(@str);
Run Code Online (Sandbox Code Playgroud)

在旧版本中,您需要使用FOR XMLhack:

DECLARE @str varchar(64) = 'abc223de11'; 

SELECT 
  OriginalString = @str, 
  QuasiReversed = (SELECT '' + New
    FROM dbo.SortString(@str) 
    ORDER BY n
    FOR XML PATH, TYPE).value(N'.[1]','varchar(64)');
Run Code Online (Sandbox Code Playgroud)

两种情况下的结果:

OriginalString  QuasiReversed
--------------  -------------
abc223de11      edc223ba11
Run Code Online (Sandbox Code Playgroud)