postgresql----數據庫表約束----UNIQUE


 

四、UNIQUE ---- 唯一約束

唯一鍵可以是單個字段,也可以是多個字段的組合,設置唯一約束后,INSERT或UPDATE時如果表中唯一鍵字段中已存在該數據,則拒絕該行數據的INSERT或UPDATE。但是數據庫中NULL並不等於NULL,所以唯一鍵中如果沒有NOT NULL約束,則可以在唯一鍵中INSERT或UPDATE任意多個NULL。

1.創建測試表

唯一約束為組合鍵(a,b),即a和b的組合必須是唯一的。

create table tbl_unique(
a int not null,
b int,
c varchar(10) not null default 'catch u',
constraint uk_tbl_unique_a_b unique(a,b)
);

向tbl_unique表中寫入數據(1,,1,'test')

test=# insert into tbl_unique (a,b,c) values(1,1,'test');
INSERT 0 1

再次寫入(a,b)組合(1,1)時,則會返回錯誤。

test=# insert into tbl_unique (a,b,c) values(1,1,'u see');
ERROR:  duplicate key value violates unique constraint "uk_tbl_unique_a_b"
DETAIL:  Key (a, b)=(1, 1) already exists.

那么唯一鍵中出現NULL呢?唯一鍵中可以寫入任意多個NULL!

test=# insert into tbl_unique (a) values(2);
INSERT 0 1
test=# insert into tbl_unique (a) values(2);
INSERT 0 1
test=# insert into tbl_unique (a) values(2);
INSERT 0 1
test=# \pset null 'NULL'
Null display is "NULL".
test=# select * from tbl_unique ;
 a |  b   |    c    
---+------+---------
 1 |    1 | test
 2 | NULL | catch u
 2 | NULL | catch u
 2 | NULL | catch u
(4 rows)

2.唯一鍵約束刪除

test=# alter table tbl_unique drop constraint uk_tbl_unique_a_b ;
ALTER TABLE

3.唯一鍵約束增加

如果你想向表中增加唯一約束,必須要考慮表中已存在的數據可能存在重復數據。重復的數據有兩種理解方式:

方式一:嚴格意義上的唯一,NULL不等於NULL,即(1,NULL)和(1,NULL)不是重復數據。

方式二:非嚴格意義上的唯一,NULL等於NULL,即(1,NULL)和(1,NULL)是重復數據。

 

所以向表中增加唯一約束必須要刪除這些重復數據,或者將重復數據刪除到唯一。

情況一:刪除嚴格意義上的重復

第一步:清空測試表,寫入一些測試數據。

 

test=# delete from tbl_unique ;
DELETE 4
test=# insert into tbl_unique (a,b) values (1,1),(1,1),(1,1);
INSERT 0 3
test=# insert into tbl_unique (a) values (2),(2),(2);
INSERT 0 3
test=# select * from tbl_unique ;
 a |  b   |    c    
---+------+---------
 1 |    1 | catch u
 1 |    1 | catch u
 1 |    1 | catch u
 2 | NULL | catch u
 2 | NULL | catch u
 2 | NULL | catch u
(6 rows)

 

從結果中看,嚴格意義上的唯一有1個(1,1,'catch u')和3個(2,NULL,'catch u'),刪除重復數據即是要刪除所有的(1,1,'catch u')。這種情況下只要使用下面的語句刪除即可。

delete from tbl_unique where a= 1 and b = 1;

但是如果表中存在成千上萬個這種重復數據,這么一條一條的刪除豈不顯得低級?!

第二步:查詢(a,b)存在重復的數據

test=# select a,b from tbl_unique where a is not null and b is not null group by a,b having count(*) > 1;
 a | b 
---+---
 1 | 1
(1 row)

第三步:查詢所有(a,b)重復的數據

test=# select * from tbl_unique where exists(select null from (select a,b from tbl_unique where a is not null and b is not null group by a,b having count(*) > 1)tbl_temp where tbl_temp.a=tbl_unique.a and tbl_temp.b=tbl_unique.b) ;
 a | b |    c    
---+---+---------
 1 | 1 | catch u
 1 | 1 | catch u
 1 | 1 | catch u
(3 rows)

第四步:刪除所有(a,b)重復的數據

把上面的語句中select *替換成 delete就可以了。

test=# delete from tbl_unique where exists(select null from (select a,b from tbl_unique where a is not null and b is not null group by a,b having count(*) > 1)tbl_temp where tbl_temp.a=tbl_unique.a and tbl_temp.b=tbl_unique.b) ;
DELETE 3
test=# select * from tbl_unique ;
 a |  b   |    c    
---+------+---------
 2 | NULL | catch u
 2 | NULL | catch u
 2 | NULL | catch u
(3 rows)

第五步:增加唯一約束

test=# alter table tbl_unique add constraint uk_tbl_unique_a_b unique (a,b);
ALTER TABLE

 

情況二:刪除非嚴格意義重復數據

第一步:刪除約束,清空數據,寫入測試數據

test=# alter table tbl_unique drop constraint uk_tbl_unique_a_b ;
ALTER TABLE
test=# delete from tbl_unique ;
DELETE 3
test=# insert into tbl_unique (a,b) values (1,1),(1,1),(1,1);
INSERT 0 3
test=# insert into tbl_unique (a) values (2),(2),(2);
INSERT 0 3
test=# select * from tbl_unique ;
 a |  b   |    c    
---+------+---------
 1 |    1 | catch u
 1 |    1 | catch u
 1 |    1 | catch u
 2 | NULL | catch u
 2 | NULL | catch u
 2 | NULL | catch u
(6 rows)

非嚴格意義上該表中的數據全部是重復數據,和情況一比只需要把NOT NULL過濾條件去掉即可。

第二步:查詢(a,b)重復數據

test=# select a,b from tbl_unique group by a,b having count(*) > 1;
 a |  b   
---+------
 2 | NULL
 1 |    1
(2 rows)

 

第三步:查詢所有(a,b)重復數據

test=# select * from tbl_unique where exists(select null from (select a,b from tbl_unique group by a,b having count(*) > 1)tbl_temp where (tbl_temp.a=tbl_unique.a and tbl_temp.b=tbl_unique.b) or (tbl_temp.a is null and tbl_unique.a is null) or (tbl_temp.b is null and tbl_unique.b is null)) ;
 a |  b   |    c    
---+------+---------
 1 |    1 | catch u
 1 |    1 | catch u
 1 |    1 | catch u
 2 | NULL | catch u
 2 | NULL | catch u
 2 | NULL | catch u
(6 rows)

第四步:刪除所有(a,b)重復數據

同樣把上面語句的select * 替換成delete即可。

test=# delete from tbl_unique where exists(select null from (select a,b from tbl_unique group by a,b having count(*) > 1)tbl_temp where (tbl_temp.a=tbl_unique.a and tbl_temp.b=tbl_unique.b) or (tbl_temp.a is null and tbl_unique.a is null) or (tbl_temp.b is null and tbl_unique.b is null)) ;
DELETE 6
test=# select * from tbl_unique ;
 a | b | c 
---+---+---
(0 rows)

第五步:增加唯一鍵約束

test=# alter table tbl_unique add constraint uk_tbl_unique_a_b unique (a,b);
ALTER TABLE

如果表中沒有主鍵或NOT NULL的唯一鍵,那么可以利用表的OID屬性,將表的oid列顯示出來,該列類似主鍵的功能。利用該列,可以將重復數據刪除到只剩一條,先使用下面的SQL語句,修改表的屬性。

test=# alter table tbl_unique set with oids;
ALTER TABLE

 

情況三:將嚴格意義上重復數據刪除到只有一條

第一步:刪除表約束,清空表,寫入測試數據

test=# alter table tbl_unique drop constraint uk_tbl_unique_a_b ;
ALTER TABLE
test=# delete from tbl_unique ;
DELETE 0
test=# insert into tbl_unique (a,b) values (1,1),(1,1),(1,1);
INSERT 0 3
test=# insert into tbl_unique (a) values (2),(2),(2);
INSERT 0 3
test=# select oid,* from tbl_unique ;
  oid  | a |  b   |    c    
-------+---+------+---------
 16399 | 1 |    1 | catch u
 16400 | 1 |    1 | catch u
 16401 | 1 |    1 | catch u
 16402 | 2 | NULL | catch u
 16403 | 2 | NULL | catch u
 16404 | 2 | NULL | catch u
(6 rows)

嚴格意義上的重復數據是3條(1,1,'catch u'),現在要將三條的重復數據,刪除到只剩一條。

 

第二步:查詢重復數據的最小oid

test=# select min(oid) from tbl_unique where a is not null and b is not null group by a,b;
  min  
-------
 16399
(1 row)

 

第三步:查詢oid不是最小的重復數據

test=# select oid,* from tbl_unique where oid not in(select min(oid) from tbl_unique where a is not null and b is not null group by a,b) and a is not null and b is not null;
  oid  | a | b |    c    
-------+---+---+---------
 16400 | 1 | 1 | catch u
 16401 | 1 | 1 | catch u
(2 rows)

 

第四步:刪除oid不是最小的重復數據

把上面的SQL語句中select替換成delete即可。

test=# delete from tbl_unique where oid not in(select min(oid) from tbl_unique where a is not null and b is not null group by a,b) and a is not null and b is not null;
DELETE 2
test=# select oid,* from tbl_unique ;
  oid  | a |  b   |    c    
-------+---+------+---------
 16399 | 1 |    1 | catch u
 16402 | 2 | NULL | catch u
 16403 | 2 | NULL | catch u
 16404 | 2 | NULL | catch u
(4 rows)

 

第五步:增加唯一鍵約束

test=# alter table tbl_unique add constraint uk_tbl_unique_a_b unique (a,b);
ALTER TABLE

 

情況四:將非嚴格意義上重復數據刪除到只有一條

第一步:刪除唯一約束,清空表,寫入測試數據

test=# alter table tbl_unique drop constraint uk_tbl_unique_a_b ;
ALTER TABLE
test=# delete from tbl_unique ;
DELETE 4
test=# insert into tbl_unique (a,b) values (1,1),(1,1),(1,1);
INSERT 0 3
test=# insert into tbl_unique (a) values (2),(2),(2);
INSERT 0 3
test=# select oid,* from tbl_unique ;
  oid  | a |  b   |    c    
-------+---+------+---------
 16407 | 1 |    1 | catch u
 16408 | 1 |    1 | catch u
 16409 | 1 |    1 | catch u
 16410 | 2 | NULL | catch u
 16411 | 2 | NULL | catch u
 16412 | 2 | NULL | catch u
(6 rows)

第二步:查詢重復數據的最小oid

test=# select min(oid) from tbl_unique group by a,b;
  min  
-------
 16410
 16407
(2 rows)

第三步:查詢oid不是最小的重復數據

test=# select oid,* from tbl_unique where oid not in(select min(oid) from tbl_unique group by a,b);
  oid  | a |  b   |    c    
-------+---+------+---------
 16408 | 1 |    1 | catch u
 16409 | 1 |    1 | catch u
 16411 | 2 | NULL | catch u
 16412 | 2 | NULL | catch u
(4 rows)

第四步:刪除oid不是最小的重復數據

把上面的SQL語句中select替換成delete即可。 

test=# delete from tbl_unique where oid not in(select min(oid) from tbl_unique group by a,b);
DELETE 4
test=# select oid,* from tbl_unique ;
  oid  | a |  b   |    c    
-------+---+------+---------
 16407 | 1 |    1 | catch u
 16410 | 2 | NULL | catch u
(2 rows)

第五步:增加唯一鍵約束

test=# alter table tbl_unique add constraint uk_tbl_unique_a_b unique (a,b);
ALTER TABLE

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM