设置附加数字列的值,以免违反主键

问题描述 投票:0回答:1

我有一个填充了一些值的表,例如:

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

我想添加一个新列并使其成为主键的一部分:

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);

当然,SEQ_NUMBER的值0和FOREIGN_ID的重复值将违反主键。在添加约束之前,如何(使用Oracle SQL)将SEQ_NUMBER设置为0,1,2,...为SEQ_NUMBER的每个值?

结果可能如下所示:

FOREIGN_ID  VV  SEQ_NUMBER
----- --------- -----
I1   XXXXX     0
I2   YYYYY     0
I2   ZZZZZ     1
I2   SSSSS     2
I2   SSSSS     3
I1   TTTTT     1
sql oracle constraints primary-key
1个回答
0
投票

您可以使用row_number解析函数来计算排名:

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

这给出了预期的结果:

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

现在分析函数存在一个问题:你只能在selectgroup by子句中使用它们,因为它们是在最后计算的。这意味着你不能做你想做的事,即:

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

我能想到的最好的解决方法是从这个创建另一个表:

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;

然后你可以在这个上应用PK!

ALTER TABLE TABLE2 ADD CONSTRAINT TABLE2_PK PRIMARY KEY (FOREIGN_ID, SEQ_NUMBER);
© www.soinside.com 2019 - 2024. All rights reserved.