Home>Question Details



Venkat -- Thanks for the question regarding "Sequences", version 8.0.6

Submitted on 22-Jun-2002 11:54 Central time zone
Last updated 7-Oct-2009 8:34

You Asked

Hi Tom,
   What you suggest is the best way to generate system generated numbers. As Oracle 
Sequences are not gap free, can you please suggets an alternative.

Thanks..

Prasad 

and we said...

I would recommend ignoring the fact that they are not gap free.  

Period. (i've said that lots here, many many discussions on it.  No one has ever 
presented a good reason for gap free numbers beyond "it's always been that way")

 

Reviews    
3 stars Sequences   June 22, 2002 - 3pm Central time zone
Reviewer: Venkatesa Prasad from India
Tom,
   Suppose I cannot use sequences for my PK generator, then what is the best way to generate.

   Well, I cannot use sequences for basically 3 reasons.

  1. My numbers have to be generated financial year-wise.
      - Then I have to create sequences 1 for each financial year. isn't it?

  2. I have a master table which tells what are the various voucher types and when user selects a 
given voucher type in the transcation, system has to generate a number for that type and that too 
it should start afresh for every month. I cannot create sequences before itself, as I dont know how 
many voucher types will get added each month.

   3. Third is related to gaps. Suppose in the front end (we user Developer 2000 - Forms 4.5), the 
user saves the data but leaves the session uncommitted (I mean 'POST' is issued). Then sequence is 
ost without the data getting committed. I mean the saved data is rolled back. Then how to avoid 
gaps.

Can you clarify, please.

Venkatesa Prasad 


Followup   June 22, 2002 - 4pm Central time zone:

1) why -- why not just know that "1-100323" are fy1.  100324-2431223 are fy2 and so on.  Since you 
"reset" the numbers for each year, this obviously isn't a primary key by itself -- the pk must be 
"FY + ID" (two columns).  This id is just to keep it unique within the year.

2) why again?  why?

3) well, if you use a gap free approach -- you know what'll happen in this case?  NO ONE ELSE IN 
YOUR ENTIRE SYSTEM WILL BE ABLE TO WORK, that is what.  Why?  cause this session with uncommitted 
data will have the id generating table locked.


Sigh, I hesitate to show you this, but here goes.  Gap free, non-concurrent, highly NON-scalable:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create table ids ( name varchar2(30), id number );

Table created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> 
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace function get_nextval( p_name in varchar2 ) 
return number
  2  as
  3     l_id number;
  4  begin
  5     update ids set id = id+1 where name = upper(p_name)
  6     returning id into l_id;
  7  
  8     if ( sql%rowcount = 0 )
  9     then
 10            raise_application_error( -20001, 'No such id name ' || p_name );
 11     end if;
 12     return l_id;
 13  end;
 14  /

Function created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> 
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( get_nextval( 'foo' ) )
BEGIN dbms_output.put_line( get_nextval( 'foo' ) ); END;

*
ERROR at line 1:
ORA-20001: No such id name foo
ORA-06512: at "OPS$TKYTE.GET_NEXTVAL", line 10
ORA-06512: at line 1


ops$tkyte@ORA817DEV.US.ORACLE.COM> 
ops$tkyte@ORA817DEV.US.ORACLE.COM> insert into ids values ( 'FOO', 0 );

1 row created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( get_nextval( 'foo' ) )
1

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( get_nextval( 'foo' ) )
2

PL/SQL procedure successfully completed.

Now, when you want to reset, just update ids set id = 0 where name = 'whatever'.

Yuck.

 

5 stars sequnces   November 12, 2002 - 7am Central time zone
Reviewer: mo 
Tom:

I have a production instance that started to skip sequnce numbers.  The first 15 records created 
were fine and created with number 1000 - 1015 but the nafter oct 1 I statrted noticing I got 1020, 
1043 and 1060.

I am only doing a select on the sequence.next val in my save procedure.  First I select ito into a 
variable and the ni use the variable in my insert statement.  The reason I use a variable instead 
of seq.nextval is that I insert into multiple tables with same sequnce numbers.

What do you think may be happening that causing this?  This is a web application using stored 
procedures. 


Followup   November 12, 2002 - 10am Central time zone:

There is no such thing as a sequence "skipping numbers".  In order for a sequence to "skip numbers" 
it would have to first assure gap free number sequences and they explicitly DO NOT.

Sounds like your shared pool is way too small and the sequence is getting aged out (not used 
enough).  

But -- I would just *NOT WORRY ABOUT IT AT ALL* (unless your shared pool is really too small, fix 
that of course but don't worry about the sequence)

a sequence is used to generate a primary key/unique value. Nothing more, nothing less.  any 
assumptions about "gap free" or "lost numbers" is in vain.   

5 stars sequence   November 12, 2002 - 10am Central time zone
Reviewer: mo 
TOm:

<Sounds like your shared pool is way too small and the sequence is getting aged 
out (not used enough).  >

Can you elaborate on how can a sequence get aged out if it is not used.  How does it increment if 
you are nor running (select seq.nextval from dual).

2. The primary key is used by client as a reference number. It is really awkward to have then refer 
to PO 1000 and the npo 1050. It makes you think that there are 50 po's in the system when in fact 
there are only 2.

Thank you, 


Followup   November 12, 2002 - 1pm Central time zone:

things in the shared pool (where sequences are cached) are aged out using an LRU (least recently 
used). Hence, if you select s.nextval and then don't touch S for a while and we need space in the 
shared pool -- out goes S and out goes any cached values for S.

2) no it isn't.  why is it?  count(*) tells them how many po's are in the system.  A po number 
doesn't, cannot.

Think about this.  Its the days before computers.  Everything is on paper.  You have a stack of 
numbered PO's in a tablet.  The current number is 1 on the top.  You fill out PO #1 and put it in 
the OUT box.  You bump your coffee onto this tablet spilling it.  Whoops.  The coffee soaks the 
next 20 sheets which you tear off and through away.  You are on PO 21 -- are you confused?  Do you 
think there are 20 po's in your out box?  No -- you see there is one PO there.



Getting back to today. If you've told your users to look at the PO number to figure out how many 
there are -- they've been mislead.  There is a fact about sequences -- an UNDENIABLE, UNESCAPABLE 
fact -- they are not gap free, will never be gap free, they will have gaps!.  No matter WHAT 
you do, you cannot look at the sequence number (your po number) and make any conclusions about the 
count of PO's in your system -- none. 

5 stars How does sequences avoid serialization?   December 18, 2002 - 4pm Central time zone
Reviewer: Sam from San Mateo, CA
Tom,

As usual, your answers are most helpful.

I read this in the Oracle9i Application Developers Guide:
"Sequences eliminate serialization and improve the concurrency of your application".  Is this 
really true?  Or do they just mean "sequences minimizes serialization because it's native in Oracle 
and is really fast especially when the numbers are cached"?  What gets locked when I do 
my_sequence_s.nextval?

Also, I saw this statement in my trace file:
update seq$ set increment$=:2,minvalue=:3,maxvalue=:4,cycle#=:5,order$=:6,
  cache=:7,highwater=:8,audit$=:9
where
 obj#=:1

Could you tell me what operation caused this SQL?



 


Followup   December 18, 2002 - 6pm Central time zone:

there is a lightweight latch used to serialize access for a split instant.  100% de-serialization, 
no, 99.99% -- yes.  

The alternative is to serialize entire TRANSACTIONS...


that is recursive SQL, everytime you advance the sequence in the SGA beyond the cache size, we need 
to update a database table in a recursive (autonomous) transaction 

3 stars Strong reason   December 19, 2002 - 1am Central time zone
Reviewer: Tony from India
  Tom, You say that gap free numbers are not required at all. I hope you will agree with the 
following case:
  Generated numbers should have built-in intelligence so that end users will easily identify the 
counts and other business related thing. For example, prefixing purchase order number with vendor 
code will defintely help the end users to know the vendor by merely seeing the PO number. Only 
numbers (PO number, Request number, voucher number...etc) with lot of gaps will confuse the users. 
There are valid reasons , as above, to have gap free numbers. We can't ignore the importance of gap 
free numbers just becoz Oracle doesn't have the feature.





 


Followup   December 19, 2002 - 7am Central time zone:

I disagree totally, 100%

Your argument will be "well, they used to use paper and the paper was sequentially numbered.  they 
relied on that number".

My counter argument will be "well, I just spilled my coffee on your tablet of paper destroying the 
top 20 pieces of paper.  I put them in the garbage.  Did the business shutdown?  No, of course 
not".

We void checks all of the time.  Same thing.


If your end users rely on "counts" embedded in a number, they are getting BAD information.  Period. 
 There are cancelled orders.  There will be undone transactions.  The counts will be *wrong*.  

Knowing the vendor by looking at the "po" number -- trivial.  the PO number is obviously a compound 
field on a printed report -- eg:

select vendor_id || '-' || primary_key PO_NUMBER, ....
  from table 



If gaps confuse users -- it is only because you told them there was some implied meaning to it.  
There is no other reason -- cause the old paper based system sure couldn't have taught them this. 

5 stars   December 19, 2002 - 8am Central time zone
Reviewer: Jeff Larimore from Miami, Florida
Tom,

Is Oracle considering creating a column type of IDENTITY whereby Oracle will automatically assign a 
unique value to a column?

This would create a sequence tied to the column automatically and would not require the user to 
define a sequence for the column, and then create an insert trigger to call it, which you I know 
you recommend against.

I've seen this in other DBMS servers and have found it extremely user-friendly, self-documenting 
and convienient.

Thank you,
Jeff 


Followup   December 19, 2002 - 9am Central time zone:

I will submit this to the people that can make it happen... 

5 stars That nasty word "embedded"   December 19, 2002 - 11am Central time zone
Reviewer: Connor McDonald from UK
The problem with "informational" columns, for example, the PO number telling you how many there 
are, is that it breaks a lot of the rules for relational databases.  Scalar columns represent an 
attribute (singular not plural).

There is nothing worse than being forced to work on a system where column P contains "02X3751" 
because it was

- create in the year '02'
- is of type 'X'
- is the 3751'st recording of such
Ugh!!  It doesn't take long before your start seeing hideous queries like:

where substr(P,4,4) = '3751'

and voila! Welcome to function-based-index heaven...

What's wrong with a year, type, and occurrence column ? 


Followup   December 19, 2002 - 11am Central time zone:

exactly -- and then a view to synthesize these "human friendly" things

select vendor_id || '-' || primary_key PO_NUMBER, ....
  from table 


people do seem to have an irrational fear of views for some reason.... 

store the data in its component pieces, glue them together however you see fit on OUTPUT.


 

4 stars   December 19, 2002 - 12pm Central time zone
Reviewer: Tianhua Wu from Atlanta, GA
I agree in most case the gap should not be a problem at all.  However, in some country (e.g. 
Italy), you can not have the gap by law (if I understood correctly). 


Followup   December 19, 2002 - 1pm Central time zone:

what did they do when the coffee got spilt?

what do they do when a customer cancels an order?

what would be the purpose of such a law?  I mean -- what is to stop me from just creating a dummy 
order for $0 or just to go back and put the orders in out of sequence.

I would just create a view:

select a.*, rownum LAW_ABIDING_STUFF from t;

I guess.... no gaps there and just as meaningful! 

3 stars Sequence generation   December 19, 2002 - 4pm Central time zone
Reviewer: pk from alaska
For sequence generation why don't you do this :-
PK>create table temp1(id number(12));

Table created.

Elapsed: 00:00:00.51
PK>select * from temp1;

no rows selected

Elapsed: 00:00:00.10
PK>select nvl(max(id),0) + 1 seq_num from temp1;

   SEQ_NUM
----------
         1

Elapsed: 00:00:00.31
PK> 


Followup   December 19, 2002 - 6pm Central time zone:

can you spell "serialization"

I can, you just did in SQL ;)


read:
http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:3379873654938
I *hate* that method more than most anything you can do (well, not as much as not using bind 
variables -- but a very very close second)
 

5 stars Try this then...   December 19, 2002 - 5pm Central time zone
Reviewer: Connor McDonald from UK
session 1:
  select max(...)+1

session 2:
  select max(...)+1

Ooops....data corruption. 


3 stars   December 20, 2002 - 12am Central time zone
Reviewer: Dave from Ohio
Tianhua's point is an important one, and the legal requirement to avoid gaps in sequences is a real 
one in many countries.

Commonly it applies to tax-related "documents" such as invoices -- if a tax authority finds a 
missing value in a sequence of invoices it raises a red flag to them that there is something fishy 
going on (although I have to add that even if there were no apparant rationale for the law, it has 
to be complied with if only because a company will be prosecuted and fined for not being in 
compliance. They will then sue their software vendor.)  For all the scenarios of spilt coffee, 
cancelled orders, dummy orders etc. there is a legally sanctioned resolution.

The view-method would be legally unacceptable as the invoice number must not be subject to change.

However that doesn't mean that you have to cripple the performance of your application by 
serializing the generation of invoices, for example. Consider whether you could PK the invoice with 
a regular (performant) methodology, then update the records later on as a batch process, such as 
...

update invoices set invoice_number=inv_seq.next_val;

... or ...

select max(invoice_number) from invoices into l_max_inv_number;
update invoices set invoice_number=l_max_inv_number+rownum
where invoice_number is null;

You can put a unique constraint on the nullable invoice_number field, and maybe a function-based 
index also to give fast identification of the null invoice number rows.

Tom, I'm not familiar with Oracle Applications, but perhaps you could get someone from the 
Applications team to address how they deal with requirements like this -- I bet that they are 
familiar with the scenario, and have a way of coping with it.
 


Followup   December 20, 2002 - 8am Central time zone:

But my point seems to be getting totally missed.

anyway.

you next_val -- not gap free. 100% not gap fere.

Your select max(), not very concurrent (eg: leads to duplicates out the wahzoo)...


They do it like you would with your checkbook.  It is called a "void".  fill in dummy records.  
Assign the numbers when you close the books, not when filling them.

Tell me -- what happened when someone spilt coffee on the invoice forms???

 

4 stars   December 20, 2002 - 12am Central time zone
Reviewer: Tianhua Wu from Atlanta, GA
select a.*, rownum LAW_ABIDING_STUFF from t;
...

Unfortunately, the rownum will be different for the same record in different queries.

The law is law, there are not too much we can do about it.  And it indeed makes life much 
difficult.  On the other hand, it may generate new positions.  :) 


5 stars Hmmmm   December 20, 2002 - 8am Central time zone
Reviewer: George Johnson from UK
I totally accept the gap-free argument, I can't see what the problem is, if numbers are skipped due 
to cancellations, employee incompetance (split coffee), then surely simply keeping an official 
record that missed numbers are "voided" should satisfy TAX officials, but I guess my real question 
would be, what on earth is a "whazoo"? (I'm from the UK you see.)

Tks in adv 


Followup   December 20, 2002 - 8am Central time zone:

I guess I spelled it wrong ;)

Main Entry: wa·zoo
Pronunciation: (")wä-'zü
Function: noun
Etymology: origin unknown
Date: 1983
- up the wazoo also out the wazoo : in excess <we've got lawyers up the wazoo -- Steven Bochco>

http://www.m-w.com/cgi-bin/dictionary?va=wazoo

3 stars   December 20, 2002 - 8am Central time zone
Reviewer: Dave from Ohio
I understand your point, which is that gap-free sequences are logically meaningless and highly 
non-concurrent, no? However the point that I was helping to make is even more simple --  it is a 
legal requirement in many cases to have gap-free sequences. Full-stop, that's it. We may not like 
it, it may not be logical, it may not be performant, but it is the law. What software house or 
development team can afford to have a policy that legal requirements can be ignored?

It was my intention that the methods I suggested should allow concurrency in generating the new 
records by delaying the attempt to generate gap-free sequences until after the insert. The methods 
were to be implemented as a post-creation batch job (say DBMS_JOB every few minutes) which would 
not have to compete with other sessions for the invoice_number sequence, or would not have to use a 
sequence at all. In either case it would be a single update process.

When someone spilt coffee on the form, you kept the damaged form to show the authorities. If an 
invoice is generated incorrectly it is kept, marked as void, and regenerated under a new number. 


Followup   December 20, 2002 - 8am Central time zone:

The "gap free" numbers can (and should be) assigned after the fact, during a bulk process, the 
closing of the books.  I did not realize that is what you were also proposing.  I see the next_val 
in there -- that'll never work.  sequences by definition promise NOT to be gap free.

Ok, someone drops the cigarrette on the form...
The form was left in the rain, totally obliterating it...
The forms blew away in a wind storm...
<any one of 1,000 other scenarios>

 

3 stars Legal reasons   December 20, 2002 - 9am Central time zone
Reviewer: Tony 
Tom, in our country also, gap-free invoice, voucher numbers are mandatory in legal terms. Even if 
we happen to generate wrong voucher, it can be cancelled. But the cancelled vouchers should be in 
the system during auditing. If the voucher is hand written one , we can atleast try to convince the 
auditors to some extent saying that its lost. As we use computers, we can't convince the auditors. 
we can't say that performance/concurrency is the reason for not having gap-free numbers.
 


Followup   December 20, 2002 - 9am Central time zone:

assign the numbers in a batch process AFTER the fact.

does it matter if the number is assigned right now, this instant.  Or tonight at midnight.

(funny, the fact that computer wise we can assign these numbers *after the fact* makes them *ever 
less meaningless*, they are useless for any purpose -- except to consume disk space of course)

 

5 stars Federal Regulations and Sequences   December 20, 2002 - 10am Central time zone
Reviewer: Pedro Diaz from Dominican Republic
Well, here I go...
In my country You have to match the pre-printed document number with the computer generated number, 
it is restricted by laws to have a gap in any case. To make things more dificult EVERY branch 
office need its own sequence and it most be GAP FREE.

We tray many ways but no one gets it done.  We have:

A. SELECT MAX( NVL( invoice_num, 0) ) +1 
    FROM invoices 
      WHERE branch_office = :branch_num

B. SELECT Last_invoice + 1
    FROM branch_sequences
    Where branch_office = :branch_num

C. The Trigger / Package Approach:
create or replace package body invoice_sequence_pkg is

   type sequence_type is table of invoices.invoice_num%type
                          index by binary_integer;

   type branch_office_type is table of invoices.branch_num%type
                          index by binary_integer;

   sequence_table  sequence_type;

   branch_table    branch_office_type;


   CURSOR last_sequence is
      SELECT A.branch_num, NVL( max( A.invoice_num ), 0 ) last_invoice
        FROM invoices A
        WHERE invoice_date >='01-Jul-01'
      GROUP BY a.branch_num;


   procedure Init_tables is
   begin

         actual_sequence    := 0;

      sequence_table.delete;

         branch_table.delete;

   end;

   procedure Sequence_Branch_Office is
   begin
     FOR branch_sequence IN last_sequence LOOP
        sequence_table( branch_sequence.branch_num ) := branch_sequence.last_invoice;
     END LOOP;
   end Sequence_Branch_Office;


   function netx_sequence( branch_num_in in invoices.branch_num%type) return 
invoices.invoice_num%type is
   begin
      return ( NVL ( sequence_table( cbranch_num_in ), 0 ) + 1 );
   end;

end invoice_sequence_pkg;

Calling it from Statement lavel and Row Level triggers in invoice table.

Its one of this correct, helpfull, or does exists any better way to do it. 


Followup   December 20, 2002 - 11am Central time zone:

short of moving?

you should do it like this:

  UPDATE branch_sequences
     set last_invoice = last_invoice+1
   where branch_offset = :branch_num
  RETURNING last_invoice into :invoice_number;

  if (sql%rowcount = 0)
  then
      do the insert of 1
  end if;

you want to use the UPDATE, not a select, in order to impose serialization and avoid artificial 
"dups" that will cause transactions to fail.

 

5 stars Sequences are just that Sequential   December 20, 2002 - 4pm Central time zone
Reviewer: Jeff Larimore from Sunny Miami Florida
Great topic!  

It seems clear that there will be a requirement for a geometric sequence generator (no gaps) in 
some app somewhere.

Now if gaps or serialization are not important, then simply a unique random number would do.

1.  Sequence - generates a series of numbers in order. -Oracle has this, its called a Sequence.

2.  Geometric sequence - generates a series of numbers whereby each term differs from previous term 
by same amount, ie 1,2,3 or 10,20,30., no gaps  - We need this from Oracle.


Tom,
I tried once to put something like seq.nextval in the default value of a column, hoping that this 
would fool Oracle into automatically grabbing the next value of the sequence if none was specified 
for the column on insert.

I believe it didn't like that, but felt this was a smooth way of creating the equivalent of an 
IDENTITY column.

Have you got a way to make that work?

Thanks,
Jeff 


Followup   December 20, 2002 - 8pm Central time zone:

you use a trigger + sequence to accomplish that.

"geometric sequence" as you call it -- you already got it:

create table gseqs ( name varchar2(30), val int );

create or replace function gseq_nextval( p_name in varchar2 ) return number
as
   l_val number;
begin
   update gseqs 
      set val = val+1
    where name = p_name
   returning val into l_val;

   if ( sql%rowcount = 0 ) 
   then
        raise_application_error( -20001, 'No such sequence exists' );
   end if;
   return l_val;
end;


 

5 stars What is this system sequence IDGEN1$.   February 26, 2004 - 3am Central time zone
Reviewer: Saibabu Devabhaktuni from San Jose, CA USA.
Hi Tom,

I was hoping may be you could shed some light on this question:

What is this Sequence "IDGEN1$" is used for. I think
it has some relation with "ID_GENS$" table.

"ID_GENS$" table has a single row telling how many of
total id generators are in effect.

I did a google search on it, not even a single useful link, and metalink is more of a make up to 
Oracle documentation. How does Oracle use this sequence IDGEN1$ and for what purpose. I understand, 
we don't need to dig too deep in to internals, but it won't take anything away from Oracle. Every 
other software vendors provide documentation/support or some forums way too deep in to details than 
Oracle does. Is this a strategy of keeping complexity unexposed attract more people bind to it? 


Followup   February 26, 2004 - 10am Central time zone:

Umm, every other vendor?  Really.  Where is the MS internals website for sqlserver?  and IBM's for 
DB2 (well, they'd need quite a few actually given they have so many flavors of DB2 and then 
informix and redbrick and so on -- something like 7 or 8 RDBMS's).

Let me ask you -- why do you need to know?  Is it causing some issue on your system?   

5 stars sequence and remote table changes   July 22, 2004 - 4am Central time zone
Reviewer: bn 
Hello Tom,

Pls suggest something for our situation.

Situation:
We have same dabase schema on 2 different servers.
Loadings happen on server S1 and the schema tables are then copied onto Server S2(truncate n reload 
with one-to-one mapping). 
In a general situation Web interfaces work with S2 and log table entries happen from interfaces.
Our plan is to be able to use S1 when S2 cant be available.

To achieve this we have to make sure that
1. Log table entries are to be made in both S1 and S2.
2. Sequence numbers of the log table entries should be same on both S1 and S2.
3. When one goes down and comes up, the changes on the other server during the down time are to be 
copied to keep the data in sync.

My plans is
1) I use insert/update over db link.
2) In my opinion i can use the following .
   update gseqs 
   set val = val+1
   where name = p_name
   returning val into l_val;
I think if i use database sequences i cant keep them in sync.
3) Run some stored procedures to copy the changes occured during the down time.

Pls make corrections/suggestions or suggest alternatives.
Also throw light on potential pitfalls.

TIA 


Followup   July 22, 2004 - 7am Central time zone:

you want to use data guard if your concept is to have a DR/failover site.

do not attempt to "do it yourself", this technology is well known, long in the tooth, and already 
written.

use database sequences -- don't even consider doing it yourself. 

4 stars sequence and remote table changes   July 22, 2004 - 9am Central time zone
Reviewer: bn 
 Thanks for the comments TOM.

As per the little understanding i have "data guard" needs to have standby database and we are going 
in that direction soon.

Currently our application( office hours only) is not a very critical one.
Both datawarehouse and datamart are on the same database (9ir1).For some reasons our strategy of 
loading Datamart is truncate/reload which takes 2-3 hours.If the loading batch starts late users 
cant have data until its complete.

To avoid such long delay we plan to have one another database for Datamarts on a different 
server.This will be loaded from the existing datamart. The loading is one to one as business logic 
is already applied and it may take 10 minutes to truncate and reload. 
In this way the time is cut down from 2-3 hours to 10 minutes.

I hope i made you understand our environment.

Since we will have data available in two places we thought of designing something to keep the them 
entirely in sync, i.e by ensuring that all the changes done
by the Web interface are written into both servers. 
This kind of standby system( in some sense) is not very critical to our system but as an add-on.

So i think i will have to build some logic to achieve this.

Pls provide your comments on my last posting in new scenario. 
I failed to understand why you said "use database sequences -- don't even consider doing it 
yourself."
When should we use 
     update gseqs set val = val+1
     where name = p_name
     returning val into l_val;
TIA 


Followup   July 23, 2004 - 7am Central time zone:

if you build logic, you are on your own.

if you want it done for you instantly, dataguard.  you have totally described to me "i want 
dataguard, i want a standby database for failover"

using your own database sequences = i will serialize all of my transactions making Oracle appear to 
be the slowest database on the planet.  It is, will be, and has been the worst idea -- use 
sequences, use proper techniques -- seriously.  standby technology exists, you own it, it is there 
- just start using it.


short of that, use read only replication -- and if sequences are an "issue", simply:

create sequence s start with 1 increment by 10;  <=== at site 1
create sequence s start with 2 increment by 10;  <=== at site 2

and then they will generate their own unique streams of numbers without overlaps. 

4 stars If no gaps are permitted for legal reasons...   July 22, 2004 - 10am Central time zone
Reviewer: Adam Musch from Omaha, NE, USA
... then fill them in as part of the close process.

Assuming the example of invoice numbers, one would know both the first and the last valid invoices 
for the financial period.  It should then be simple to fill in the gaps.

SQL> create table invoices (invoice_id number, invoice_type varchar2(10))
  2  /

Table created.

SQL> 
SQL> insert into invoices
  2  select rownum invoice_id, 'VALID' as invoice_type
  3    from all_objects
  4  /

13820 rows created.

SQL> 
SQL> alter table invoices 
  2    add constraint pk_invoices 
  3      primary key (invoice_id)
  4  /

Table altered.

SQL> 
SQL> -- find valid ranges of invoices
SQL> select min(invoice_id), max(invoice_id) from invoices
  2  /

MIN(INVOICE_ID) MAX(INVOICE_ID)
--------------- ---------------
              1           13820

SQL> 
SQL> -- create gaps in invoice range
SQL> delete from invoices
  2   where mod(invoice_id, 20) = 0
  3     and invoice_id != (select min(invoice_id) from invoices)
  4     and invoice_id != (select max(invoice_id) from invoices)
  5  /

690 rows deleted.

SQL> 
SQL> -- fill gaps in invoice range
SQL> declare
  2    l_min_invoice_id number;
  3    l_max_invoice_id number;
  4  begin
  5    select min(invoice_id), max(invoice_id)
  6      into l_min_invoice_id, l_max_invoice_id
  7      from invoices;
  8  
  9    for i in l_min_invoice_id..l_max_invoice_id
 10    loop
 11      begin
 12        insert into invoices
 13        values (i, 'VOID');
 14      exception
 15        when DUP_VAL_ON_INDEX then
 16          null;
 17      end;
 18    end loop;
 19    commit;
 20  end;
 21  /    

PL/SQL procedure successfully completed.

SQL> 
SQL> select invoice_type, count(*)
  2    from invoices
  3   group by invoice_type
  4  /

INVOICE_TY   COUNT(*)
---------- ----------
VALID           13130
VOID              690

SQL> select min(invoice_id), max(invoice_id), count(invoice_id)
  2    from invoices;

MIN(INVOICE_ID) MAX(INVOICE_ID) COUNT(INVOICE_ID)
--------------- --------------- -----------------
              1           13820             13820

Functionally gap-free.  There's almost certainly a more elagant way to fill the gaps than I did, 
but it suffices for the purposes of this example. 


4 stars sequence and remote table changes   July 26, 2004 - 10am Central time zone
Reviewer: bn 
Thanks again TOM ,

Certainly "dataguard" would be the best. But when i refresh the datamart(truncate/reload) should i 
do it on two databases or "dataguard" will take care of it in standby database !!

I still dont get convinced of its necessity in our case. Out of 5 schemas in the database only one 
schema needs to be kept in sync. That too 3-4 tables only. Pls comment.

You suggested "read only replication" .. is it same as "read only snapshots" !!! pls corrent if 
wrong.I find several threads regarding it. May be that will fit us.

I think the solution you suggested regarding sequence will not work for us because our requirement 
is that site1 and site2 should have same sequnce for the same record.Is there any other way !!

There will be hardly 1000 transactions a day.If there is no other way, then using a table record 
may not be a big overhead. Pls comment on it.

I was curious about where to use the following solution which was suggested by you in this same 
thread.
------
   update gseqs 
      set val = val+1
    where name = p_name
   returning val into l_val;
------


TIA
 


Followup   July 26, 2004 - 11am Central time zone:

dataguard deals with that.

logical standby can selectively do certain tables.
replication certainly does selective tables.

snapshots = readonly replication = materialized views.


site1 and site2 would have the same sequence id's for records -- it is just that a sequence 
generated at site1 would be different from, unique with regards to, a sequence generated at site2 
-- but if site1 created a record and it was replicated to site2 -- it would have the same id of 
course.


 

4 stars sequence and remote table changes   July 27, 2004 - 10am Central time zone
Reviewer: bn 
TOM,

Thanks for clearing sequences issue at site1 and site2.

I started going through Oracle9i Streams concepts.
Looks very good for my case and apprears to be alternative to snapshots.

Pls advise on using streams/snapshots.

TIA
 


Followup   July 27, 2004 - 12pm Central time zone:

if you can use streams -- it is the preferred method going forward. 

4 stars Assigning new field id inside trigger   October 21, 2004 - 10am Central time zone
Reviewer: Teymur Hajiyev from Azerbaijan
Dear Tom.

An application inserting records into t1. Now I want add new field and set it to seq.nextval. Below 
is my trigger:

CREATE OR REPLACE TRIGGER "My"."Test_Ins" BEFORE
INSERT ON "My"."TEST" FOR EACH ROW 
declare
seq_num number;
BEGIN 

select f1_rowid.nextval into seq_num from dual;

update test set RID = seq_num  where rid is null;

END;

--------

It work, but there is problem:

Assume that there is no any record:

Now after writing trigger, I inserted new record:
RID   F
      1

But RID didn't changed.

Now adding new record:
RID   F
1     1
      2

Oops, RID now changed, but not inserting record, record which inserted before.

Thanks in advance. 


Followup   October 21, 2004 - 2pm Central time zone:

boy, that is the wrong way to do this -- way way wrong way.

try this:

insert into t select null, null from dual;

opps - mutating table.  (and do you really want to FULL SCAN this table each time to update?????)

(you don't really have a schema "My" do you?  mixed case would be a horrible terrifically bad idea)


CREATE OR REPLACE TRIGGER test_ins before insert on test for each row
begin
   select f1_rowid.nextval into :new.rid from dual;
end;


before jumping head first into Oracle from sqlserver -- you might want to read:

a) concepts guide
b) application developers guide

you won't regret the hours it takes to at least skim them -- never. 

3 stars Skipping sequences   December 23, 2004 - 12pm Central time zone
Reviewer: J1 
Tom,

Why does sequences skip once in a while?  What is the logic behind that?  Is there any init 
parameter for that?

Happy Holidays!

Thanks. 


Followup   December 23, 2004 - 12pm Central time zone:

sequences have a default cache (10 -- you should seriously consider upping that to 100 or 1000)....


so, you say "select s.nextval from dual" -- that'll get 1..10 loaded up in the SGA.  You get 1.  
2..10 are still there.

If

a) you shutdown abort -- 2..10 gone
b) have the sequence get aged out of the shared pool -- 2..10 gone
c) select s.nextval, select s.nextval, rollback -- 2..3 gone.

for example.  

sequences are never never never going to be gap free, just unique.   

5 stars   December 23, 2004 - 2pm Central time zone
Reviewer: J1 


4 stars Seg.nextval   February 9, 2005 - 1am Central time zone
Reviewer: Anil from Dubai
Hi Tom 


Which is better

CREATE OR REPLACE TRIGGER test_ins before insert on test for each row
begin
   select f1_rowid.nextval into :new.rid from dual;
end;

or 

CREATE OR REPLACE TRIGGER test_ins before insert on test for each row
begin
   :new.rid:= f1_rowid.nextval;
end;



Rgds
Anil  


Followup   February 9, 2005 - 2pm Central time zone:

well, since only one of them will compile -- I'll pick the one that doesn't compile -- the 2cd one.

it won't compile and that is good, because the "best" way is:

insert into test_ins( rid, .... ) values ( f1_rowid.nextval, ..... );


short of that, the first one looks like it will compile... 

4 stars Sequence   February 10, 2005 - 1am Central time zone
Reviewer: Anil from Dubai
Sorry for that Tom, I should have compiled it before sending it.

But to set the new values only way is 

select poc.nextval into :new.XTRASNACTION_ID from dual;

since I cannot use the following to set the new value in a trigger!!
insert into test_ins( rid, .... ) values ( f1_rowid.nextval, ..... );

Sorry once again , 

Thanks & Rgds
Anil  


Followup   February 10, 2005 - 2am Central time zone:

i'm trying to imply that the trigger is not to be used at all

the BEST, most performant way is for the insert to actually supply the value.  

It is clear in the code that does the insert what is happening
the database will do less work
the trigger is not needed or really even "desirable" here. 

5 stars Sequence   February 10, 2005 - 5am Central time zone
Reviewer: Raghav from India
Hi Tom,

While the system generated sequence is used, and there is a some time gap while the next number is 
generated (suppose for example 10 minutes) shared pool (where sequences are cached) are aged out. 
When the next number is it has left 20 numbers and generated the next sequence number. Like in the 
prior case as it has given a 5 numbers difference.  Is there any specific number it lefts out. Like 
in his example it is 5 and in my example it is 20?

We have got this problem in the beginning of the implementation of our software and now to come 
across this problem what we are using is we are maintaining a table having transaction type and 
last sequence number and while every transaction being inserted, it will be updated from the this 
table using the last generated sequence number.

In your view, what is the best method. Using the system generated sequences or as we have used in 
our system.
 


Followup   February 11, 2005 - 2am Central time zone:

why is it "a problem".

fact: sequences have gaps
fact: you cannot change prior fact
fact: even if you generated or lost thousands of sequence values per second it would take many 
millions of years to exhaust them


use a sequence. (actually, alter your sequences to cache 1000 and get better performance and don't 
lose sleep over "gaps" - gaps are a fact) 

4 stars Sequences   February 10, 2005 - 5am Central time zone
Reviewer: Anil from Dubai
Yes Tom, In this context sql is the right approach. But setting a value for audit column, say 
created,by created_date etc.. when sqls are generated from a middle tier and not using store 
procedure we have no other option but to use before trigger.

Thanks & Rgds
Anil  


Followup   February 11, 2005 - 2am Central time zone:

sure -- but you see, i was answering the other question about how best to get nextval in there, not 
how best to do something unrelated.

for insert - the sequence should be in the sql.
the "created_date" would be defaulted to sysdate
created_by defaulted to user 


and no trigger would be necessary for insert. 

4 stars Sequence   February 11, 2005 - 6am Central time zone
Reviewer: Anil from Dubai
Right Tom, But default has a limitation. as you said I can use it for setting the created date.

"A DEFAULT expression cannot contain references to PL/SQL functions or to other columns,"

If I want to set the username(not oracle username, but application username which is in a context 
variable set by the application) I can't do this since default does not support user defined 
function.


 Also what about update. So if the SQL is not providing the updated_date we have no other choice at 
the moment other than a before trigger.

Thanks & rgds
Anil  


Followup   February 11, 2005 - 8pm Central time zone:


4 stars sequences   February 11, 2005 - 6am Central time zone
Reviewer: Anil from Dubai
Hi Tom 

" not how best to do something unrelated.'
Sorry for posting a unrelated question. PLeas ignore my latest posting. I am very clear with that.

Thanks once again
rgds
Anil  


4 stars Oki-doki, how about this one...   March 30, 2005 - 7am Central time zone
Reviewer: Dmytro from Kyiv, Ukraine
I really agree with the most things you are talking about, but real life is throwing new & new 
problems where not all can be done in the way we wish...
 A little more about this "gap-free/not-gap-free stuff":
our company is working for one goverment organization, that is registering emmm... i'm a little 
unsure how translate it into english, let it be "enterprises". And this organization wants to 
generate numbers for these enterprises, even created standard for this: number is generated from 
10-digit code of territory & 4-digit number of enterprise (yes-yes-yes, number of territory is also 
stored in some other place too). This last 4-digit number is divided into two intervals 0001..8999 
for physical persons & 9000..9999 for juridical (not sure about terminology) persons.
 So, when we create new enterprise we even not simple look for max(num+1), we search for first 
"free" number (because where can be "gaps" & they really mean something, because of tight bounds of 
allowed numbers) for this territory, check physical\juridical status & create new number...
 So, the question is - are there some ways to increase scalability of system even a little more & 
decrease number of conflicts or there is no such way, that not involves firing half of our 
developers, 90% of architectors and rewriting few laws. We can not dynamically create numbers with 
the view, because number of enterprise must be unchanged "from birth to death"...
 Sorry, for bothering with such perhaps stupid or just ananswarable question...

PS It is related to the previous theme by the thought like: "...perphaps some time people really 
need gap-free sequences... or no?.." ;) 


Followup   March 30, 2005 - 8am Central time zone:

what is the business requirement behind this want.

All you can do is explain to the business the ramifications.  Now given that you have but 9,999 
numbers per territory, this won't be a blazingly high volume request so perhaps serialization at 
the territory level is ok for them (I mean with 9,999 maximum enterprises per territory key, it 
probably isn't going to be much of a scaling issue, territory is the big number -- 6 digits, within 
a territory, you need to serialize)

logic:

lock territory parent record
   search for 4 digit number

 

4 stars Non-intelligent keys, anyone??   March 30, 2005 - 9am Central time zone
Reviewer: Greg from Toronto, Canada
Just to add a follow-up to the previous post:

Dmytro, why wouldn't you create a (proper?) non-intelligent PK using a sequence  .... and yes, 
you'd have gaps ...

Then create another column for these "business-requirements"??  Then you can assign them just about 
anything you wanted, and still be assured you have an reliable, internal id for each row of each 
table ... 

Not sure if that's what Tom's suggesting or not .. but I see this whole "Voucher can't have gaps" 
issue as: "Hey, the voucher id shouldn't be the PK if it's being *used* .. that defies the 
definition of a PK (from what I understand it ... )

Isn't a PK supposed to be a "non-intelligent" value?  That is, a value that is not used by the 
business?  Not given out to anyone .. only used internally .. for things like Foreign Keys, 
identifying a record, etc?

If needed, you can still have a unique index on that other column that the business needs ... if 
the business requirements are that it must be unique .. ;)

I guess that still doesn't solve the problem of "hey we have a business requirement of this column 
- it can't have gaps" .. but that's not a problem to solve with sequences, now, is it??
;)
 


Followup   March 30, 2005 - 10am Central time zone:

(i would prefer the surrogate key and then the other attributed be assigned attributes, but you 
have the same serialization issues, but at least we could move someone from territory 1 to 2 
without massive cascades) 

4 stars Come to think about it...   March 30, 2005 - 9am Central time zone
Reviewer: Dmytro from Kyiv, Ukraine
...yes, you are right, of course... :) It's hard to think, that it will be much a problem if once 
... let's say in few weeks ... some girl with very-very long manicure ;) will be waiting for a few 
moments during registering process of the next enterprise.
 Perhaps my testing environment was a little more demanding than her... :) But still there are 
these awful GUID numbers as PK in almost every table (even in some not-very-big dictionaries!!!) 
and many other stuff, sigh <gone complaining>...

PS Sorry for bothering you and thanks for advice, great as ever... ;)
  


4 stars In fact...   March 30, 2005 - 9am Central time zone
Reviewer: Dmytro from Kyiv, Ukraine
...if there was no requirements for uniquiness, there would be no problems - no locking needed, no 
"duplicate" problem - just insert it and that's all. Problem is in generating new value for this 
field, that can be generated by somebody else in the same moment. But idea to have separate PK is 
interesting... 


4 stars Problem with Sequence After Import   August 24, 2005 - 7am Central time zone
Reviewer: Richard from Buckinghamshire, UK
Oracle8i Release 8.1.7.4.0 - Production

1. export from database "A" performed using owner=foobar - no warnings
2. import into database "B" performed using dump file from above export of "A" - no warnings
3. Upon using database "B", primary key violation occurs when an attempt is made to insert a row 
into table myTable, owned by foobar. A sequence belonging to foobar is used to generate primary key 
values for myTable. So, it looks like the import wrote the sequence to the dump file, and then 
wrote myTable, thus leading to the imported sequence lagging behind the imported table's data.

Would using consistent=y in the export statement solve this? 


Followup   August 24, 2005 - 11am Central time zone:

consistent=y would give you a view of the database at a single point in time, so yes, it would be 
as if all sql were run at the same exact instant. 

5 stars Excellent, thank you!   August 25, 2005 - 3am Central time zone
Reviewer: Richard from Buckinghamshire, UK


4 stars Sequence no   November 26, 2005 - 7am Central time zone
Reviewer: AD from UK
Tom,

Can you please share your views on the following:

I have a requirement where by I have to produce an extract file on a regular basis(monthly), and 
each time I create the file the sequence no (one of the field in the file) should be incremented by 
1. I am wondering whether I shall be using a sequence no as provided by oracle or 
creating/maintaining my own. The only issue is the program should be re-runnable, so in case of an 
error the file should be re-created but the sequence no should be adjusted accordingly. The 
sequence no should be gap free e.g. you should generate 1, 2, 5, 7 but it has to be 1, 2, 3, 4, and 
so on.

Many thanks in advance
 


Followup   November 26, 2005 - 12pm Central time zone:

sequences in Oracle (in any database that supports a concept of a surrogate key generator) and 
never gap free.  They will not be incremented by 1.

 

3 stars please clarify   January 10, 2006 - 5am Central time zone
Reviewer: Kumar from Pune,India
SQL> create sequence s
  2  /

Sequence created.

1) SQL> select s.nextval,s.nextval,s.nextval from dual
     2  /

   NEXTVAL    NEXTVAL    NEXTVAL
---------- ---------- ----------
         1          1          1

1 row selected.

I thought sequence values would come as 1,2,3.
But why it returns like this??


2)
SQL> select s.nextval from dual
  2  union all
  3  select s.nextval from dual
  4  union all
  5  select s.nextval from dual
  6  /
select s.nextval from dual
         *
ERROR at line 1:
ORA-02287: sequence number not allowed here


why this statement fails?? 


Followup   January 10, 2006 - 8am Central time zone:

nextval and currval are documented as having the above behavior (that nextval and currval are 
evaluated "consistently" like that)

http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/sql_elements6a.htm#80564
technically I believe the sequence should be OK in a UNION ALL or the documentation  is missing the 
fact that you cannot (here are the restrictions:
http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/sql_elements6a.htm#111114
) 

 

5 stars Question about Oracle Projects Draft Invoices   January 19, 2006 - 6pm Central time zone
Reviewer: A reader 
I read this thread about gaps and wanted to get your take on Oracle Projects and how they generate 
draft invoices.  I realize there is a very good chance that just because you work for Oracle you 
have never used it and know nothing about it.  But here goes anyway.

In Oracle Projects, the draft invoices table (pa_draft_invoices_all) has a composite primary key of 
project_id and draft_invoice_num.  The draft invoice number ALWAYS starts at 1 for every project, 
and is ALWAYS gap free for each project.  If you cancel an invoice, it just sets a flag and the 
next invoice continues on with the next number.  This is stored that way in the base table itself, 
and not through a ranked analytical function in a view.  Any views that the forms use just select 
from this column directly as well (so they are not doing anything special).

Could you shed some light as to why they decided to go with a gap-free solution instead of 
implementing this in views?   I'm just curious because you always question the business 
justification for a solution like this, and Oracle itself has implemented it.  Obviously Oracle 
Applications would be used in a setting with thousands of users - so why do you think they chose to 
serialize this process?  Since all of the forms are built off of views, why not just create a 
sequence and build the gap free number in the view using analytics?

Secondly, I was curious if you knew how they actually do it.  The draft invoice number gets 
assigned at the time an invoice is created, so it must lock the table somehow.  I was just curious 
for my own knowledge more than anything.

Hopefully this made sense!  Keep up the good work.     


4 stars Sequences   March 7, 2006 - 12pm Central time zone
Reviewer: Steve from UK
Tom.

Like it or not, it is sometimes desirable to have a geometric sequence (in the general sense of the 
word, not the Oracle sense).

Cases in question: where it is legally binding to have a continuous sequence; where you rely on a 
number for serialisation purposes (e.g. over some kind of IPC) - a gap in such a sequence 
indicating an error or omission.

My cheques come numbered in order, and I have never seen a gap. If a cheque is voided by me, it 
still has the number. It is just never used and never appears on my statement. The number was 
however initially generated.

Hypothesising, I would imagine that in most scenarios of the "coffee on paper" example, important 
documents would not be allowed to just be thrown away with no kind of audit trail, even if they had 
had coffee spilled on them. If they had been inadvertently burnt with a cigarette, I would imagine 
this would involve a business process to account for such a missing form, and one that (a) you 
wouldn't want to repeat frequently or (b) involved some kind of reprimand.

In Oracle terms, a sequence is used as you say to generate a *unique* number, not a gap-free 
numerical sequence. This does not mean that every possible context in which one wishes to use such 
a numerical sequence is invalid because of Oracle's implementation. If my remit is to provide a 
continuous integral sequence, that is what I must do.

Out of interest, our workaround is messy and necessary, and involves us using our own sequences 
which contain gaps, and having to identify when a gap is legitimate (e.g. rollback transaction) or 
not legitimate (a table has been cleansed of old data leaving gaps). Using SQL Server would have 
spared all these problems due to the IDENTITY type. 


Followup   March 8, 2006 - 4pm Central time zone:

I have never seen a true "legally binding" thing - for you see, coffee would get spilled in the 
past before computers.

Have you ever lost a check book?  I have.

Have you ever voided a check?  I have.

Have you ever spilled something ruining some checks? I have.

You just gave the perfect example. 

4 stars Double Sequences   March 8, 2006 - 6pm Central time zone
Reviewer: Martin from Columbia, MD
Hi Tom,
 I have seen this question many times over the years. I thought I would give a solution I have used 
over the years when record id's could not be lost.

 The process is not very efficient, but is very effective. I also do not recommend this for primary 
keys but works well for unique business logic type columns(check numbers, po numbers)

CREATE TABLE CHECKS
(CHECK_KEY number(10) primary key,
 CHECK_NO number(10) unique,
 CHECK_STATUS char(1) default 'T',
 AMOUNT number(10,2));

CREATE SEQUENCE CHECK_NO_TEMP_SEQ
start with 1000000
cache 20;

CREATE SEQUENCE CHECK_NO_PERM_SEQ
start with 2000000
nocache;

How it works:
We use a before insert trigger in the checks table
to give the CHECK_NO a value from the TEMP sequence and we set the STATUS to 'T' or whatever to 
indicate temp sequence was used. Let the database do what it wants. Skip whole sets of numbers, 
whatever.

Part 2 can be accomplished any number of ways including a  job that runs several times per hour - 
or even a nightly batch job(best technique).
 This job then takes the records that have a STATUS of 'T' and replaces the TEMP sequence with a 
number generated by the PERM sequence. If perm process fails, dba gets notified and has to take 
corrective actions.

The users can easily spot the temp and perm numbers because the order of magnitude and/or 
visibility of the STATUS flag. 


Followup   March 9, 2006 - 1pm Central time zone:

sorry, I will continue to disagree with the very premise that gaps cannot be tolerated.

For all of HUMAN HISTORY they have been.  Fact.


 

5 stars sequence gap free   March 9, 2006 - 12am Central time zone
Reviewer: Umesh Kasturi from Bangalore , India
I do agree with you that sequences can never be gap free.

My client has 10 different letter_type which are stored in same table and he wants to maintain the 
"sequence of numbers " for each letter_type  so that by looking at the number he can say how many 
letters are there in a letter_type? 

primary key is (letter_type,letter_number)for table "all_letters" holding all the letters.

should I go for another table "letter_seq_master" as below to capture the last seq_value for a 
particular letter

"letter_seq_master"

letter_type   last_seq_value
---------------------------
ordinary      11
special       9
extra         4

when he receives the next ordinary letter he wants to store ord and 12

when he receives the next special letter he wants to store spl and 10

when I insert a letter into all_letters . I pick up the value from "letter_seq_master" and populate 
the next letter number 

should i follow this approach or just have "gapped" sequence numbers across the letter types
 


Followup   March 9, 2006 - 1pm Central time zone:

I'd rather either

a) compute that number as he requests it (on the firm belief they won't request it very often!!!)

b) maintain a rollup via a materialized view with the aggregate count.

clients do not design databases.
clients have business requirements (I need to know how many....), WE implement physical designs to 
satisfy that. 

4 stars Use a view people!! You don't need a sequence!!   March 9, 2006 - 9am Central time zone
Reviewer: Greg from Toronto, Ontario
Seriously ... if you need "gap free" ... consider using a view  .. something like this:


gregs-DEV > drop table cheque;

Table dropped.

gregs-DEV > 
gregs-DEV > create table cheque
  2    ( cheque_id        number,
  3      account_num   number,
  4      cto            varchar2(1000),
  5      cfrom          varchar2(1000),
  6      amount        number )
  7  /

Table created.

gregs-DEV > 
gregs-DEV > alter table cheque add constraint cheque_pk primary key ( cheque_id )
  2  /

Table altered.

gregs-DEV > 
gregs-DEV > -- I already created this .. no big deal . just got bigger numbers to show you ...
gregs-DEV > create sequence seq_cheque_ids nocycle nomaxvalue
  2  /
create sequence seq_cheque_ids nocycle nomaxvalue
                *
ERROR at line 1:
ORA-00955: name is already used by an existing object


gregs-DEV > 
gregs-DEV > create or replace view v_cheque
  2    as ( select cheque_id,
  3                account_num,
  4                row_number() over ( partition by account_num order by cheque_id ) + 100   
cheque_num,
  5                cto,
  6                cfrom,
  7                amount
  8           from cheque )
  9  /

View created.

gregs-DEV > 
gregs-DEV > -- populate with some random data ..
gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > -- create gaps in the sequence
gregs-DEV > rollback;

Rollback complete.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > commit;

Commit complete.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > rollback;

Rollback complete.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > insert into cheque
  2    values ( seq_cheque_ids.nextval, trunc ( dbms_random.value ( 100000, 999999 ) ),
  3                                     dbms_random.string ( 'a', 20 ), dbms_random.string ( 'a', 
20 ),
  4                               dbms_random.value ( 10, 1000 ) )
  5  /

1 row created.

gregs-DEV > commit;

Commit complete.

gregs-DEV > -- duplicate a few records/accounts so we can see the cheque numbers ...
gregs-DEV > insert into cheque
  2    ( select seq_cheque_ids.nextval, account_num, dbms_random.string ( 'a', 20 ), cfrom, 
dbms_random.value ( 10, 1000) from cheque )
  3  /

4 rows created.

gregs-DEV > insert into cheque
  2    ( select seq_cheque_ids.nextval, account_num, dbms_random.string ( 'a', 20 ), cfrom, 
dbms_random.value ( 10, 1000) from cheque
  3             where rownum < 3 )
  4  /

2 rows created.

gregs-DEV > commit;

Commit complete.

gregs-DEV > 
gregs-DEV > -- and viola ... presto - chango!!
gregs-DEV > break on account_num skip 1
gregs-DEV > select * from v_cheque order by account_num, cheque_num;

 CHEQUE_ID ACCOUNT_NUM CHEQUE_NUM CTO                            CFROM                              
AMOUNT
---------- ----------- ---------- ------------------------------ ------------------------------ 
----------
       168      195618        101 NGXkjEHpNnWFWo_qaAQR           G[jeGatg`ngiLP\H_WLr           
910.618819
       172                    102 TLYIcNbF`iIUVmWpCi^a           G[jeGatg`ngiLP\H_WLr           
732.945593

       163      845567        101 rgMdGYMtJeNofJ\tgoOW           WFYs]GkfUhhYOrEiIrTL           
495.269658
       169                    102 ^SflYRgHfI[J]kUhX]Us           WFYs]GkfUhhYOrEiIrTL           
873.013064
       173                    103 PaGNkGOQftgUeqEjkDSn           WFYs]GkfUhhYOrEiIrTL           
701.278641

       167      931387        101 `NN_mEBK`U`tLISpGa\E           mfR[PQdCHMPqoUFGUkTd           
756.177798
       171                    102 iV]IsgE\]PpWE\_gIPKO           mfR[PQdCHMPqoUFGUkTd            
727.31892

       164      968983        101 XLOahdWP\cUhjZnCV\MA           YYcScnHoLLmgcefLcsWR           
406.852995
       170                    102 dYIsMAQkn]_cDstGWNSI           YYcScnHoLLmgcefLcsWR           
241.576482
       174                    103 qfint_TPiB[olbC_Wtsb           YYcScnHoLLmgcefLcsWR           
831.687898


10 rows selected.

gregs-DEV > 


Tom .. can I say it??? Can I?? Please, please, please!??
:)

Analytics Rock & Roll!!
:P
 


4 stars SEQUENCE   March 29, 2006 - 5am Central time zone
Reviewer: Pradikan from India
Hi TOM,

We have a typical requirement. I've a situation where only the sequences needs to be copied to a 
different instnace / schema. Using export I can do at table level, user level, tablespace level or 
full database level. But is there any way where i can export only the sequences and import them to 
a different schema.

Thanks in Advance

Pradikan
 


Followup   March 29, 2006 - 7am Central time zone:

not via export and import.

You could easily write a script that creates a "create sequence script" - it would take seconds to 
develop. 

4 stars Alternative for the insane...?   April 13, 2006 - 8pm Central time zone
Reviewer: Asher Cerka from IL USA
Create table t (t number(22))

Insert into t values (1)

Create or replace function Get_Next_T return number
IS
NextT number(22);
Begin
select max(t)+1 into NextT from t;
If NextT is null Then
    return 1;
Else
    return NextT;
End If;
End;

Insert into t values (Get_Next_T())



Will never skip a value, because the value that it gets is always the next one in the sequence. Not 
safe for multiple users, because 2 users can both get the same value before the other manages to do 
their insert. (need to lock the table to get around that, unless you can think of an alternative.) 
Also, if t is unindexed then it has to do a full table scan every time you want to insert a value. 
If I index it, it does a 'index full scan (min/max)' which unfortunately with my limited knowledge 
of explain plans means little to me. It sounds like it's doing a full-scan of the index... which 
would seem silly as the highest value is obviously going to either be at the top or the bottom.

I'm unsure of how much effect this would have performance-wise, and unless an alterative can be 
found to locking the table every time you need to do such an insert... to me it's nothing short of 
insanity. But... legal people make others do more insane things then this. :) So... it could be 
made to work if absolutely neccessary I believe. No matter what, in order to generate a truely 
gap-free number-set the next number has to be somehow depending on the current last ID on a table. 


Followup   April 14, 2006 - 12pm Central time zone:

that would not fly at all in a multi-user environment.  serialization would be the word of the day.

it would read just the end of the index - but you would have to serialize before doing so. 

5 stars Sequence number with no gaps   May 4, 2006 - 6pm Central time zone
Reviewer: A reader 
Tom,

Instead of using an Oracle sequence number, can we use Oracle rownum to generate sequence numbers 
with no gaps (Run an update statement on the column where a sequence number with no gap is 
required)?


Thank you 


Followup   May 5, 2006 - 1am Central time zone:

you can come back and assign unique gap free numbers to rows, yes, if you wanted to. 

5 stars Using rownum as a unique sequence   May 5, 2006 - 3pm Central time zone
Reviewer: A reader 
Tom,

1) Do you know or see any limitations or scalability issues with this approach (using rownum)?
2) Does rownum implementation change with oracle db versions?

Thank you
 


Followup   May 5, 2006 - 3pm Central time zone:

I likely would not use rownum, it could be unpredicable (same data, different rownums assigned).

You would want to use something repeatable I would think. 

3 stars sql loader header   May 5, 2006 - 4pm Central time zone
Reviewer: jhon edison b.c from Colombia
Hola since as,like all: The truth almost not groin but I expect they understand me a bit. I have 
the following problem, desire To load a base of datas information using sqlloader but not since, 
like before the load to add her(it) Head-board of the record, in this case the date: the file is of 
the following form:


clamasiva8.log;    C:\clasmas;     30;     Clasificacion ;     172976;     182510;     2;     
8490073;     ;     1;     0;     24;     AAA;    
clamasiva8.log;    C:\clasmas;     30;     Clasificacion ;     68901;     73461;     2;     
8490075;     ;     1;     0;     24;     AAA;    
 30-01-2006;
clamasiva3.log;    C:\clasmas;     28;     Clasificacion ;     2523;     2616;     2;     8849387;  
   ;     1;     0;     1;     AAA;    
clamasiva3.log;    C:\clasmas;     28;     Clasificacion ;     9923;     10510;     2;     8861563; 
    A;     1;     0;     4;     AAA;    
clamasiva3.log;    C:\clasmas;     28;     Clasificacion ;     36988;     39030;     2;     
8845339;     ;     1;     0;     1;     AAA;    
26-01-2006;

It must be this way:

clamasiva8.log;    C:\clasmas; 30-01-2006;     30;     Clasificacion ;     172976;     182510;     
2;     8490073;     ;     1;     0;     24;     AAA;    
clamasiva8.log;    C:\clasmas; 30-01-2006;     30;     Clasificacion ;     68901;     73461;     2; 
    8490075;     ;     1;     0;     24;     AAA;    
clamasiva3.log;    C:\clasmas; 26-01-2006;     28;     Clasificacion ;     2523;     2616;     2;   
  8849387;     ;     1;     0;     1;     AAA;    
clamasiva3.log;    C:\clasmas; 26-01-2006;     28;     Clasificacion ;     9923;     10510;     2;  
   8861563;     A;     1;     0;     4;     AAA;    
clamasiva3.log;    C:\clasmas; 26-01-2006;     28;     Clasificacion ;     36988;     39030;     2; 
    8845339;     ;     1;     0;     1;     AAA;    

Thank you:

att: jhon edison B.C Colombia 


Followup   May 5, 2006 - 4pm Central time zone:

Ok, I'll bite - where do the dates come from exactly - what "logic" produced them? 

5 stars It is great   August 8, 2006 - 7am Central time zone
Reviewer: Subhrajit Bandyopadhyay from INDIA
I agree with Tom 200%.. there is no meaning of gap-less unique ID's numbers. Even if some 
government depts like Income Tax etc are asking to keep each and every paper with serially numbered 
... they should understand that it doesn't helps them ... because when papers were used then ther 
may be some legal issues in case a numbered form is lost ..it may be misused ..so there was a 
threat.. but in case of Computerizewd system generated forms no one can missuse it ..how can he??? 
because its not there actually.

Using Seuqences allows real concurrent transactions.

 


5 stars Sequnce value retrieval swells Rollback Segment   November 8, 2006 - 3pm Central time zone
Reviewer: Sanji from Shelton, CT
Tom,

Following is the trigger body which when invoked causes Rollback segment extend failure.
More than anything else, i'm wondering why would this cause rollback segments to go out of space. 
(The env. is Oracle 9i on HP-UX 11i and the database is still configured for Rollback segments as 
against to UNDO.) 

CREATE OR REPLACE TRIGGER "COGNOS"."TRG_SEQ_XOCUBEFACT_ROW_ID" 
    BEFORE INSERT ON "COGNOS"."XOCUBEFACT" FOR EACH ROW 
begin  
SELECT SEQ_XOCUBEFACT_ROW_ID.NEXTVAL INTO :NEW.ROW_ID FROM DUAL; 
END;

Thanks
Sanji 


Followup   November 8, 2006 - 8pm Central time zone:

well, i hate triggers like that...

but triggers generate extra undo

the recursive sql used to update the seq$ table will too.

Suggest you:

alter sequence seq_xocubefact_row_id cache 100000;

really suggest you:

drop trigger;
and put the seq.nextval right into the insert too. 

2 stars any why of rolling back the sequence number to the previous   November 9, 2006 - 1am Central time zone
Reviewer: A reader 


Followup   November 9, 2006 - 8am Central time zone:

why???

sequences are not gap free
sequences are not gap free
sequences will never be gap free.


assume this order of operation:

session1:  give me a sequence (they get 42)
session2:  give me a sequence (they get 43)
session1:  rollback


to what value could you POSSIBLY put a sequence "back" to - it doesn't even make sense in that 
context. 

5 stars Regarding Oracle Sequences   November 16, 2006 - 5am Central time zone
Reviewer: Hemal from India
Hello Tom,
I am creating a data entry application in which user will enter the number of Clients visited to a 
nursing home
in a particular month.

I need your advice to implement the following mentioned logic for generation of client code using 
Oracle Sequences.
Client code is the primary key of the database table in which client information is stored.

Suppose a client visited the nursing home in January 2007, the client code is having  following 
format "P07A001"
Out of this "P" is hardcoded.
07 stands for year "2007".
A - Standands for January, (If client visited in February  then this would be "B",If client visited 
in March then it would be "C" ..If client visited in December then it would be "L").

001 is the running number.(This number is reset back to 000 in the next month).

For the 2nd client in the January 2007 the  client code will be 'P07A002', 3rd client in the 
January 2007 the client code will be "P07A003".

In case of February 2007,first client who visits the nursing home will have client code as 
"P07B001",
Second client who visits the nursing home will have client code as "P07B002".

I would like to know as whether I can use Oracle Sequences for generation of Client Codes in such a 
format.
If not what will be the best method of implementing this logic.

Your help is highly appreciated.
Thanks and Best Regards
-Hemal 


Followup   November 16, 2006 - 3pm Central time zone:

you have made the most fatal mistake of your database career.

you are encoding multiple data fields into on.

Just stop that right now, don't do that.

P is not needed, it is a constant.
2007 should be a date field else where, a standalone attribute.
A, B, C, ... is beyond "not smart".  2007 and the month are a single attribute, the date

and the client id is just a surrogate, without any reseting

Please remember, this is NOT dbase, this is real life.


stop doing this, please please please - this is so wrong. 

3 stars Min Value in sequences   November 16, 2006 - 4pm Central time zone
Reviewer: Maverick 
Tom, what is the use of MinVal option while creating sequences? Start with, Max val,Increment by 
..pretty much takes care of everything that's needed [or may be i'm missing sonething]

Thanks, 


Followup   November 16, 2006 - 4pm Central time zone:

ops$tkyte%ORA10GR2> create sequence s start with 9999999 increment by -1 maxvalue 9999999999 
minvalue 1;

Sequence created.

ops$tkyte%ORA10GR2> select s.nextval from dual;

   NEXTVAL
----------
   9999999

ops$tkyte%ORA10GR2> select s.nextval from dual;

   NEXTVAL
----------
   9999998


they do not have to go up 

5 stars Regarding Oracle Sequences   November 17, 2006 - 4am Central time zone
Reviewer: Hemal from India
Hello Tom,
This is in continuation with my question with title "Regarding Oracle Sequences  November 16, 2006 
" on this link.
Thanks for your reply.
I totally agree with you, but the problem is the users who needs this Nursing Home Application 
requires the Client Codes be generated in the same format ("P07A001").Users are using this client 
code format from years and therefore they are not ready to change it.

Can you please help me / guide me as what will be the best way of generating the client codes in 
this format ("P07A001").
Is it possible by using oracle sequences or should I write a PL/SQL funtion to generate the client 
codes ?

I was planning to maintain a control table which will have structure and data as follows:-

--------->
SQL> DESC CLIENT_CODE_MAST;
 Name                           
 -----------------------------
 CLIENT_MONTH                   
 MONTH_DECODED_VAL              
 MONTH_CURR_VAL                 


SQL> SELECT * 
  2  FROM CLIENT_CODE_MAST;

CLIENT_MONTH  MONTH_DECODED_VAL MONTH_CURR_VAL
JAN            A                      1
FEB        B            1
MAR        C            1
APR        D            1
MAY        E            1
JUN        F            1
JUL        G            1
AUG        H            1
SEP        I            1
OCT        J            1
NOV        K            1
DEC        L            1


--------<-

The above data is stored in the CLIENT_CODE_MAST table  before the user starts using the 
application for the first time.

When the user creates the first client in January 2007,in my oracle PL/SQL function I will get the 
Current Value from the CLIENT_CODE_MAST.MONTH_CURR_VAL
column and create the client code as "P07A001". I will also update the CLIENT_CODE_MAST row having 
CLIENT_MONTH = "JAN" to 2 so that we can use this value for the next client created in January 
2007.Therfore,the data present in the CLIENT_CODE_MAST will be as follows:-

SQL> SELECT * 
  2  FROM CLIENT_CODE_MAST;

CLIENT_MONTH  MONTH_DECODED_VAL MONTH_CURR_VAL
JAN            A                      2
FEB        B            1
MAR        C            1
APR        D            1
MAY        E            1
JUN        F            1
JUL        G            1
AUG        H            1
SEP        I            1
OCT        J            1
NOV        K            1
DEC        L            1

--------

Therefore,for the second client created in January 2007 we can use the MONTH_CURR_VAL value ('2') 
and create its client code
as "P07A002"


Now ,suppose the user is creating the Client in February 2007,we will reset the 
CLIENT_CODE_MAST.MONTH_CURR_VAL to '1' for the
CLIENT_MONTH='JAN' and we will use the value of the MONTH_CURR_VAL for the CLIENT_MONTH='FEB'.
Therefore,the first client code created in Feb 07 will be "P07B001",second client code created in 
Feb 07 will be "P07B002".

Please advice me as whether the above mentioned technique is right ?
Please advice me the best technique to generate the client codes in this format "P07A001".

Thanks and Best Regards
-Hemal  


Followup   November 17, 2006 - 8am Central time zone:

you will write a procedure to do this, there is nothing but nothing built in that can do this, it 
is a bad requirement. 

3 stars Min Value in sequences   November 17, 2006 - 1pm Central time zone
Reviewer: Maverick 
Tom, To be frank, I did not understand your response on this one. your example is taken care of by 
"increment by -1" option. So where does MinVal come into picture?

Thanks, 


Followup   November 20, 2006 - 2am Central time zone:

umm, sequences can run backwards.

so, you can set a minimum value they can run backwards to. 

5 stars Min Value in sequences   November 17, 2006 - 4pm Central time zone
Reviewer: AD from UK
Fisrt of all thanks to Tom and the readers.

To Maverick,

I think Tom's point is:
If you want a sequence to be in an increasing order then you will start with some min val and then 
specify the max val.
for example a sequence can starts with minval =1
max val=1000000 and may be incremet by 1.

If you want your sequence to be in a decreasing order then you can define your sequence as follows 
start with =1000000
min val =1
increment by -1
and max val = 9999999999

So, you do require minval setting sometime as you would like to set the lower limit just you would 
set the upper limit in an increasing sequence.

I hope Tom will correct me if I am wrong.

Regards

 


Followup   November 20, 2006 - 2am Central time zone:

that is it. 

5 stars Regarding Oracle Sequences   November 18, 2006 - 12am Central time zone
Reviewer: Hemal from India
Thanks a lot Tom.
I highly appreciate your help.

Best Regards
-Hemal 


2 stars MinValue Still not sure :-)   November 18, 2006 - 9pm Central time zone
Reviewer: Maverick 
I am still trying to understand about this Min Value in sequences.

AD Wrote 
"If you want your sequence to be in a decreasing order then you can define your 
sequence as follows 
start with =1000000
min val =1
increment by -1
and max val = 9999999999"

Ok, here if we want in decreasing order, we said start with 1000000 and increment by -1. So every 
iteration will be in decreasing order. So, again why Min Value [Sorry Really trying to understand 
here] and  AD , why a max value of 9999999999, as it never reaches that value [since it's 
decreasing ]?

Thanks Again.
 


Followup   November 20, 2006 - 2am Central time zone:

it is putting a lower bound on the sequence value, since the sequence runs "backwards" - it 
DECREASES - the value will never go below that "minval", you'll get an error instead. 

4 stars min value   November 19, 2006 - 9am Central time zone
Reviewer: jimk from Portland, OR
Min value is there so you can specify a minimum value.  One might want to do that to give different 
instances a unique sequence in a replicated environment. (eg server 1 from 0 to 1000000 server 2 
from 1000001 to 2000000...) 


5 stars Sequences   November 30, 2006 - 9am Central time zone
Reviewer: Frank from USA
Hi Tom,

Is there any way to reset the sequences after a certain period of time? For E.g If we need to reset 
the sequence to '1' at the start of every year.  


Followup   November 30, 2006 - 10am Central time zone:

why?
5 stars Sequences   November 30, 2006 - 10pm Central time zone
Reviewer: Frank from USA
In our application, the data will be taken backup on the last day every year. From next day 
onwards, fresh records will be inserted into database, which need to start from 1.
I am ok if the sequences are not gap free also. But at the start of every year, the sequence need 
to start from 1. 


Followup   December 1, 2006 - 5am Central time zone:

why

 

5 stars Regarding Sequences   December 11, 2006 - 12pm Central time zone
Reviewer: Hemal from India
Hello Tom,
My client has a very specific format of the Transaction number.Though I love sequences but in this 
situation I am not able to use it because of clients typical requirements such as there must not be 
Gaps ,require to reset the running number back to Zero at start of every month. 

Therefore,I had no choice but to write my own function for generation of Number (Shown Below).

But I am very much worried about the concurrency.
What will happen if the two users simultaneously access the function ?
Are there any chances that both the users will get the same value from this function ?

Will this function fail in a multiuser environment ?

Is there any better way for coding this.

Following is table structure and the corresponding function code:-

SQL> desc transaction_number_mast;
 Name                                      Null?    Type
 ----------------------------------------- -------- -------
 NEXT_TRAN_NUMBER                                   NUMBER


SQL> SELECT * from  transaction_number_mast;

NEXT_TRAN_NUMBER
----------------
              36

SQL> 

-----------------------------------------------------------
CREATE OR REPLACE FUNCTION GET_NEXT_TRAN_NUMBER
RETURN NUMBER
AS
    CURSOR c_transaction_number_mast IS
    SELECT next_tran_number
    FROM transaction_number_mast
    FOR UPDATE NOWAIT;

 t_next_tran_number transaction_number_mast.next_tran_number%TYPE;

BEGIN
FOR r_transaction_number_mast IN c_transaction_number_mast LOOP

t_next_tran_number :=  r_transaction_number_mast.next_tran_number;

        UPDATE  transaction_number_mast
        SET next_tran_number = next_tran_number + 1
        WHERE CURRENT OF c_transaction_number_mast;


    END LOOP;

    COMMIT;

    RETURN t_next_tran_number;
END;
/
-----------------------------------------------------------

Please help me tom.


Thanks and Best Regards
-Hemal

 


Followup   December 11, 2006 - 1pm Central time zone:

gap free = ZERO CONCURRENCY.

period, no if an or buts about it.


just

update t
   set tran-number = tran-number+1
returning tran-number into l_tran_number;


there should be no select, totally unnecessary. 


that update will of course serialize - obviously, so there will be NO concurrency.


and you BETTER LOSE THAT COMMIT, else you have just violated your "gap free" requirement entirely.  
That COMMIT cannot be there if you want "gap free" (and hence NO CONCURRENCY) 

2 stars Primary key generation   December 14, 2006 - 12pm Central time zone
Reviewer: RP from London, UK
Hi,

slightly off topic (and i thought i asked this already but can't find it anywhere on the site!):

My shop uses Java to generate all primary keys - they come out as 36 char strings.

Any performance implications to doing this Tom?

Thanks

 


Followup   December 15, 2006 - 8am Central time zone:

besides the java bit ?  :)


there is the size (36 bytes versus something less)

there is the storage associated with that of course.

from a retrieval perspective - it is likely "not materially different, it'll take a bit more cpu" 

5 stars Regarding Sequences   December 14, 2006 - 12pm Central time zone
Reviewer: Hemal from India
Hello Tom,

I didnt understood the following statement:-
"that update will of course serialize - obviously, so there will be NO concurrency"

Suppose the intial value in tran-number column is 2.

Suppose two users at a same time fires the 

"update t
set tran-number = tran-number+1
returning tran-number into l_tran_number;"

How oracle make sure that one user gets the value as 3 
and another user gets the value of 4 ?

Also as per your advice I am not firing the COMMIT statement immidiately after the UPDATE 
statement.

Therefore,if simultaneous users fires the UPDATE statement 
at same time how does the Oracle assign unique number 
to each user.

( In my coding standard guidelines, it is writtern that "Lock the record before performing an 
update".Therefore,in my earlier code I locked the
record with 'FOR UPDATE NO WAIT' so that it will display an error message to another user trying to 
UPDATE the record at the same time.)

Please advice me.
Thanks and Best Regards
-Hemal
 


Followup   December 15, 2006 - 8am Central time zone:

that is precisely what Oracle does - it is basically its purpose - to achieve correctness of 
transactions.

If you want the entire full big story - you can check out the Concepts Guide or my version of the 
Concepts Guide - Expert Oracle Database Architecture where I cover transactions and how Oracle 
works in general.


Update locks the record - there is no need IN THIS CASE to lock the record.  You do not care about 
lost updates here - in fact you DESIRE lost updates (to update data without really reading what the 
other person did to it).   

5 stars Regarding Sequences   December 17, 2006 - 9pm Central time zone
Reviewer: Hemal from India
Thanks Tom
I highly appreciate it. 


5 stars Sequences again.... please help !   January 9, 2007 - 7am Central time zone
Reviewer: Fabio Franzotti from Brazil
Tom,

We have a table and the PK is (Customer Number(3),NUM_ID Number(8) ).

Actually we work with only one customer, the customer 001, but we have more Customers soon...

The Num_ID should be sequential, but can have small gaps.

We like to use different sequences per Customer... how the best way to implement this ?

Thanks a lot,
Fabio Franzotti

 

Followup   January 11, 2007 - 9am Central time zone:

why would you like to use different sequences per customer - that would not be sensible at all.

if num_id can have gaps - it can have gaps - period. the size of these gaps is not relevant
4 stars Avoiding Prison... pre-generate records   January 11, 2007 - 12pm Central time zone
Reviewer: SamG from NYC

The ugly truth is that sometimes we have to match the pattern of 19th and 20th century pre-printed order forms.

So, pre-generate rows in a document tracking table that match the paper forms. No gaps.

A before statement trigger can spawn a clean new batch of rows out ahead of processing as needed.

This approach isn't all that difficult to implement. Data is entered with UPDATE instead of INSERT. Not a heavy price.

Also, Content Manager used in tandem with OID can publish available slots and support information, including diagrams and regulations, through apps servers. Accomodating different series for different customers becomes trivial. 

4 stars   January 21, 2007 - 9pm Central time zone
Reviewer: YL from Hong Kong
Dear Tom,

It is a good post for the discussion of sequence number.

Recently, I am working for "translating" some statements from Microsoft SQL Server to Oracle.

In SQL Server, there is a statement about the creation of table:

CREATE TABLE SBCEvents(SBCSeq int IDENTITY(1,1) NOT NULL, SrcSystem int NOT NULL)

It is obvious that Oracle does not have identity constraint. How can I translate this from SQL Server statement to Oracle statement?

Thanks a lot
YL


5 stars non-sequential sequence in RAC database   May 25, 2007 - 9am Central time zone
Reviewer: Sean from NJ, USA
Hi Tom,

We don't mind sequence gap, but with RAC database and sequence with catch, we got non-sequential sequence (21 is created before 1), which could give misleading information when we use order by.

Thanks so much for your help.

-- Sean


Followup   May 26, 2007 - 12pm Central time zone:

hahahah - sequences are not ordered by time in any case. single instance or not.

if you need something ordered by time, you better - well - have a time stamp.


all a sequence is is a unique value, nothing else can be derived from it.


3 stars Generating sequence   June 26, 2007 - 5pm Central time zone
Reviewer: Priya from Los Angeles, CA USA
Hi Tom,
I have a table

create table library_Test
(
CLIENTID    NUMBER (11), 
PROPERTYID  NUMBER (11), 
DOCID       NUMBER (2), 
DATECREATED DATE 
)

Insert into library_test values(99999,12345,1,sysdate)

Insert into library_test values(88888,45678,2,sysdate)


Now I add in a column libraryid which will identity each row

alter table library_test add libraryid number(11)


Now I want to generate libraryIDs say 1,2 and so on for the number of rows in the table. I want libraryid as 1 for the first record created
based on datecreated.

So I want my output to look like this

clientid propertyid  docid     datecreated     libraryid       
99999     12345        1  6/26/2007 2:04:30 PM     1
88888     45678        2  6/26/2007 2:04:56 PM     2


Oracle version is 9.2.0.1.0

Thanks,
Priya.



Followup   July 2, 2007 - 9am Central time zone:

well, this is a bad idea - it seems you will make a future presumption that libraryid can be used to "date" a record - when in fact, subsequent records that are added to this table will use a SEQUENCE (please) and it could well be that the sequences are assigned in such a fashion that a record with a larger libraryid will have a smaller datecreated value than some other record.

but, to answer the question:

ops$tkyte%ORA9IR2> create table library_Test
  2  (
  3  CLIENTID    NUMBER (11),
  4  PROPERTYID  NUMBER (11),
  5  DOCID       NUMBER (2),
  6  DATECREATED DATE
  7  )
  8  /

Table created.

ops$tkyte%ORA9IR2> Insert into library_test values(99999,12345,1,sysdate);

1 row created.

ops$tkyte%ORA9IR2> exec dbms_lock.sleep(4);

PL/SQL procedure successfully completed.

ops$tkyte%ORA9IR2> Insert into library_test values(88888,45678,2,sysdate);

1 row created.

ops$tkyte%ORA9IR2> alter table library_test add libraryid number(11);

Table altered.

ops$tkyte%ORA9IR2>
ops$tkyte%ORA9IR2> merge into library_test
  2  using ( select rowid rid, row_number() over (order by datecreated) rn
  3            from library_test) new_data
  4  on (library_test.rowid = new_data.rid)
  5  when matched then update set libraryid = new_data.rn
  6  when not matched /* never happens of course */ then insert (clientid) values (null)
  7  /

2 rows merged.

ops$tkyte%ORA9IR2> select * from library_test;

  CLIENTID PROPERTYID      DOCID DATECREATED           LIBRARYID
---------- ---------- ---------- -------------------- ----------
     99999      12345          1 02-jul-2007 09:56:52          1
     88888      45678          2 02-jul-2007 09:56:56          2


5 stars accidentally dropping sequence   July 30, 2007 - 9am Central time zone
Reviewer: A reader 
Today, I accidentally drop sequence owned by SYS, but database do not going to broken. But I am 
afraid it will effect on database work. So my question, could we restore the sequence just like 
table could used recycle bin feature. My database is Oracle 10g R2.

Thanks


Followup   July 30, 2007 - 5pm Central time zone:

you cannot accidentally drop a sequence from sys.

you shouldn't be logged in as sys.

anyway, contact support, talk to them about what your options are - database is broken, you just haven't hit the issue yet.
5 stars Gap free invoice numbers   July 31, 2007 - 3pm Central time zone
Reviewer: Wiktor Moskwa from Poland
In Poland, as in many other countries, invoice numbers have to be gap-free by law. Period.
I know that this (as many other real-life things) is stupid but after 2 years of work implementing 
accounting solutions I don't even bother :-)

If you want to cancel an invoice you issue a "cancellation note". If some data changed on an 
invoice you issue a "correction invoice". In all cases the original invoice has to be untouched 
(and kept for 5 years - printed).

Fortunately invoice numbers can have many series and one organization can issue invoices like:
1/A/2007, 2/A/2007 ... 1/B/2007, 2/B/2007, etc.
So serialization is not global but on the level of single series. Because we can assign a single 
series to a single sales point or even a single salesperson - the serialization problem is solved.

Tom, you ask "what if coffee is spilled, invoice is lost or burned".
I answer in details: you have to restore it. If you don't and you have a gap in invoice numbers - 
you've just committed a financial crime. Really. Period.
You can print it for the second time (the most common case) or restore it from some notes or memory 
or even make it up...


Followup   August 2, 2007 - 10am Central time zone:

you should just assign your invoice numbers at "book closing time" then. Or have a process to fill in "null invoice"

This makes me laugh - I'll bet the law is not what you say, but has been over interpreted.

What happened when coffee was spilled on a tablet of paper, or some invoices JUST WENT MISSING - physical invoices - before the computer.

Really period - how do you restore destroyed pieces of paper? counterfeiting is a crime, having gaps - cannot be - doesn't even begin to make sense.
5 stars Even make it up?   August 2, 2007 - 11am Central time zone
Reviewer: Jim from Portland, OR, USA
If you lose it or spill coffee on it then you can "even make it up".  I would think that would be 
financial fraud.


3 stars Gaps   August 3, 2007 - 4am Central time zone
Reviewer: martina from vienna, austria
I think Wiktor is correct. if you physically lose an invoice you have to reconstruct it. if your 
accounts are correct you can do that. you might even write a note "this is a copy as original was 
spilled with coffee". If you cannot reconstruct it you are in trouble anyway because your accounts 
are not correct. (reconstruction is not counterfiting, with or without computer).
the reason for gap-free invoices is that they may be checked easiliy. you are paying tax according 
to your invoices. you are not able to just hide every other invoice and not pay tax for it. (of 
course you may, but this is defraudation).
So if you have gaps in your invoices and you are audited (big companies are audited every year) you 
are in trouble. it is possible that in some european countries you might be allowed to explain gaps 
and prove that there never was an invoice with the missing numbers. (how does one prove that 
somthing has never been there what is not there now??).
i guess that is exactly what authorities want: serialize the process of writing invoices. so 
filling in null invoices is exactly what is illegal, you must not write invoice 10 before invoice 
5.

best regards, martina


Followup   August 5, 2007 - 1pm Central time zone:

I have a tablet of invoices.

They have NOT YET BEEN USED.

I spill coffee on them, they are destroyed.
They go missing, it fell out of my briefcase, they are lost forever.
They burnt in a small fire.
My kids drew pictures all over them with crayons while I wasn't watching, they are destroyed (in fact, the little guys ripped them into shreds!)


And so on.

Now what.

Whatever you answer - WHATEVER YOU ANSWER - we will apply that to....

gaps.


Invoices need not be sequential. If they were - well, guess what - you could never have a place like "Dell computers" or "Amazon" because you cannot sequentially generate all of that stuff.



3 stars SamG is mostly right   August 3, 2007 - 1pm Central time zone
Reviewer: Carsten from Germany
If you need gap free record numbers, do it just like you would do it with paper forms:

- Create empty forms
- distribute the forms to the users
- mark them as valid when returned

In more detail:
create table VOUCHERS
(
  ID       NUMBER not null primary key,
  USERNAME VARCHAR2(20)
)

Creation is a 100% serializied nightly/weekly batch job (not via Trigger as SamG suggested!), which 
basically inserts mostly empty records in a sufficient number based on usage and current "stock" of 
empty records.
lock table vouchers in exclusive mode; /* shouldn't hurt much if timed well */
insert into vouchers (id)
SELECT ROWNUM+(select nvl(max(id),0) from vouchers) n
FROM   ( SELECT 1 
         FROM   dual
         CONNECT BY LEVEL <= 10 /* add here some smart guessing to find right number */
       );
commit;


Distribution means that the application requests a process number once a user opens the input mask 
by calling something like:
create or replace function get_voucher_form(fuser varchar2) return number is
  Result number;
begin
  update vouchers set username=fuser where username is null and rownum=1 returning id into Result;
  commit;
  return(Result);
end get_voucher_form;

And finally you call some other function to mark it as valid (too lazy now to prepare that as well 
;) ).

Advantages: 
 - serial part is minimized
 - auditors should be able to understand it
 - no chance to skip numbering with clever abort/delete (which is a problem if you do it 
afterwards, e.g. fill out the form, print it, then cancel)

Caveats:
 - just like with handing out forms usage is not in order. But again the paper analogy lets you 
explain it: as forms are printed and distributed ahead, usage may vary how much single workers 
process each day. This is the price we pay for filling out the vouchers in parallel.




Followup   August 5, 2007 - 1pm Central time zone:

well, until user uses one of them to level a table

or spills coffee

or .... whatever

I give up, go for it - be serial.
3 stars   August 6, 2007 - 7am Central time zone
Reviewer: Carsten from Germany
I don't like the idea much as well, but sometimes you are forced to by law.

You say what about spilling coffee ? Well I have seen it: they are forced to dry it, but a big 
"void" onto it and put it to the file. If a form is really destroyed with no way to keep it in the 
records, then an replacement voucher must be created with signatures of the president and the pope 
on it (or as close as you can get to that) with clear reason why and how it was lost.

If your business practice is not that strict, then Tom's orginial answer is for you: use sequences 
and do not rely that they are gap free.


Followup   August 6, 2007 - 12pm Central time zone:

it blows out the window of a 10 story building and is gone.

Look - things disappear, they just do - what happens then

when you tell me what happens with things disappear - as they are wont to do - then I'll tell you what to do with gaps.


I've worked in stores and such before - invoices are just paper - they get ripped up, they get thrown away, they disappear - they are non-sequential (you would need precisely ONE CLERK otherwise)



5 stars Current Sequence Value   August 6, 2007 - 11am Central time zone
Reviewer: Phil from Britain
Hi Tom

I agree totally about using sequences, and is what I have always done (since I used Oracle that 
is!).

However, I've got a problem with performance. I customer has a table that has a LOT of insert 
activity going on against it (typically, 1-3000 inserts a second). They want to be able to report 
any time there are more than a certain inserts in 5 minutes.

How to do this efficiently?

Well, current thinking is the following:

Each insert grabs a nextval from a sequence. An independent process runs each second and adds a row 
into a table with the currval sequence number and the prior value which means we can do the math 
and get the count of the number inserted. As well as this, a sum of the last 300 seconds or 300 
rows based on the count figure allows a much more efficient count without really pounding the table 
hard.

You're bound to rip this apart but the real flaw in this is establishing currval without being 
connected to the session that does the inserts. It looked good until we realised that.

Thanks in advance and for the past help which has made such a difference to my work.

Phil


Followup   August 6, 2007 - 12pm Central time zone:

it is as good as anything else - and not truly meaningful :)


you need a continuous function (to be alerted to a threshold being hit in a 5 minute window), but all you have is digital inputs :)


   xxxxxx
zzzzzzyyyyyy



say during the 5 minutes represented by xxxxxx you had 100,000 inserts.

It is idle before and after that.

But you do your windows of observation during zzzzzz and yyyyyy

Each of those show 50,000 inserts

Your threshold is 75,000 inserts - you exceeded that by a lot, but no one will ever know...
5 stars sliding window   August 6, 2007 - 1pm Central time zone
Reviewer: A reader 
Hi Tom,
Yes, the diagram you put together is perfect! But this is why we have the idea of:

... An independent process runs each second and adds a row 
into a table with the currval sequence number and the prior value which means we can do the math 
and get the count of the number inserted. ###As well as this, a sum of the last 300 seconds or 300 
rows based on the count figure ### allows a much more efficient count without really pounding the 
table 
hard.

I agree it is horrible but are you aware of any better method? And can we get the currval from some 
dba object without being connected as the process that writes to our big table?

Thanks as always

Phil


Followup   August 7, 2007 - 9am Central time zone:

I'd be curious as to "why you need to know this"

this process, sure, it would work - but..... it would also be adding to the problem.

now you'll have to figure out how to partition this table, manage the partitions, age data out, add the additional resources needed to perform this operation and so on.


5 stars auditing gaps   August 6, 2007 - 7pm Central time zone
Reviewer: Dario from Argentina
Well, in Argentina, the numbers must be gap free or a least, the gap must be audited or informed 
(You must inform: "These forms have been destroyed: xxxx...xxxx...". Sometimes, you must make it 
public. It's very common to see reports on newspaper of companies declaring "the following receipts 
have been" lost, stolen...)

So... a trigger could be used with an autonomous transaction inserting sequence number, user, time, 
application used, etc into a table.

You can report later, numbers 'retrived and unused' (lost sounds ugly and incorrect) by the 
application at the price of having one more table for each sequence to be tracked, or a table with 
a "SEQUENCE_NAME" column. I would probably keep that table in the recycle_buffer, (if the tuning 
and adjustment worth it). 

Of course, you should run when required:
select id from seqs_retrieved 
minus 
select id from account_events

Question: Could this "tracking" be done using log miner and avoid to "reinvent the wheel"?

If delete operations are not expected (if it needs to be gap free, the application probably will 
not do a delete),
I would audit delete operations on that table, to complete the auditing report.

And if I were reading this, I would wait for Tom to review it, before trying it.

(I totally agree: Non gap numbers have no sense, burocracy have no sense. Probably the law have no 
sense too. That's why I'm not a lawyer. B-) )

Greetings.



3 stars insert activity   August 8, 2007 - 1pm Central time zone
Reviewer: Jeff from Milwaukee WI USA
--customer has a table that has a LOT of insert 
--activity going on against it (typically, 1-3000 inserts --a second). They want to be able to 
report 
--any time there are more than a certain inserts in 5     --minutes.

-How to do this efficiently?

Is there a timestamp field in the table being inserted into?  A simple count query using the 
timestamp should be able to provide this.


5 stars Performance   August 9, 2007 - 4pm Central time zone
Reviewer: Phil from UK
Tom / Jeff 

I agree, a simple query should provide this based on timestamp, however, how will Oracle cope with 
3000 inserts a second, after 24 hours we decide to run a query that asks for average insert rate in 
5 minute slots for past 24 hours? This will need to examine 259 million rows and will presumably 
take a while to run. The method we have in mind will look at 86k rows and so require 1/3000 of the 
effort. Not only effort, but it will require no time on the table that is still receiving 3k rows a 
sec.

Is there a 3rd way of doing this? I've got a feeling there might be!

BTW, as an aside, is a trigger the best way of managing the ID or procedural code. I recall 
triggers were not as efficient as procedural code a while back.

Thanks! 


Followup   August 14, 2007 - 10am Central time zone:

I still feel the best approach for this is:


<this space intentionally left blank>


I'm failing to see the relevance of this particular metric.

average business transactions per second <<<====

now that would be useful, but this? (and we can typically get the average tps pretty easily)
3 stars after a little more thought   August 9, 2007 - 5pm Central time zone
Reviewer: Jeff from Milwaukee WI USA
Looking at this a little closer, maybe you're over-complicating the issue (or I'm 
misunderstanding).

"An independent process runs each second and adds a row 
into a table with the currval sequence number and the prior value which means we can do the math 
and get the count of the number inserted."

Why do you need the currval & prior value?  Just burn an entry from the sequence, have a table with 
two columns, timestamp and sequence_value.  Have a job run every second (or every 15 seconds, or 
every minute - do you really need the detail down to the second?) Insert a nextval with timestamp 
and you're good to go.  So you leave a 1 value gap in the original table every second (or whatever 
timeperiod) - who cares?  Now you can query this smaller table for any interval you choose.
 


5 stars More on the law   August 14, 2007 - 3pm Central time zone
Reviewer: Wiktor Moskwa from Poland
============================
Tom:
This makes me laugh - I'll bet the law is not what you say, but has been over interpreted.
[..]
 counterfeiting is a crime, having gaps - cannot be - doesn't even begin to make sense.
[..]
I've worked in stores and such before - invoices are just paper - they get ripped up, they get 
thrown away, they disappear - they are non-sequential (you would need precisely ONE CLERK 
otherwise) 
============================

Tom, with all respect, but the law here is exactly as I've written before. I've consulted a lawyer 
and accountants - the act literally states it - no gaps in invoice numbers unless you've got a 
really good explanaition like an office that was burn to the ground. People pay fines here during 
tax audits for having such gaps, an offence is called "unreliable bookkeeping".
Please remember that there are places where the law is against logic.
I shouldn't write "even make it up" last time, that was an exaggeration.

You've said few times that you do not care about the performance of a query that gives a wrong 
answer. Using sequences here would be really against the law and that way simply wrong.
I think that serialization problem is not that critical because every clerk can have his own 
invoice number series.
Only for clarification: I'm talking here about invoices only, not about orders.

Of course you're right with burnt and missing invoices.  Here when you sell something you print an 
invoice in two copies(*) and the buyer takes one of them. If your copy is missing you've got 
information to recover it (you can contact buyer, see what was sold and so on) and recovered 
invoice will have to have the same number - so it will fill the gap. I think the law was meant to 
protect against frauds or whatever and maybe many years ago it could work...

(*) - actually one copy is called "an original" by law and it has to be printed on that piece of 
paper and you can print and have only one "original" invoice, on other copies you have to print "a 
copy" (it is literally stated in the act) - another strange thing, isn't it? :-)


5 stars human subject ids need to be non-identifying   October 14, 2007 - 2pm Central time zone
Reviewer: lowest ranking person in my workgroup from wisconsin usa
Regarding the discussion about creating id numbers for
clients in nursing homes:

"Suppose a client visited the nursing home in January 2007, the client code is having  following 
format "P07A001"
Out of this "P" is hardcoded.
07 stands for year "2007".
A - Standands for January, (If client visited in February  then this would be "B",If client visited 

in March then it would be "C" ..If client visited in December then it would be "L").

001 is the running number.(This number is reset back to 000 in the next month).

For the 2nd client in the January 2007 the  client code will be 'P07A002', 3rd client in the 
January 2007 the client code will be "P07A003".

In case of February 2007,first client who visits the nursing home will have client code as 
"P07B001",
Second client who visits the nursing home will have client code as "P07B002".
"
The problem is that coding things into id numbers comes from 
managers. It is very very difficult to be a lowly dba or
developer and try to tell managers they cannot have elaborate coding schemes in ids because "it's 
wrong". They do it all the time in excel and nothing bad happens. That's their standard for 
goodness :-(. They didn't study computer science like we did and they don't much value it. My bs in
cs does not look impressive against their mba's, doctorates, and managerial titles. That's the real 
world.

Without a very big very persuasive 'book of what is right and wrong in databases for managers 
without a computing background' to show them, arguing with managers about such things and risking 
insubordination is the biggest career shortener ever I'm afraid. BUT there is now a very very good 
reason to not do this type of thing that one can invoke. It is potentially identifying of the 
persons eg in this case the persons in the nursing home. If what the questioner meant by "client" 
was people admitted to nursing homes then a raft of confidentiality principles arise. If he meant 
employees visiting nursing homes it still could be the case that somehow this data could be 
considered to link to some
confidential information about people in nursing homes. One can invoke visions of HIPAA and state 
level confidentiality laws and if this has something to do with research, human subjects' 
regulations. Anything like a date or location is definitely potentially identifying. Names, 
addresses, sex, gps coordinates, zip codes, ssn numbers,drivers license numbers, medical record 
numbers, phone numbers, email addresses, url's, and a lot more may be considered identifiable under 
some circumstances. Because of this in a study I'm involved in we have to assign unique subject id 
numbers randomly because of the possibility
of linking a range of numbers with a visited location in the state. Issues about doing that are why 
I was reading this thread. 


3 stars Why bother users with primary keys?   March 17, 2008 - 12pm Central time zone
Reviewer: Thomas Bender from Scotland
I have in the past worked with a database that used (year)|(month)|(number) as primary key, and it 
really was painful. Primary keys are nothing that users should worry about, tamper with, or even 
see. If there is a requirement for gapless numbers or composite codes, there's always the 
possibility of an alternative unique key (which I wouldn't use for RI, though).

After all, users may want to change their composite codes from (year)|(month)|(number) to 
(year)|(quarter)|(month)|(number) some day. Easily done if that composite code is not used for RI.

Sorry for the somewhat purist opinion.


Followup   March 24, 2008 - 8am Central time zone:

It is not purist, it is just correct.
5 stars SEQUENCE CACHE SIZE   July 11, 2008 - 12pm Central time zone
Reviewer: Stan from Boston
Hi Tom,

our software is distributed to clients with different needs.  All get the same schema.  
Consequently each client my put a load on different sequences in the schema.  Instead of trying to 
identify which client uses which sequences heavily I suggest to just bump the cache on all 
sequences to 1,000 across the board.

Would you agree or do you see any downside to that?

Thanks in advance.


Followup   July 11, 2008 - 1pm Central time zone:

i see no downsides
5 stars a gapless sequence   August 2, 2008 - 6am Central time zone
Reviewer: rc from The Netherlands
An easy way to create a gap less sequence is to ask the users to enter the sequence numbers by 
hand. 

One of my customers had 10.000 boxes, all with an unique number printed on top. The users take a 
box, fill it with some stuff, enter the number in our application and click on the save button. 

It seems primitive but we never heard any complaints.  



Followup   August 3, 2008 - 2pm Central time zone:

what happens when a water pipe bursts in the room over the room the boxes are in and 50 of the boxes are completely and utterly damaged beyond use.

or someone crushes a box by accident.

or - whatever


it is not gapless in general. And it is not a system assigned, gap free sequence either. it is external data the end user inputs.
5 stars gap less   August 4, 2008 - 6am Central time zone
Reviewer: rc from The Netherlands
>What happens when a water pipe burst ... or whatever...  

Their problem, not an application problem.  And why should 'the system' do everything? The user can 
also think and act. "In der Beschränkung zeigt sich erst der Meister!"


Followup   August 4, 2008 - 1pm Central time zone:

so, it is not gap free - that is my point.

And goes back to the fact that database sequences never need be gap free

because checks get voided
because water spills
because fire burns

we've never had gap free anythings.
5 stars never   August 4, 2008 - 3pm Central time zone
Reviewer: rc from The Netherlands
I don't know if database sequences never need to be gap free. One of my teachers at high school 
always said: 'never say never', he taught English (I almost wrote 'he teached English'). 

Knowing the answer to this question means knowing all the law systems on this planet, not easy. 
(Laws don't have to be reasonable). 

I just say that you don't always need a database sequence, user entry or bar code scanning 
sometimes matches the physical reality much closer. My guestimate is that users understand that 
fire and water can cause a little havoc, users don't always understand that you can't guarantee a 
gap less database sequence.  


Followup   August 4, 2008 - 3pm Central time zone:

never say never
never say always
I always say

that is one I'm fond of


The fact is: database sequences ARE NOT gap free, they cannot be, they never will be, they will always have gaps

therefore, it does not compute to say "database sequences never need to be gap free" - they cannot be gap free, that is a fact.


The laws easily accommodate this stuff. You can assign the numbers when you close the books (way one), you can void records - just like you did with water, fire, loss, whatever.



5 stars All the laws?   August 4, 2008 - 3pm Central time zone
Reviewer: rc from The Netherlands
I don't know all the laws on this planet, neither do you, do you? I can't believe you know them 
all. 

If a gap free database sequence can't exist because it is impossible, users will have to do it 
another way if they need it, so without a database sequence. Nothing wrong with that. 

Whether such another way exists or not is not my problem. 


Followup   August 4, 2008 - 8pm Central time zone:

all i know is "gap free anything"

a) has never been possible, ever, not before computers even. water exists, water makes it impossible.

b) therefore, if there is a law against it, all citizens in that country would be in jail


It is your problem, you are tasked with building systems. when someone comes to you with something so entirely utterly and completely unreasonable - you must push back.

Ask them to see that law, then you'll see or not....

Everything wrong with trying to satisfy a requirement that does NOT EXIST and would so cripple performance as to make a system unusable.

5 stars The "reality" of gap free sequences   September 11, 2008 - 6am Central time zone
Reviewer: Dieter Oberkofler from Vienna, Austria
Hi Tom,

I have been following this discussion from the very beginning and find it most interesting and 
amusing but not that useful anymore.
I know how important (2nd after binding!) this issue is for you and therefore hesitated to add my 
comments but finally I just take the risk.

I truly believe that the discussion got far to emotional and is starting to miss the point.

In my opinion the facts are:

1) Most people (especially SOX auditors) very much like the idea of a gap free sequence because 
they (and people in general) interpret some inherent correctness in it.
2) A 100% gap free sequence has been impossible on paper and still is today as you indicated in 
your examples.
3) Trying to enforce a gap free sequence leads to all kinds of performance problems due to 
serialization issues in applications.

We therefore need to find a COMPROMISE between what people "like" and what is technically 
reasonable.
I still completely agree with your point and everyone should try to avoid serialization and use 
database sequences whenever possible. At the same time my experience with clients shows that there 
is a strong demand to have "something like" a gap free sequence and we have to "deal" with this as 
well.

In my opinion the goals should be:
- Use database sequences whenever possible
- Try to avoid or explain gaps whenever needed
- Deal with the fact that we cannot completely avoid gaps

We are currently using all kind of different "sequences" for different
situations:
- We use database sequences whenever possible
- We use serialized operations whenever absolutely needed (and if concurrency allows us)
- We use MAX+1 in some cases of combined keys
- In some cases we just try to "track and explain" gaps

I'm still most interested to hears how others deal with what I would call "the reality" of 
sequences.

Dieter


Followup   September 16, 2008 - 12pm Central time zone:

1) they do not exist, and they never ever have.

2) true

3) correct


I saw no "solution" proposed here at all? Other then you stating "they never existed and they do not exist now"


max+1 doesn't even do it in real life.



When you close the books (that is what gets audited), you are free to assign to these rows that will never ever change a sequential number.

Nothing else really "works" or even makes sense.


Show me a third party product that does invoicing and 100% assures you of gap free numbers (not that gap free means *ANYTHING* at all, it shows NOTHING)


3 stars Gapless sequence   December 9, 2008 - 8am Central time zone
Reviewer: Mani from Chennai, India
As another reviewer mentioned, gapless sequences are mandated in many european countries (Spain, 
Italy, France, Greece, Austria ), Oracle's own Applicaions product(E-Business suite) understands 
this and provides solutions too for gapless sequencing. So we need to live with that. No escape 
from long arm of the law. Law enforcing bodies have their own logics and rationals.

Mani


Followup   December 9, 2008 - 2pm Central time zone:

no one provides for it, no one.


if you want, just update the silly numbers when you close the books - use a column called "the_special_gap_free_number" - it is maintained when you CLOSE THE BOOKS.

we have never - never had gap free numbers. Unless you come back and "free the gaps" later.



4 stars Gap free Seq   December 10, 2008 - 1am Central time zone
Reviewer: Umesh Kasturi from Bangalore
I think we could achieve the gap free sequence in a table ; but at the expense of 2 sequence for 
one

May be I do all the transactions using one sequence and if succesful I update the record using the 
second sequence

I know this is dirty ; but I think it helps


Followup   December 10, 2008 - 9am Central time zone:

nope, that won't work either. think it through.


all it takes is one failure. So, you do a successful transaction - and commit - now what - what makes sure

a) the second transaction even happens?
b) that the second transaction succeeds?
2 stars Gapless Sequence   December 10, 2008 - 8am Central time zone
Reviewer: Mani from Chennai, India
Tom,

This is the link for the document 11i Ebiz Suite Sys Admin guide.

http://download.oracle.com/docs/cd/B25284_01/current/acrobat/115sacg.zip

The document part pertaining to Gapless sequence is pasted below.

Gapless numbering also automatically generates a unique number for each document, but ensures that 
the document was successfully generated before assigning the number. With Gapless numbering, no 
sequence numbers are lost due to incomplete or failed document creation.

Am not getting what you mean when you say no-one ever does. Ebiz product may be internally using 
serialization for achieving this, but this certainly caters the gapless sequence requirement.

Thanks
Mani


Followup   December 10, 2008 - 10am Central time zone:

do you see what they did - exactly what I said


THEY COME BACK LATER AND DO A NUMBERING


*later*

*after the fact*

*not as part of your transaction*

*as a separate thing later*


Just like you can do with anything you want to do. close the books at the end of the month? great - go back and assign this fictitious number to a column you call "this_is_the_real_invoice_number_wink_wink"

and just ignore the existence of the true primary key of the table...
5 stars Large entities do use random numbering   December 10, 2008 - 10am Central time zone
Reviewer: sPh from USA
> ) Most people (especially SOX auditors) very much 
> like the idea of a gap free sequence because 
> they (and people in general) interpret some inherent 
> correctness in it.

Computer Discount Warehouse (CDW), one of the largest computer hardware/software suppliers in the 
United States (and I believe one of the most profitable direct sales entities anywhere) was a 
public company until 2007.  CDW uses what are AFAICS randomly generated characters strings for 
sales order acknowledgements, packing lists, and invoices.  If there is a pattern to them I can't 
see it, but they certainly aren't sequential as can be seen when you have an emergency order that 
is shipped at 0300 on Sunday and it generates 27 invoices.

sPh


5 stars sequence   February 7, 2009 - 8am Central time zone
Reviewer: A reader 
create table qstages (
bkno  number(10),
media varchar2(3),
stage_no number(1),
recdt date,
compdt date,
status varchar2(1),
created_Date   date
)

currently table has no primary key. it has a unique index on (bkno,media,stage,recdt,status).

Created_Date was added newly to table so thousands of old records do not have one.

i found it hard to deal with this table (sorts,query) as i need to sort records to find last record 
entered for a book. A stage_no does not have to be incremental (ie they can do stage 4 before stage 
2).

I am thinking of adding a "Seqno" to the table and poulate it via "after-insert" from DB.

1.  would you add a sequential number for each record i.e. 1,2,3,...150,000
or would you add 1,2,3 and the reset it for each book.

In the first case (seqno) would be PL, and second case PK would be (bkno,seqno)

It sounds to me the second option is better but not easy to implement as the t rigger would have to 
count the number of records for each book and then add one and create the next one. I probably need 
some program to sort records and apply numbers correctly (cnat be done in SQL).

2.  in one other column you mention that you can get autogenerated seq number using

but mod( dense_rank() ...., 4 ) would make it be 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, ... 

how can this be done?

3. I enforced a default constraint for "created Date" and i still see some nulls sometimes. How do 
you expalin that? should not oracle add that even if application missed that. do you think 
something is updating that field to NULL.

4. All the old records do not have created dates. Is there any way to get that from oracle 
internally. does it keep track on when a row was created?

thank you,


3 stars dbms_random   February 25, 2009 - 5am Central time zone
Reviewer: Anil 
Tom,
If I have to generate unique values in an query, can I use dbms_random? I have a problem with 
ROWNUM as it's doing a full table scan.

CREATE OR REPLACE VIEW MY_VIEW1 AS
SELECT ROWNUM COL0, COL1, COL2
FROM MY_TABLE1

SELECT * FROM MY_VIEW1
WHERE COL1 = 111;

The above query goes for a full table scan. 

So, I thought I would use DBMS_RANDOM() but Iam doubtful whether it generates unique numbers.

CREATE OR REPLACE VIEW MY_VIEW1 AS
SELECT ROUND(DBMS_RANDOM.VALUE(1,100)) COL0, COL1, COL2
FROM MY_TABLE1

SELECT * FROM MY_VIEW1
WHERE COL1 = 111

Do you any alternative way to generate the unique values? I have query from a view only.



Followup   February 25, 2009 - 6am Central time zone:

... If I have to generate unique values in an query, can I use dbms_random? ...

well, of course not. dbms_random returns a random number, the probability it returns "1" twice exists.


you will need to explain your entire problem - rownum would not in general "force" that, so - explain in painstaking DETAIL what you are trying to do - do not provide solutions that haven't worked - provide only "what you are trying to do - phrased as a specification", then we can generate a solution for you.
3 stars Here's the specification   February 25, 2009 - 7am Central time zone
Reviewer: Anil 
Tom,
We want to generate unique number (not neccessarily it should start from 1) while SELECTing from a 
VIEW. This view will be based on an another table which is not having any unique column (though 
there's composite primary key)

Table
-----
Col1       Col2    Col3
A          PPP    10-jan-2008
A          XXX    11-jan-2008
A          HGF    10-jan-2008
B          A12    10-jan-2008
C          LMN    10-jan-2008
C          PQR    12-jan-2008
Z          C15    1-feb-2008

If I want to fetch all the rows where Col1='A' and the result should look like:

View
----
Serial_No Col1  Col2     Col3
1          A     PPP    10-jan-2008
2          A     XXX    11-jan-2008
3          A     HGF    10-jan-2008

Assuming Col1 and Col2 are composite primary key. The Serial_No must be a running sequence not 
necessarily should start from 1

I hope Iam clear in my explaination. 





Followup   February 25, 2009 - 5pm Central time zone:

just add rownum to the view, but be prepared for it to be slow slow slow - as it would have to evaluate rownum before applying any of your other predicates against the view (no view merging)

this all sounds very fishy, this unique column - would not be deterministic, so while it might be unique - it would be USELESS, no idea why you would want it, no idea what you could use it for, it would be less than useful - it would be misleading at best and used inappropriately at worst.

why do you want this?


If it is really that the view would be a single table view like this:

CREATE OR REPLACE VIEW MY_VIEW1 AS
SELECT ROUND(DBMS_RANDOM.VALUE(1,100)) COL0, COL1, COL2
FROM MY_TABLE1


why not use rowid? If you do not enable row movement and never reorganize this table, at least rowid would be unique AND deterministic.


or better yet, fix the table, give it the required primary key.
4 stars To: Anil   February 26, 2009 - 5am Central time zone
Reviewer: Oleksandr Alesinskyy from Germany
Consider usage of analytical row_number() over(...) function if you definitely need your number.

But tom is 100% right - it very hard to imagine meaningful usage of a such number.

Followup   March 3, 2009 - 7am Central time zone:

it would have the same defects as rownum - most acute would be "not deterministic". I cannot see the use of an artificial unique number that cannot be reproduced in the same fashion tomorrow.
3 stars   March 3, 2009 - 10am Central time zone
Reviewer: Oleksandr Alesinskyy 
Sure it would - that why a said that it's hard to imagine reasonable usage of this number. 


3 stars the best sequential method I've found so far   March 9, 2009 - 6pm Central time zone
Reviewer: Mark M 
I've got the same opinion as Tom about sequence numbers, but at one time I had a CFO that would 
question me personally every time there was a gap in check numbers and I wanted him off my back.

THIS METHOD STILL DOES NOT GUARANTEE THERE WILL NEVER BE A GAP.  But it minimizes the risk of a gap 
tremendously.

(1)  Create a sequence with NOCACHE, ORDER, and INCREMENT BY 1.  
 o Yes, I know NOCACHE hurts performance.
 o ORDER only matters in a cluster (according to 10g documentation), and can seriously hurt 
performance.
(2)  Create an autonomous stored function to insert your new record.
 o Make sure you do as little as possible between getting the sequence number and committing the 
record.  Ideally, the seq.nextval is in the insert statement.
 o Return the new sequence number for future reference.
 o Give your new record a status of VOID.  If something happens before you get back to saving the 
rest of your information you have a voided record.

I never ran into a gap again.  That doesn't mean there aren't holes.  There are:

(1)  No matter how close the seq.nextval to the commit, there is an opportunity for Oracle to be 
shut down or crash.  If you are truly anal you can create a database trigger to run after the 
database starts to find the max sequence and update the sequence to value + 1;

(2)  If you have high transaction volume there is no reason to believe that the records in 
different connections will be committed in the order the sequences were handed out.  That doesn't 
mean there will be a gap, only that they will not be committed in the same order they were handed 
out.  

(3)  Combining (1) and (2) means you can have an out-of-sequence crash where the 2nd one is 
committed and the 1st one isn't.  This is a gap that can't be mended by just updating the sequence 
with a database startup trigger.  Told you there was a hole.  You can use the same database trigger 
to create a voided record for each gap if that makes you feel any better.  Or use different 
sequences for each user or station to avoid concurrency issues.

(4)  There are any number of innovative ways to fail the insert, which will eat your sequence 
number.  Make the insert as simple as possible, ideally just the sequence.  Or insert normally and 
have the autonomous function do an update at a later time.

(5)  If you REALLY REALLY need to make sure, use pre-printed invoice forms that already have the 
invoice number on them.  After printing enter the invoice number into your application.  (You can 
streamline this with pre-printed bar-codes!)  Manage your coffee-stained, stolen, etc., invoices 
outside the computer system.


I wonder if you could do something with advanced queues to really take care of the concurrency 
issue.  I'm sure that would be a ridiculous solution, but it's fun to think about.


4 stars mainataing sequences using autonomus transaction in RAC   September 30, 2009 - 8am Central time zone
Reviewer: A Reader from PA
Would like to know any impact of generating the sequences using autonomous transaction in RAC 
environment, While loading the data in bulk, we are seeing high "log file sync" and "wait scn ack" 
waits, though same test runs fine in NON-RAC environment with no waits. The procedure is selecting 
(SELECT FOR UPDATE)  and then updating the in-built sequence based on certain criteria.


Followup   October 7, 2009 - 8am Central time zone:

just alter the sequence to be cache 10000000;


since

a) sequences are NEVER GAP FREE
b) sequences NEVER IMPLY ORDER

this is perfectly ok, if you made the mistake of falsely believing either A or B, stop it with A (it is not possible, it is not physically possible) and with B, start using some attribute YOU assign (like a date, a timestamp) to order data, nothing but nothing else works.


sequences already use autonomous transactions - that is why you are seeing high log file sync waits. By default every 10 times you hit a sequence we

a) start an autonomous tranaction
b) update seq$
c) commit <<<=== log file sync!!!! right there


the only correct way to fix that is to up the cache size to something reasonable.

Write a Review
 


All information and materials provided here are provided "as-is"; Oracle disclaims all express and implied warranties, including, the implied warranties of merchantability or fitness for a particular use. Oracle shall not be liable for any damages, including, direct, indirect, incidental, special or consequential damages for loss of profits, revenue, data or data use, incurred by you or any third party in connection with the use of this information or these materials.

About Oracle | Legal Notices and Terms of Use | Privacy Statement