213

尝试在 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

谁能解释为什么会出现这个错误?

4

4 回答 4

269

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

bar因此,假设您在包含名称的表上有 2 行,并且您在on 上插入'ams'一行,由于有两行匹配,它将引用哪一行?baz'ams'bar_fkbar

于 2012-08-15T09:00:22.520 回答
110

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

另请参阅http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK,特别是:

最后,我们应该提到外键必须引用作为主键或形成唯一约束的列。

强调我的。

于 2012-08-15T08:54:32.017 回答
13

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

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

    \d table_name
    

    您在底部显示为这样"some_constraint" PRIMARY KEY, btree (column)

  2. 删除约束:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
    
  3. 用现有的主键列添加一个新的主键列:

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

就这样。

于 2018-01-17T06:43:42.447 回答
9

当您像所做UNIQUE的那样作为表级约束执行时,您的定义有点像复合主键,请参见ddl 约束,这是一个摘录

这指定指定列中的值组合在整个表中是唯一的,尽管任何一列不必是(并且通常不是)唯一的。

这意味着如果组合是唯一的并且这与您的外键约束不匹配,则任一字段都可能具有非唯一值。

您很可能希望约束处于列级别。因此,与其将它们定义为表级约束,不如将它们“附加”UNIQUE到列定义的末尾,name VARCHAR(60) NOT NULL UNIQUE或者为每个字段指定单独的表级约束。

于 2012-08-15T09:09:34.590 回答