SQL:是否有可能将数字(1、2、3、4...)转换为字母(A、B、C、D...) [英] SQL: Is there a possibility to convert numbers (1,2,3,4...) to letters (A,B,C,D...)

查看:32
本文介绍了SQL:是否有可能将数字(1、2、3、4...)转换为字母(A、B、C、D...)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有可能获得字母(如 A、B)而不是数字(1,2),例如由于 Dense_Rank 函数调用(在 MS Sql 中)?

Is there a possibility to obtain letters (like A,B) instead of numbers (1,2) e.g. as a result of Dense_Rank function call(in MS Sql) ?

推荐答案

试试这个:

SELECT
   Letters = Char(64 + T.Num),
   T.Col1,
   T.Col2
FROM
   dbo.YourTable T
;

请注意,当您达到 27(过去 Z)时,事情会变得有趣,但没有用处.

Just be aware that when you get to 27 (past Z), things are going to get interesting, and not useful.

如果您想开始将字母加倍,例如 ... X, Y, Z, AA, AB, AC, AD ... 那么它会变得有点棘手.这适用于所有版本的 SQL Server.SELECT 子句只是 CASE 语句的替代(每个都短 2 个字符).

If you wanted to start doubling up letters, as in ... X, Y, Z, AA, AB, AC, AD ... then it's going to get a bit trickier. This works in all versions of SQL Server. The SELECT clauses are just an alternate to a CASE statement (and 2 characters shorter, each).

SELECT
   *,
   LetterCode =
      Coalesce((SELECT Char(65 + (N.Num - 475255) / 456976 % 26) WHERE N.Num >= 475255), '')
      + Coalesce((SELECT Char(65 + (N.Num - 18279) / 17576 % 26) WHERE N.Num >= 18279), '')
      + Coalesce((SELECT Char(65 + (N.Num - 703) / 676 % 26) WHERE N.Num >= 703), '')
      + Coalesce((SELECT Char(65 + (N.Num - 27) / 26 % 26) WHERE N.Num >= 27), '')
      + (SELECT Char(65 + (N.Num - 1) % 26))
FROM dbo.YourTable N
ORDER BY N.Num
;

在 SQL Fiddle 上观看现场演示

(用于 SQL 2008 及以上的演示,注意我使用 Dense_Rank() 来模拟一系列数字)

这将从 AZZZZZ 工作,表示值 112356630.上面所有疯狂而不是更简单的表达式的原因是因为 A 不简单地代表 0,这里.当序列转移到添加到前面的下一个字母 A 时,在每个阈值之前,实际上有一个隐藏的、空白的数字——但它不会再次使用.所以 5 个字母长不是 26^5 组合,而是 26 + 26^2 + 26^3 + 26^4 + 26^5!

This will work from A to ZZZZZ, representing the values 1 to 12356630. The reason for all the craziness above instead of a more simple expression is because A doesn't simply represent 0, here. Before each threshold when the sequence kicks over to the next letter A added to the front, there is in effect a hidden, blank, digit--but it's not used again. So 5 letters long is not 26^5 combinations, it's 26 + 26^2 + 26^3 + 26^4 + 26^5!

需要一些真正的修补才能使此代码正常工作...我希望您或其他人对此表示赞赏!只需添加另一个具有正确值的字母生成表达式,就可以轻松地将其扩展为更多字母.

It took some REAL tinkering to get this code working right... I hope you or someone appreciates it! This can easily be extended to more letters just by adding another letter-generating expression with the right values.

因为现在看来我正处于男子气概比赛的中间,所以我做了一些性能测试.WHILE 循环对我来说不是比较性能的好方法,因为我的查询旨在同时针对整个行集运行.当它可以针对一百万行运行一次时,针对一行运行一百万次(基本上是强制它进入虚拟 UDF 区域)对我来说没有意义,这是 OP 给出的用例场景,用于执行这是针对大行集的.所以这是针对 1,000,000 行进行测试的脚本(测试脚本需要 SQL Server 2005 及更高版本).

Since it appears I'm now square in the middle of a proof-of-manliness match, I did some performance testing. A WHILE loop is to me not a great way to compare performance because my query is designed to run against an entire set of rows at once. It doesn't make sense to me to run it a million times against one row (basically forcing it into virtual-UDF land) when it can be run once against a million rows, which is the use case scenario given by the OP for performing this against a large rowset. So here's the script to test against 1,000,000 rows (test script requires SQL Server 2005 and up).

DECLARE
   @Buffer varchar(16),
   @Start datetime;

SET @Start = GetDate();
WITH A (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) A (N)),
B (N) AS (SELECT 1 FROM A, A X),
C (N) AS (SELECT 1 FROM B, B X),
D (N) AS (SELECT 1 FROM C, B X),
N (Num) AS (SELECT Row_Number() OVER (ORDER BY (SELECT 1)) FROM D)
SELECT @Buffer = dbo.HinkyBase26(N.Num)
FROM N
;
SELECT [HABO Elapsed Milliseconds] = DateDiff( ms, @Start, GetDate());

SET @Start = GetDate();
WITH A (N) AS (SELECT 1 FROM (VALUES (1), (1), (1), (1), (1), (1), (1), (1), (1), (1)) A (N)),
B (N) AS (SELECT 1 FROM A, A X),
C (N) AS (SELECT 1 FROM B, B X),
D (N) AS (SELECT 1 FROM C, B X),
N (Num) AS (SELECT Row_Number() OVER (ORDER BY (SELECT 1)) FROM D)
SELECT
   @Buffer =
      Coalesce((SELECT Char(65 + (N.Num - 475255) / 456976 % 26) WHERE N.Num >= 475255), '')
      + Coalesce((SELECT Char(65 + (N.Num - 18279) / 17576 % 26) WHERE N.Num >= 18279), '')
      + Coalesce((SELECT Char(65 + (N.Num - 703) / 676 % 26) WHERE N.Num >= 703), '')
      + Coalesce((SELECT Char(65 + (N.Num - 27) / 26 % 26) WHERE N.Num >= 27), '')
      + (SELECT Char(65 + (N.Num - 1) % 26))   
FROM N
;
SELECT [ErikE Elapsed Milliseconds] = DateDiff( ms, @Start, GetDate());

结果:

UDF: 17093 ms
ErikE: 12056 ms

原始查询

我最初通过为每个字母生成 1 行并使用 XML 进行枢轴连接来做到这一点的有趣"方式,但虽然它确实很有趣,但事实证明它很慢.这是供后代使用的版本(Dense_Rank 需要 SQL 2005 及更高版本,但在 SQL 2000 中仅用于将数字转换为字母):

I initially did this a "fun" way by generating 1 row per letter and pivot-concatenating using XML, but while it was indeed fun, it proved to be slow. Here is that version for posterity (SQL 2005 and up required for the Dense_Rank, but will work in SQL 2000 for just converting numbers to letters):

WITH Ranks AS (
   SELECT
      Num = Dense_Rank() OVER (ORDER BY T.Sequence),
      T.Col1,
      T.Col2
   FROM
      dbo.YourTable T
)
SELECT
   *,
   LetterCode =
      (
         SELECT Char(65 + (R.Num - X.Low) / X.Div % 26)
         FROM
            (
               SELECT 18279, 475254, 17576
               UNION ALL SELECT 703, 18278, 676
               UNION ALL SELECT 27, 702, 26
               UNION ALL SELECT 1, 26, 1
            ) X (Low, High, Div)      
         WHERE R.Num >= X.Low
         FOR XML PATH(''), TYPE
      ).value('.[1]', 'varchar(4)')
FROM Ranks R
ORDER BY R.Num
;

这篇关于SQL:是否有可能将数字(1、2、3、4...)转换为字母(A、B、C、D...)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆