我需要执行一个将2个字符转换为整数的函数。
规则以这种方式工作:
99 = 99
9A = 100
9B = 101
9C = 102
9D = 103
.
.
.
9Z = 125
AA = 126
AB = 127
例如,我的函数接收到“ 9C”,并且应返回“ 102”。该功能必须在SQL中完成。
这只是一个例子,存在的序列具有字母的所有字符以及从0到9的数字。
答案 0 :(得分:0)
这很有趣而且很棘手。我使用了一个计数表来构建ASCII表,并将dense_rank
和row_number
应用于唯一字符和字符对。然后,结果是一个简单的case
语句。
declare @val varchar(2) = '9C'
;WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select
RN = dense_rank() over (order by c.N)
,d = char(c.N)
,d2 = char(c.N) + char(c2.N)
,RN2 = row_number() over (order by c.N, c2.N) + 125
into #myTemp
from cteTally c
cross apply cteTally c2
where c.N between 65 and 90 and c2.N between 65 and 90
--uncomment this code to see how the ranking and row_number worked
--select *
--from #myTemp
--order by RN
select
case
when @val like '[0-9][0-9]' then @val
when @val like '[9][A-Z]' then 99 + (select top 1 RN from #myTemp where d = right(@val,1))
when @val like '[A-Z][A-Z]' then (select RN2 from #myTemp where d2 = @val)
end
drop table #myTemp
答案 1 :(得分:0)
好像您要将base36数字转换为base10数字。
然后您可以创建一个用于基本转换的函数。
功能
create function dbo.fnBase36ToBase10(@input varchar(8))
returns int
as
begin
declare @base36string varchar(8) = upper(@input);
declare @result int = 0;
declare @basechars varchar(36) = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
declare @N int = 36;
declare @digit char(1);
declare @pow int = 0;
while @pow < len(@base36string)
begin
set @Digit = substring(reverse(@base36string),@Pow+1,1);
set @result = @result + (charindex(@Digit, @basechars)-1) * power(@N, @pow);
set @pow = @pow + 1;
end
return @result;
end;
GO
使用该功能的示例
select code, (dbo.fnBase36ToBase10(code) - 234) as num
from (values
('99'),('9A'),('9B'),('9C')
,('9Z'),('A0')
,('A9'),('AA'),('AB')
) AS codes(code)
order by num;
返回:
code num
99 99
9A 100
9B 101
9C 102
9Z 125
A0 126
A9 135
AA 136
AB 137
如果创建函数不是一种选择。
然后,您可以加入一个Tally表,该表包含
Base36和Base10数字。
示例:
IF OBJECT_ID('tempdb..#Base36ToBase10') IS NOT NULL DROP TABLE #Base36ToBase10;
CREATE TABLE #Base36ToBase10 (base36 varchar(2) COLLATE Latin1_General_CS_AS primary key, base10 int);
-- Fill Tally Table
;WITH CHARS AS
(
select 0 as n, convert(char(1),0) as c
union all
select n+1, iif(n<9,convert(char(1),n+1),char(n+56))
from CHARS where n < 35
)
insert into #Base36ToBase10 (base36, base10)
select
concat(c2.c,c1.c) as b36,
(c2.n*36+c1.n) as b10
from CHARS c1
cross join CHARS c2
order by c2.c, c1.c;
declare @codes table (code varchar(2));
insert into @codes (code) values
('99'),('9A'),('9B'),('9C')
,('9Z'),('A0')
,('A9'),('AA'),('AB')
;
select code, (b36to10.base10 - 234) as num
from @codes AS codes
join #Base36ToBase10 as b36to10
on codes.code collate Latin1_General_CS_AS = b36to10.base36
order by num;