Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.Sign up
Transaction Number Generator #173
Please read through this and need help to determine what to call these function(s)
Sometimes business users want a transaction number. Ex: invoice number.
What most people do is create a sequence and then pad it with some
A simple solution is to covert a sequence to hex , thus giving transaction numbers like
The following table shows how many values you can get for the number of characters:
The proposed solution is to allow for transaction numbers that cover
The following query converts a number to base 36:
with lvls as ( select level lvl from dual -- The <= logic will return the number of characters required for conversion connect by level <= ceil(log(:base, :x)) + decode(log(:base, :x), ceil(log(:base, :x)), 1,0) ), -- Alphabet 0..Z alphabet as ( select level-1 num, case when level-1 < 10 then to_char(level-1) else chr( ascii('A')+level-1-10) end letter from dual connect by level <= :base ), -- Returns rows for all the decimal values for each character position my_data as ( select to_char(:x, 'XXXXXX') hex_val, -- for testing lvl, remainder, quotient from lvls model return all rows dimension by (lvl) measures( 0 remainder, 0 quotient) rules ( -- Order matters here. I.e. s must come after t so s can "see" t quotient[lvl] = trunc(nvl(quotient[cv(lvl)-1], :x) / :base), remainder[lvl] = mod(nvl(quotient[cv(lvl)-1], :x), :base) ) ) select to_char(:x, 'XXXXXX') hex_conv, -- to test for hex listagg(a.letter, '') within group (order by md.lvl desc) basex from my_data md, alphabet a where 1=1 and md.remainder = a.num -- For testing --select * --from my_data ;
create or replace function basex ( p_num in integer, p_base in integer) return varchar2 as l_return varchar2(255); l_quotient integer; l_remainder integer; begin -- TODO mdsouza: checks that p_num > = 0 and p_base bwteen 10 and 36 l_quotient := p_num; while l_quotient > 0 loop l_remainder := mod(l_quotient, p_base); l_quotient := trunc(l_quotient / p_base); if l_remainder < 10 then l_return := to_char(l_remainder) || l_return; else -- Subtract -10 since 0~10 covered in above l_return := chr(ascii('A') + l_remainder - 10) || l_return; end if; end loop; return l_return; end basex; /
I found that enumerating the symbols in advance, and exchanging the MOD for subtraction gives a little perf boost. Around 15% on my machine.
In regards to @dmcghan suggestion on Twitter, this file from PWGen has the list of ambiguous characters they use.
I'd suggest to add lowercase