SQL convert number to string representation of any base (binary, hexadecimal, …, tricontahexadecimal)

后端 未结 3 1834
感情败类
感情败类 2020-12-18 09:31

How to convert a number to it string representation for a desired numeric base using SQL, for example convert 45 to the base 2(binary), 8(octantal),16(hexadecimal), ..36.

3条回答
  •  死守一世寂寞
    2020-12-18 10:07

    Functions can have performance problems, especially multi-statement functions, because of how cardinality is estimated and how the optimizer is limited in re-arranging the function's content. Also writing procedural code (WHILE loops) in a declarative language is sub-optimal. The desired results can be achieved by using a recursive 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;
    

    This can be packaged as a single-statement table valued function or as a stored procedure. Either way the cardinality estimates will be accurate. The declared variables will become input parameters.

    The recursive CTE (called "Division") performs long division on @Dividend, just like we learnt in school. By default the CTE is limited to 100 recursions i.e. a 100-digit ouput can be produced. If this is not long enough the limit can be changed - see MAXRECURSION.

    OutputGlyphs translates the decimal remainder from each recursion to whatever symbol you want to see. I stopped at 16 for brevity. This list can be extended ad nauseam for whatever base you choose to use. Indeed, non-ASCII characters or emojis are possible with a little tweaking. I used an in-line CTE for convenience but a regular table, view or table-valued function would do just as well.

    It is important to sort the output by Level to ensure the correct glyph appears in the correct position.

提交回复
热议问题