views:

76

answers:

4

Hi Folk, I'm trying to see if exists something to create a sequence with partition logic. I need a sequence number that depend on other primary key ex:

id_person   sequence id
        1 | 1
        1 | 2
        2 | 1
        3 | 1
        1 | 3

so the sequence must depend on the id_person partition. Is there something like this on oracle or i must implement it by myself on the application level?

thank you.

A: 

I'm afraid you have to do it like this:

INSERT INTO t
(
  id_person,
  sequence_id
)
VALUES
( 
  <your_person_id>,
  ( SELECT 1 + NVL( MAX( sequence_id ), 0 )
    FROM t
    WHERE t.id_person = <your_person_id>
  )
)
Peter Lang
thank for the idea, i'm trying to implement a package pl-sql to make this kind of sequence
Macdeveloper
You'll need to handle the situation where 2 users try the insert at the same time - one will fail due to a PK violation.
Tony Andrews
Why not just use a normal sequence and not have it dependent on the person? You can still present a person-dependent order number to the client application if required.
Nick Pierpoint
@Tony Andrews: Definitely right. I tried to avoid this problem by putting the `INSERT` into a procedure and call it recursively in the `DUP_VAL_ON_INDEX`-exception handling block. As the second `INSERT` is being blocked by the first transaction, the second attempt succeeds. Nothing to be proud of, though... Any suggestions?
Peter Lang
@nick if i can choice I prefer to put ordered sequence, also in in insert is a little bit slow, but in read i can have more simple select
Macdeveloper
@Peter: yes, handling the DUP_VAL_ON_INDEX exception is good for most situations. Obviously, if the system were handling many inserts per second on this table for the same parent there would be a lot of these exceptions to handle, but probably that isn't the case; if it is the case, then the best bet would be to just use a sequence.
Tony Andrews
+2  A: 

Is the actual requirement that the secondary sequence be gap free? If so, you've got a giant serialization/scalability issue.

If you need to present a gap-free sequence for human consumption, you could use an actual sequence (or a timestamp, for that matter) as Nick Pierpont suggests and preserve scalability, you could use analytic functions.

Dataset (t1):

 ID_PERSON SEQUENCE_ID
---------- -----------
         1           1
         2           2
         3           3
         1           4
         1           5
         1           6
         2           7
         3           8
         1           9

SQL:

select * 
  from 
  (select id_person, 
          sequence_id as orig_sequence_id,         
          rank () 
            over (partition by id_person 
                  order by sequence_id) 
            as new_sequence_id
     from t1
  )
 order by id_person, new_sequence_id;

Result:

ID_PERSON  ORIG_SEQUENCE_ID NEW_SEQUENCE_ID
---------- ---------------- ---------------
         1                1               1
         1                4               2
         1                5               3
         1                6               4
         1                9               5
         2                2               1
         2                7               2
         3                3               1
         3                8               2
Adam Musch
+1, good solution. Avoids storing secondary sequence and it's attendant maintenance/performance issues.
DCookie
Giant? a GIANT serialization issue... with 10 records inserted per day? Where does that number come from? I made it up, just as you would have to to determine if there is *really* a concurrency problem in the offing. He may or may not have a concurrency issue.
Stephanie Page
@Stephanie Page: Designs which introduce serialization do not scale. Either it's a toy application or eventually, serialization will bite designs which use a "select max(column) + 1" "pattern". Far easier to not introduce the serialization in the first place.
Adam Musch
A: 

What you are looking for is not a sequence, as the Oracle Documentation claims: "The sequence generator provides a sequential series of numbers".

You are looking for a calculated field depending on another, in this case the primary key. As other suggested you need to add the logic on your code. It means in a procedure or in the insert sentence.

FerranB
I have created a olsql package that manage this kind od sequence and use dbms_lock to perform control over concurency. Every kind of that sequence has a table cor calculation. Late in this day i'll post the code in this post i would to' like to shareware this idea and see if it is well designed
Macdeveloper
A: 

Hi have create this PLSQL package one function and procedure:

PROCEDURE INIT_SEQUENCE(NAME varchar2, pkColumnNameList PARTITIONED_SEQUENCE_PK_COLUMN);
FUNCTION GET_NEXT_SEQUENCE_VALUE(NAME varchar2, pkPartitionColValue PARTITIONED_SEQUENCE_COL_VALUE) RETURN NUMBER;

INIT_SEQUENCE - get in input the name to associate at the sequence and a list of column name that are the fixed primary key part that vincolate the sequence Ex:'ID_PERSON'

the work of this procedure is to create the table that will manage the increment of sequence according to pkColumnNameList column.

GET_NEXT_SEQUENCE_VALUE- get the name of sequence to increment and the value of pkColumnNameList primary key and make the next step: 1) Create dynamically the sql to work 2) dbms_lock.allocate_unique(); to lock the table 3) check if is present a record in the table for pk value in input 4) if a record is present update the record with max + 1 in the sequence column 5) if a record is not present insert the new record with the 1 in the sequence column 6) return new id;

i would like to receive comment about this thanks in advanced...

Macdeveloper