SQL将数字转换为任何基数的字符串表示形式(二进制,十六进制,...,tricontahexadecimal)

时间:2015-10-13 01:46:11

标签: sql sql-server algorithm binary hex

如何使用SQL将数字转换为所需数字基数的字符串表示形式,例如将45转换为基数2(二进制),8(八进制),16(十六进制),。。36。

要求是使用数字[0-9]和大写字符[A-Z],可用字符总数为36。

我需要将示例45转换为基数36,输出必须是" 19",或使用任何范围基本形式2到36。

3 个答案:

答案 0 :(得分:3)

这是将数字转换为字符串表示形式到任何数字基础的解决方案。该解决方案是一个在SQL Server上运行的函数,它接收base和number参数。第一个参数是您要获取的基数,第二个参数是您要转换的数字。 The algorithm used取自mathbits.com网站。

如果您想将5个基数10转换为基数2,请使用site of the algorithm中的相同示例。

enter image description here

过程是:

  1. 划分"期望" base(在本例中为base 2)INTO您要转换的数字。
  2. 用你在小学写的余数写出商(答案)。
  3. 使用前一个商(前面的数字前面的数字)中的整数来重复此除法过程。
  4. 继续重复此除法,直到余数前面的数字仅为零。
  5. 答案是剩下的人从下往上阅读。
  6. 您可以看到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,但是常规表,视图或表值函数也可以做到这一点。

按级别对输出进行排序很重要,以确保正确的字形出现在正确的位置。