2011-10-13 78 views
6

我有一個像這些行上的Postgres:空值不是唯一的

name | address | college 

john | rome | 
john | rome | 
max | tokyo | 

我創建一個表是這樣的:

create test (
name varchar(10), 
address varchar(20), 
college varchar(20), 
constraint test_uq unique (name,address,college); 

我怎樣才能讓空值成爲唯一的,所以輸出可以是這樣的:

name | address | college 

john | rome | 
max | tokyo | 
+0

有關MySQL和非唯一空值的相關問題:http://stackoverflow.com/query estions/4081783/unique-key-with-nulls – osa

回答

2

Postgres的文檔claims這種行爲符合SQL標準:

在一般情況下,當有表中的兩個或兩個以上 行的唯一約束被違反,所有列的值包含在 中的約束是相等的。然而,在這個比較中,兩個空值不被認爲是等於 。這意味着即使存在唯一的約束條件,也可以在至少一個受約束的列中存儲包含空值的重複行。這種行爲 符合SQL標準[。]

一種可能性是重新考慮你的架構(說實話,在name+address+college唯一性約束不會使整個地段的感覺在你的例子)。

+0

哦我my..so空值不是唯一的?那麼如何避免還原數據呢? 在我的真實表中,我插入記錄到表中,該表中唯一的約束是真的,然後我再次插入相同的記錄,並將相同的記錄插入到表中,最後在該表中有2個相同的記錄:( –

0

如果你把它作爲主鍵,而不是唯一的約束,它會工作。爲此,college列必須是NOT NULL並且使用(例如)空字符串而不是NULL值。 或者你正在尋找一個查詢?

+0

我不能把它作爲主鍵,因爲在我的真實數據中,有幾條記錄有一個值, –

+0

這沒關係 - 即使某些記錄有值。你希望這兩個記錄不應該有相同的(姓名,地址,大學)值,對嗎? –

+0

是的,名稱,地址,學院 –

0

NULL是未知的,所以NULL的值等於NULL永遠不會是真的。爲了解決這個問題,你可以這樣做。

爲您的學院創建一個新的查找表。在該表中有一個值爲None的記錄。然後把一個外鍵放到新的大學查詢表中。

這是僞代碼,所以你可能不得不攪亂它才能工作,但這裏是基本的想法。

CREATE TABLE college(college_id SERIAL PRIMARY KEY,college_type); 
INSERT INTO college(college_type) 
SELECT 1,None; 


create test (
name varchar(10), 
address varchar(20), 
college_id INTEGER NOT NULL DEFAULT 1, 
constraint test_uq unique (name,address,college_id); 
+0

hmm我不想讓它變成2張桌子,因爲在我的真實數據中,我必須把它做成1張桌子,因爲我的數據的目的是做一個summary_report。 但是,謝謝你的回答,我對此表示讚賞。非常感謝你 –

+0

你仍然可以按照我的意思去做,但是不要使用新表,而是用NO COLLEGE或NA代替現有的大學表中的NULL。 – Kuberchaun

+0

所以我給出了大學的默認值,然後給大學的約束不爲空? –

2

如果你只需要在查詢結果中唯一的記錄使用SELECT DISTINCT

 
postgres=# SELECT * FROM test; 
name | address | college 
------+---------+--------- 
john | rome | 
john | rome | 
max | tokyo | 
(3 rows) 

postgres=# SELECT DISTINCT * FROM test; 
name | address | college 
------+---------+--------- 
john | rome | 
max | tokyo | 
(2 rows) 

如果你想強制使用唯一的記錄,而忽略空值,你必須創建一個conditional unique index

 
postgres=# CREATE UNIQUE INDEX test_index ON test (name, address) WHERE college IS NULL; 
CREATE INDEX 
postgres=# INSERT INTO test (name, address) VALUES ('john', 'rome'); 
INSERT 0 1 
postgres=# INSERT INTO test (name, address) VALUES ('max', 'tokyo'); 
INSERT 0 1 
postgres=# INSERT INTO test (name, address, college) VALUES ('john', 'rome', 'college'); 
INSERT 0 1 
postgres=# INSERT INTO test (name, address) VALUES ('john', 'rome'); 
ERROR: duplicate key value violates unique constraint "test_index" 
DETAIL: Key (name, address)=(john, rome) already exists. 

HTH