O que está causando o erro: não há nenhuma restrição exclusiva que corresponda a determinadas chaves para a tabela referenciada?

154

Abaixo, a estrutura da tabela de exemplo fornece um ERRO: não há nenhuma restrição exclusiva que corresponda às chaves fornecidas para a tabela referenciada e, depois de observá-la por um tempo, não consigo descobrir por que esse erro ocorre nessa situação.

BEGIN;

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)
);

COMMIT;

A execução do código acima fornece o seguinte erro, o que não faz sentido para mim, alguém pode explicar por que esse erro ocorre. Estou usando o postgres 9.1

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
ams
fonte

Respostas:

188

É porque a namecoluna nobar ocorre tabela não possui a restrição UNIQUE .

Imagine que você tenha 2 linhas na bartabela que contêm o nome 'ams'e insira uma linha bazcom 'ams'on bar_fk, a qual linha barela se referiria, pois existem duas linhas correspondentes?

Diego
fonte
1
perfeito curto e preciso e fácil de pegar explicação!
Alex
79

No postgresql, todas as chaves estrangeiras devem fazer referência a uma chave exclusiva na tabela pai, portanto, na sua bartabela, você deve ter um unique (name)índice.

Veja também http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK e especificamente:

Finalmente, devemos mencionar que uma chave estrangeira deve fazer referência a colunas que são uma chave primária ou formam uma restrição exclusiva.

Ênfase minha.

Matteo Tassinari
fonte
21
por que o PK declarado não é considerado uma restrição única? não é como você pode ter uma PK não exclusivo ...
amphibient
2
Ele deve ser exclusivo na tabela para a qual "aponta", porque, caso contrário, o mecanismo do banco de dados não terá como saber a qual linha você está se referindo.
Matteo Tassinari
Chaves compostas? @amphibient
Charming Robot
1
Eu acho que ter uma chave única na coluna referenciada na tabela pai não é necessária no PostgreSQL somente mas também outros RDBMSs também como Oracle, SQL Server, etc
Mufachir Hossain
2
Observe que a resposta também é verdadeira para chaves estrangeiras compostas, em que uma restrição exclusiva composta ou chave primária é necessária na tabela pai.
Ninjakannon
8

quando você faz UNIQUEuma restrição no nível da tabela, como você fez, então qual é a sua definição como uma chave primária composta, veja restrições ddl , aqui está uma extração

"This specifies that the *combination* of values in the indicated columns is unique across the whole table, though any one of the columns need not be (and ordinarily isn't) unique."

isso significa que qualquer um dos campos pode ter um valor não exclusivo, desde que a combinação seja única e isso não corresponda à sua restrição de chave estrangeira.

provavelmente você deseja que a restrição esteja no nível da coluna. então, em vez disso, defina-as como restrições no nível da tabela, 'acrescente' UNIQUEao final da definição da coluna, como name VARCHAR(60) NOT NULL UNIQUEou especifique restrições no nível da tabela para cada campo.

TI
fonte
A restrição de nível de coluna na minha situação não funcionará. Eu realmente deveria estar definindo uma chave primária composta, mas eu me afastei dela, porque mapeá-la para JPA é um pouco dolorosa :) #
1520
6

Você deve ter a coluna de nome como uma restrição exclusiva. aqui estão três linhas de código para alterar seus problemas

  1. Primeiro, descubra as restrições da chave primária digitando este código

    \d table_name

    você é mostrado assim na parte inferior "some_constraint" PRIMARY KEY, btree (column)

  2. Solte a restrição:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
  3. Adicione uma nova coluna de chave primária com a existente:

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

Isso é tudo.

Hari Bharathi
fonte