错误:引用表“bar”的给定键没有唯一约束匹配

Posted

技术标签:

【中文标题】错误:引用表“bar”的给定键没有唯一约束匹配【英文标题】:ERROR: there is no unique constraint matching given keys for referenced table "bar" 【发布时间】:2012-08-11 13:52:30 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

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

因此,假设您在 bar 表中有 2 行包含名称 'ams',并且您在 baz 上插入一行,bar_fk 上的 'ams',它会指代 bar 上的哪一行因为有两行匹配?

【讨论】:

【参考方案2】:

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

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

最后,我们应该提到外键必须引用列 要么是主键,要么构成唯一约束。

强调我的。

【讨论】:

为什么声明的 PK 不被视为唯一约束?这不像你可以有一个非唯一的PK...... 它在它“指向”的表上必须是唯一的,因为如果不是,数据库引擎将无法知道您实际指的是哪一行。 复合键? @amphibient 我认为仅在 postgresql 中不需要在父表上的引用列上具有唯一键,而且其他 RDBMS 也需要,如 oracle、sql server 等。 请注意,对于复合外键,答案也是正确的,其中父表上需要复合唯一约束或主键。【参考方案3】:

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

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

    \d table_name
    

    你在底部显示为"some_constraint" PRIMARY KEY, btree (column)

    删除约束:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
    

    用现有的主键列添加一个新的主键列:

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

仅此而已。

【讨论】:

【参考方案4】:

当您将UNIQUE 用作表级约束时,您的定义有点像复合主键,请参阅ddl constraints,这是一个摘录

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

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

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

【讨论】:

列级约束在我的情况下不起作用我真的应该定义一个复合主键,但我放弃了它,因为将它映射到 JPA 有点痛苦:)

以上是关于错误:引用表“bar”的给定键没有唯一约束匹配的主要内容,如果未能解决你的问题,请参考以下文章

添加外键约束时遇到问题(错误 ORA-02270:此列列表没有匹配的唯一键或主键)

oracle 唯一索引,唯一约束,主键之间的联系

数据库相关练习题

MySQL数据库:数据完整性及约束的应用

更改表 - 错误 ORA-02270

约束的类型