Home » SQL & PL/SQL » SQL & PL/SQL » alphanumeric sequence generator (oracle 10g r2)
- alphanumeric sequence generator [message #451157] Mon, 12 April 2010 13:22 Go to next message
caiti1012
Messages: 3
Registered: April 2010
Junior Member
Is there a function or has anyone developed a process to generate and maintain an alphanumeric sequence?

I need to be able to sequentially generate both a 3 and 5 byte case sensitive alphanumeric primary key that uses A-Za-z0-9 characters intermittently of which the 5 byte MAY be a subset of the 3 byte. e.g. the key can be 00000 or a3BD7.

so I need to be able to generate a new 5 char using 3 char base and if that value is not available, generate a unique 5 char value and allocate the substr(1,3) of that value backwards.

Ex1: unique customer location comes in - not a preexisting customer name (same name,different location address doesn't exist) --> select nextval.[5char] into v_long_c to insert into customer_loc table, and substr (v_long_c, 1, 3) for customer name table.

EX 2: unique customer location comes in. customer name exists in customer table with 3char val A39, but that location doesn't exist in customer_location table (5chars are location specific).

I need to take the A39 and generate new 5char for that unique location using that prefix (A39) if possible.

However, a number of a39-- already exist, though not all assigned to the same customer name (we're trying to keep them grouped together but that might not be logically feasible)

How do I select next a39||[2char] for that unique location - and if that value is not available (all 62*62 possibilities have been used for A39--), select nextval.[5charseq] into long_key.

I suspect someone out there knows the functions I can use to create this or has written a package to do just this; I suspect with enough time I could do it, but I don't currently have the time or knowledge to develop it within these deadlines. I thought it would be easier.

My short-sighted solution was to create a static table of all iterations of A-z0-9 5 char values, select one, mark it used and move on. Unfortunately 62^5 is a substantial number (913+million records) and that table took a LOT of space, causing my development server to groan and crack miserably. indexing on it takes a lot of space too (and trying to build multiple indexes exceeded database size). But without an index on the 3char field, selecting an available 5 code from it based on the customer_3char prefix took five minutes - much longer than the fraction of a second I need.

- Re: alphanumeric sequence generator [message #451158 is a reply to message #451157] Mon, 12 April 2010 13:31 Go to previous messageGo to next message
Michel Cadot
Messages: 68760
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
You have to do it with a procedure that implements exactly what you said just keeping the last 3 bytes in a single row table.
BUT you have to lock the tables before any insert or update (and maybe delete) statement and so you decrease concurrency.

Regards
Michel

[Updated on: Mon, 12 April 2010 13:32]

Report message to a moderator

- Re: alphanumeric sequence generator [message #451167 is a reply to message #451158] Mon, 12 April 2010 14:45 Go to previous messageGo to next message
caiti1012
Messages: 3
Registered: April 2010
Junior Member
Michel,

If anyone has a procedure which does this kind of sequence generation using alphanumeric fields, looping and referencing existing data for possible beginning codes, without selecting from a static table of pregenerated codes, I would love to see it.

However, I lack the ability to formulate and/or implement a design in 24 hours for a procedure that could do what I stated I needed and throw back a complete alphanumeric code on the fly in the time frame I have without using a static reference table. I am now two weeks behind on development, and my deadline to put into test environment for users to try to break it is in two days and my brain, unfortunately, is close to melting point. I'm just not that good.

I had already decided to do what you're suggesting - to keep a static list of my 3char prefixes (62*62*62 = 238,328 potential customer values and build both master_customer_name and customer_location pk values off of those values using numeric 00-99 appendings. There will be a couple of passes for data existing or non-existing, but it shouldn't be near as extensive as I was having to go through with a full table scan (even indexed) on 918Mil records. Boy, did I get big eyes when I quoted that number... and was appropriately chided for being a little too zealous Smile.

Using numeric for the last two values will give me the ability to +1 to a selected short (possible)/long code and provides 23,832,800 total possibilities.

That should suffice us for a few years on unique customer locations. (we are currently running about 75K-1mil of these annually, and I would expect there should be growth of some nature, barring the apocolypse, in which case it doesn't really matter now, does it?)

And since These 5char fields (and 3char) are actually 6char and 4char preceded by a non-alphanumeric character (we are currently using '#') to indicate that they are not really contracted customers, but allow us to keep up with the data, should I actually somehow run through that 23million codes, I can generate a new set of short_codes preceded by a new character such as %, @, * etc, and have devised the system to do it.

However, let's say I don't see that happening in the next 10 years by which time technology will have evolved to provide me with something far more beautiful elegant and simple, but I - hopefully - will be somewhere else letting my greys actually stay grey and climbing mountains in africa, exploring new zealand or touring the celtic cultures while minds more brilliant and learned than mine solve these issues.

The critical part was to try to keep the number down on our customer_name table if possible and yet still try to keep them tied to a common short code. For reporting purposes we needed to keep the code generation to 3 and 5(actually 4 and 6 as explained above) bytes, so we could merge this process with our existing customer tables (This process I'm developing is to maintain a separate table source for non-contractual customers).

Thanks for any and all suggestions. If something better or more efficient comes up I can always implement as a modification later!

Kathleen
- Re: alphanumeric sequence generator [message #451169 is a reply to message #451167] Mon, 12 April 2010 15:16 Go to previous messageGo to next message
Michel Cadot
Messages: 68760
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Here's how you can get 3 characters sequence from a standard sequence number:
SQL> with
  2    data as (
  3      select level-1 a, 100+level-1 b, 3000+level-1 c, 10000+level-1 d, 100000+level-1 e 
  4      from dual connect by level <= 30
  5    ),
  6    vals as (select 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' val from dual)
  7  select a,
  8         substr(val,trunc(a/2704)+1,1)
  9         ||substr(val,trunc(mod(a,2704)/52)+1,1)
 10         ||substr(val,mod(a,52)+1,1) val_a,
 11         b,
 12         substr(val,trunc(b/2704)+1,1)
 13         ||substr(val,trunc(mod(b,2704)/52)+1,1)
 14         ||substr(val,mod(b,52)+1,1) val_b,
 15         c,
 16         substr(val,trunc(c/2704)+1,1)
 17         ||substr(val,trunc(mod(c,2704)/52)+1,1)
 18         ||substr(val,mod(c,52)+1,1) val_c,
 19         d,
 20         substr(val,trunc(d/2704)+1,1)
 21         ||substr(val,trunc(mod(d,2704)/52)+1,1)
 22         ||substr(val,mod(d,52)+1,1) val_d,
 23         e,
 24         substr(val,trunc(e/2704)+1,1)
 25         ||substr(val,trunc(mod(e,2704)/52)+1,1)
 26         ||substr(val,mod(e,52)+1,1) val_e
 27  from data, vals
 28  /
         A VAL          B VAL          C VAL          D VAL          E VAL
---------- --- ---------- --- ---------- --- ---------- --- ---------- ---
         0 aaa        100 abW       3000 bfK      10000 dKq     100000 KZe
         1 aab        101 abX       3001 bfL      10001 dKr     100001 KZf
         2 aac        102 abY       3002 bfM      10002 dKs     100002 KZg
         3 aad        103 abZ       3003 bfN      10003 dKt     100003 KZh
         4 aae        104 aca       3004 bfO      10004 dKu     100004 KZi
         5 aaf        105 acb       3005 bfP      10005 dKv     100005 KZj
         6 aag        106 acc       3006 bfQ      10006 dKw     100006 KZk
         7 aah        107 acd       3007 bfR      10007 dKx     100007 KZl
         8 aai        108 ace       3008 bfS      10008 dKy     100008 KZm
         9 aaj        109 acf       3009 bfT      10009 dKz     100009 KZn
        10 aak        110 acg       3010 bfU      10010 dKA     100010 KZo
        11 aal        111 ach       3011 bfV      10011 dKB     100011 KZp
        12 aam        112 aci       3012 bfW      10012 dKC     100012 KZq
        13 aan        113 acj       3013 bfX      10013 dKD     100013 KZr
        14 aao        114 ack       3014 bfY      10014 dKE     100014 KZs
        15 aap        115 acl       3015 bfZ      10015 dKF     100015 KZt
        16 aaq        116 acm       3016 bga      10016 dKG     100016 KZu
        17 aar        117 acn       3017 bgb      10017 dKH     100017 KZv
        18 aas        118 aco       3018 bgc      10018 dKI     100018 KZw
        19 aat        119 acp       3019 bgd      10019 dKJ     100019 KZx
        20 aau        120 acq       3020 bge      10020 dKK     100020 KZy
        21 aav        121 acr       3021 bgf      10021 dKL     100021 KZz
        22 aaw        122 acs       3022 bgg      10022 dKM     100022 KZA
        23 aax        123 act       3023 bgh      10023 dKN     100023 KZB
        24 aay        124 acu       3024 bgi      10024 dKO     100024 KZC
        25 aaz        125 acv       3025 bgj      10025 dKP     100025 KZD
        26 aaA        126 acw       3026 bgk      10026 dKQ     100026 KZE
        27 aaB        127 acx       3027 bgl      10027 dKR     100027 KZF
        28 aaC        128 acy       3028 bgm      10028 dKS     100028 KZG
        29 aaD        129 acz       3029 bgn      10029 dKT     100029 KZH

Regards
Michel

[Updated on: Mon, 12 April 2010 15:26]

Report message to a moderator

- Re: alphanumeric sequence generator [message #451170 is a reply to message #451167] Mon, 12 April 2010 15:33 Go to previous messageGo to next message
BlackSwan
Messages: 26766
Registered: January 2009
Location: SoCal
Senior Member
> to keep a static list of my 3char prefixes (62*62*62 = 238,328 potential customer values

CREATE TABLE CUST_PREFIX (PRE_3 VARCHAR2(3), SUFF_2 VARCHAR2(2));

At most CUST_PREFIX holds 238,328 rows but only contains assigned prefix values.
The SUFF_2 column contains the highest value for that prefix.
- Re: alphanumeric sequence generator - thanks! [message #451179 is a reply to message #451170] Mon, 12 April 2010 21:50 Go to previous message
caiti1012
Messages: 3
Registered: April 2010
Junior Member
lol - awesome. Thank you both!

Blackswan, what's great is that I decided on that same solution after getting michel's solution, merging the two together. Talk about confirmation. Thank you!

For your critique and for future readers who might need a solution for a similar situation, here's now the plan:

Create a prefix table for master_code possibilities in design like Black Swans.
Create a suffix table with a numeric PK for each suffix.
Store the most recently assigned suffix_pk in the prefix table.

When assigning a new code to a customer that has an existing prefix, select next suffix from suffix value based on that numeric value+1, update the prefix table with the new suffix value.

if the customer is new, randomly select (where rownum = 1) an available prefix table and go from there.

when I select the max suffix pk (currently 62*62) I will either delete the calling prefix from the prefix table or set an indicator on that prefix to N (I lean towards indicators). I have already written the package that generates new long and short codes; I'll modify that to generate short only; the suffix table should remain unchanged.

I had already written into the daily customer code assignment process that if for some reason we ran out of available codes before a weekly or monthly maintenance package caught that we were approaching the threshold, it would automatically generate a new code short code set. so I'm covered there. The routine maintenance program will count available prefix' and if it approaches or is less than that threshold, a new set of prefixes will be generated with a new leading character (already stored in code_chars table indicated as reserved for leading character only.

voila.

Is it too simple?

Michel, your code does something I have not seen, showing my level of (in)expertise - wow. I created my initial long codes set by creating a code_chars table of characters that could be used in the code, and then generated the short and long codes by cross joining the table to itself 3 and 5 times to populate the individual short and long code reference tables. I couldn't figure out how to cross join an array. to be honest, I am going to have to explore what yours does so I know how to use it. amazing.

Thanks so much for both of you giving this situation thought and responding. If you have any further suggestions or corrections to my current solution, feel free to respond. And again Smile I apologize for the lack of brevity, but hope that someone with the same issue can use these concepts to solve their own or perhaps they can offer something better!

Have a wonderful evening.

Kathleen

[Updated on: Mon, 12 April 2010 21:57]

Report message to a moderator

Previous Topic: pl/sql
Next Topic: Full Outer Join
Goto Forum:
  


Current Time: Fri Jun 20 21:52:39 CDT 2025