如何使用SQL将数字转换为所需数字基数的字符串表示形式,例如将45转换为基数2(二进制),8(八进制),16(十六进制),。。36。
要求是使用数字[0-9]和大写字符[A-Z],可用字符总数为36。
我需要将示例45转换为基数36,输出必须是" 19",或使用任何范围基本形式2到36。
答案 0 :(得分:3)
这是将数字转换为字符串表示形式到任何数字基础的解决方案。该解决方案是一个在SQL Server上运行的函数,它接收base和number参数。第一个参数是您要获取的基数,第二个参数是您要转换的数字。 The algorithm used取自mathbits.com网站。
如果您想将5个基数10转换为基数2,请使用site of the algorithm中的相同示例。
过程是:
您可以看到algorithm and more examples here。
SQL中的函数是使它们在SQL Server实例中全局有用的最佳选择,执行转换的代码如下:
IF OBJECT_ID (N'dbo.NUMBER_TO_STR_BASE', N'FN') IS NOT NULL
DROP FUNCTION dbo.NUMBER_TO_STR_BASE;
GO
CREATE FUNCTION dbo.NUMBER_TO_STR_BASE (@base int,@number int)
RETURNS varchar(MAX)
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE @dividend int = @number
,@remainder int = 0
,@numberString varchar(MAX) = CASE WHEN @number = 0 THEN '0' ELSE '' END ;
SET @base = CASE WHEN @base <= 36 THEN @base ELSE 36 END;--The max base is 36, includes the range of [0-9A-Z]
WHILE (@dividend > 0 OR @remainder > 0)
BEGIN
SET @remainder = @dividend % @base ; --The reminder by the division number in base
SET @dividend = @dividend / @base ; -- The integer part of the division, becomes the new divident for the next loop
IF(@dividend > 0 OR @remainder > 0)--check that not correspond the last loop when quotient and reminder is 0
SET @numberString = CHAR( (CASE WHEN @remainder <= 9 THEN ASCII('0') ELSE ASCII('A')-10 END) + @remainder ) + @numberString;
END;
RETURN(@numberString);
END
GO
执行上面的代码后,您可以测试它们在任何查询中调用函数,甚至是复杂的TSL代码。
SELECT dbo.NUMBER_TO_STR_BASE(16,45) AS 'hexadecimal';
-- 45 in base 16(hexadecimal) is 2D
SELECT dbo.NUMBER_TO_STR_BASE(2,45) AS 'binary';
-- 45 in base 2(binary) is 101101
SELECT dbo.NUMBER_TO_STR_BASE(36,45) AS 'tricontahexadecimal';
-- 45 in base (tricontaexadecimal) is 19
SELECT dbo.NUMBER_TO_STR_BASE(37,45) AS 'tricontahexadecimal-test-max-base';
--The output will be 19, because the maximum base is 36,
-- which correspond to the characters [0-9A-Z]
随意评论或建议改进,我希望它有用
答案 1 :(得分:0)
希望这会有所帮助:
-- Decimal to hex
SELECT CAST(493202384 AS varbinary)
-- Hex to decimal
SELECT CAST(0x1D65ABD0 AS int)
-- Decimal to hex to decimal
SELECT CAST(CAST(493202384 AS varbinary) AS int)
-- Binary to decimal
CREATE FUNCTION [dbo].[BinaryToDecimal]
(
@Input varchar(255)
)
RETURNS bigint
AS
BEGIN
DECLARE @Cnt tinyint = 1
DECLARE @Len tinyint = LEN(@Input)
DECLARE @Output bigint = CAST(SUBSTRING(@Input, @Len, 1) AS bigint)
WHILE(@Cnt < @Len) BEGIN
SET @Output = @Output+POWER(CAST(SUBSTRING(@Input, @Len-@Cnt,1)*2 AS bigint), @Cnt)
SET @Cnt = @Cnt + 1
END
RETURN @Output
END
-- Decimal to binary
CREATE FUNCTION [dbo].[DecimalToBinary]
(
@Input bigint
)
RETURNS varchar(255)
AS
BEGIN
DECLARE @Output varchar(255) = ''
WHILE @Input > 0 BEGIN
SET @Output = @Output + CAST((@Input % 2) AS varchar)
SET @Input = @Input / 2
END
RETURN REVERSE(@Output)
END
答案 2 :(得分:0)
由于可能如何估计基数以及在重新安排功能内容时如何限制优化器,所以功能可能会出现性能问题,尤其是多语句功能。同样,以声明性语言编写过程代码(WHILE循环)也不理想。通过使用递归CTE可以达到预期的结果。
declare @Dividend int = 32;
declare @Divisor int = 16;
with Division as
(
select
Quotient = @Dividend / @Divisor,
Remainder = @Dividend % @Divisor,
Level = 0
union all
select
Quotient = d.Quotient / @Divisor,
Remainder = d.Quotient % @Divisor,
Level = d.Level + 1
from Division as d
where d.Quotient > 0
),
OuputGlyphs as
(
select *
from
(
values
(0, '0'), (1, '1'), (2, '2'), (3, '3'), (4, '4'),
(5, '5'), (6, '6'), (7, '7'), (8, '8'), (9, '9'),
(10, 'A'), (11, 'B'), (12, 'C'), (13, 'D'),
(14, 'E'), (15, 'F') -- extend this list as required
) as T(Given, Returned)
)
select
CAST(@Dividend as varchar(99)) + ' in base ' + CAST(@Divisor as varchar(99)) + ' = ' +
STRING_AGG(gg.Returned, ',') within group ( order by Level DESC )
from Division as dd
inner join OuputGlyphs as gg
on gg.Given = dd.Remainder;
这可以打包为单语句表值函数或存储过程。无论哪种方式,基数估计都将是准确的。声明的变量将成为输入参数。
递归CTE(称为“除法”)对@Dividend执行长除法,就像我们在学校中学到的那样。默认情况下,CTE限制为100次递归,即可以产生100位数字的输出。如果时间不够长,可以更改限制-请参见MAXRECURSION。
OutputGlyphs将每次递归的小数点余数转换为您想要查看的任何符号。为了简洁起见,我在16点停了下来。无论您选择使用哪种基础,都可以将此列表扩展为恶心。实际上,只需稍作调整,就可以使用非ASCII字符或表情符号。为了方便起见,我使用了嵌入式CTE,但是常规表,视图或表值函数也可以做到这一点。
按级别对输出进行排序很重要,以确保正确的字形出现在正确的位置。