例如由于Dense_Rank函数调用(在MS Sql中),是否有可能获得字母(如A,B)而不是数字(1,2)?
试试这个:
SELECT Letters = Char(64 + T.Num), T.Col1, T.Col2 FROM dbo.YourTable T ;
请注意,当您达到27(past Z)时,事情将变得有趣而无用。
Z
如果您想开始将字母加倍,... X, Y, Z, AA, AB, AC, AD ...那么它将变得有些棘手。这适用于所有版本的SQL Server。这些SELECT子句只是CASE语句的替代(每个短2个字符)。
... X, Y, Z, AA, AB, AC, AD ...
SELECT
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 2008及更高版本的演示,请注意,我Dense_Rank()用来模拟一系列数字)
Dense_Rank()
这将在Ato的范围内起作用ZZZZZ,代表1to的值12356630。上面所有疯狂的原因,而不是更简单的表达,是因为这里A并没有简单地表示0。在每个阈值之前,当序列跳转到A添加到前面的下一个字母时,实际上是一个隐藏的空白数字,但不再使用。所以5个字母长不是26 ^ 5的组合,而是26 + 26 ^ 2 + 26 ^ 3 + 26 ^ 4 + 26 ^ 5!
A
ZZZZZ
1
12356630
0
为了使此代码正常工作,需要花点时间进行修补…希望您或有人对此感到满意!只需添加另一个具有正确值的生成字母的表达式,就可以轻松地将其扩展为更多的字母。
由于看起来我现在正处于男子气概比赛的中间,因此我进行了一些性能测试。一WHILE环是我,不是因为我的查询设计为一次对整个行集的运行来比较性能的好办法。对于一次只能对一百万行运行一遍(基本上将其强制进入虚拟UDF土地)对我来说没有意义,这是OP给出的用于执行的用例场景这是针对大型行集的。因此,这里是要针对1,000,000行进行测试的脚本(测试脚本需要SQL Server 2005及更高版本)。
WHILE
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进行数据透视连接来实现这种“有趣”的方式,但是尽管确实很有趣,但是事实证明它很慢。这是后代的版本(,需要SQL 2005及更高版本Dense_Rank,但仅将数字转换为字母即可在SQL 2000中使用):
Dense_Rank
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 ;