错误:没有唯一的约束匹配给定的键参考表"bar"

尝试在Postgres 9.1中创建这个示例表结构:

CREATE TABLE foo (
name        VARCHAR(256) PRIMARY KEY
);


CREATE TABLE bar (
pkey        SERIAL PRIMARY KEY,
foo_fk      VARCHAR(256) NOT NULL REFERENCES foo(name),
name        VARCHAR(256) NOT NULL,
UNIQUE (foo_fk,name)
);


CREATE TABLE baz(
pkey        SERIAL PRIMARY KEY,
bar_fk      VARCHAR(256) NOT NULL REFERENCES bar(name),
name        VARCHAR(256)
);

运行上面的代码会产生一个错误,这对我来说没有意义:

NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "foo_pkey" for table "foo"
NOTICE:  CREATE TABLE will create implicit sequence "bar_pkey_seq" for serial column "bar.pkey"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "bar_pkey" for table "bar"
NOTICE:  CREATE TABLE / UNIQUE will create implicit index "bar_foo_fk_name_key" for table "bar"
NOTICE:  CREATE TABLE will create implicit sequence "baz_pkey_seq" for serial column "baz.pkey"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "baz_pkey" for table "baz"
ERROR:  there is no unique constraint matching given keys for referenced table "bar"
********** Error **********


ERROR: there is no unique constraint matching given keys for referenced table "bar"
SQL state: 42830

有人能解释为什么会出现这个错误吗?

298283 次浏览

在postgresql中,所有外键都必须引用父表中的唯一键,所以在你的bar表中,你必须有一个unique (name)索引。

请参见http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK,具体地说:

最后,我们应该提到外键必须引用列

我特别强调。

这是因为bar表上的name列没有独特的约束。

所以想象你在bar表中有两行包含名字'ams',你在baz上插入一行,在bar_fk上插入'ams',既然有两行匹配,它将引用bar上的哪一行?

当你把UNIQUE作为一个表级约束时,你的定义有点像一个复合主键,请看ddl约束,这里是一个提取

这指定了在所指定列中的值的结合在整个表中是唯一的,尽管任何列都不需要是(通常也不是)唯一的。

这意味着如果结合是唯一的,并且这与你的外键约束不匹配,那么任何一个字段都可能有一个非唯一的值。

大多数情况下,您希望约束位于列级。因此,与其将它们定义为表级约束,不如将UNIQUE '追加'到列定义的末尾,如name VARCHAR(60) NOT NULL UNIQUE或为每个字段指定单独的表级约束。

您应该将name列作为唯一的约束。这里有3行代码来改变你的问题

  1. 首先通过键入以下代码找出主键约束

    \d table_name
    

    你会像这样显示在底部"some_constraint" PRIMARY KEY, btree (column)

  2. ALTER TABLE table_name DROP CONSTRAINT some_constraint
    
  3. Add a new primary key column with existing one:

    ALTER TABLE table_name ADD CONSTRAINT some_constraint PRIMARY KEY(COLUMN_NAME1,COLUMN_NAME2);
    

That's All.