SQL Server中的转换功能

时间:2018-07-13 20:34:05

标签: sql sql-server function

我需要执行一个将2个字符转换为整数的函数。

规则以这种方式工作:

99 = 99
9A = 100
9B = 101
9C = 102
9D = 103
.
.
.
9Z = 125
AA = 126
AB = 127

例如,我的函数接收到“ 9C”,并且应返回“ 102”。该功能必须在SQL中完成。

这只是一个例子,存在的序列具有字母的所有字符以及从0到9的数字。

2 个答案:

答案 0 :(得分:0)

这很有趣而且很棘手。我使用了一个计数表来构建ASCII表,并将dense_rankrow_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;