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.
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.