简体   繁体   中英

Setting values of additional number column in order not to violate primary key

I have a table filled in with some values, for example:

CREATE TABLE TABLE1(FOREIGN_ID VARCHAR(5), VV VARCHAR(10));

INSERT INTO TABLE1(FOREIGN_ID, VV) VALUES ('I1', 'XXXXX');
INSERT INTO TABLE1(FOREIGN_ID, VV) VALUES ('I2', 'YYYYY');
INSERT INTO TABLE1(FOREIGN_ID, VV) VALUES ('I2', 'ZZZZZ');
INSERT INTO TABLE1(FOREIGN_ID, VV) VALUES ('I2', 'SSSSS');
INSERT INTO TABLE1(FOREIGN_ID, VV) VALUES ('I2', 'SSSSS');
INSERT INTO TABLE1(FOREIGN_ID, VV) VALUES ('I1', 'TTTTT');

FOREIGN_ID  VV
----- ---------
I1   XXXXX
I2   YYYYY
I2   ZZZZZ
I2   SSSSS
I2   SSSSS
I1   TTTTT

And I want to add a new column and make it a part of a primary key:

ALTER TABLE TABLE1 ADD SEQ_NUMBER NUMBER(5) DEFAULT 0 NOT NULL;

ALTER TABLE TABLE1 ADD CONSTRAINT TABLE1_PK PRIMARY KEY (FOREIGN_ID, SEQ_NUMBER);

Of course, the value 0 of SEQ_NUMBER and repeated values of FOREIGN_ID will violate the primary key. How (using Oracle SQL) to set SEQ_NUMBER to 0, 1, 2, ... for each value of SEQ_NUMBER before the constraint is added?

The result could look like this:

FOREIGN_ID  VV  SEQ_NUMBER
----- --------- -----
I1   XXXXX     0
I2   YYYYY     0
I2   ZZZZZ     1
I2   SSSSS     2
I2   SSSSS     3
I1   TTTTT     1

You can use the row_number analytic function to compute the rank:

select t.*,
       row_number() over (partition by t.foreign_id order by t.vv) - 1 seq_number
from TABLE1 t;

This gives the expected result:

FOREIGN_ID  VV  SEQ
I1  TTTTT   0
I1  XXXXX   1
I2  SSSSS   0
I2  SSSSS   1
I2  YYYYY   2
I2  ZZZZZ   3

Now there is a problem with analytic functions: you can only use them in select and group by clauses because they are computed at the end. This means that you cannot do what you would like to do, ie:

update TABLE1 t
set t.seq_number = row_number() over (partition by t.foreign_id order by t.vv)-1
;

The best workaround I can think of is to create another table from this one:

create table TABLE2 as
select t.foreign_id,
       t.vv,
       row_number() over (partition by t.foreign_id order by t.vv) - 1 seq_number
from TABLE1 t;

Then you can apply the PK on this one !

ALTER TABLE TABLE2 ADD CONSTRAINT TABLE2_PK PRIMARY KEY (FOREIGN_ID, SEQ_NUMBER);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM