2011-10-13 75 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