¿Qué está causando ERROR: no hay una restricción única que coincida con las claves dadas para la tabla referenciada?

155

La estructura de la tabla de ejemplo a continuación da un ERROR: no hay una restricción única que coincida con las claves dadas para la tabla referenciada, y después de haberla observado durante un tiempo, ahora no puedo entender por qué surge este error en esta situación.

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;

Ejecutar el código anterior da el siguiente error, que no tiene sentido para mí, ¿alguien puede explicar por qué surge este error? Estoy usando 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
fuente

Respuestas:

189

Es porque la namecolumna en la bartabla no tiene la restricción ÚNICA .

Imagine que tiene 2 filas en la bartabla que contienen el nombre 'ams'e inserta una fila bazcon 'ams'on bar_fk, ¿a qué fila barse referiría ya que hay dos filas coincidentes?

Diego
fuente
1
¡Perfecto, corto, preciso y fácil de entender!
Alex
79

En postgresql, todas las claves externas deben hacer referencia a una clave única en la tabla primaria, por lo que en su bartabla debe tener un unique (name)índice.

Ver también http://www.postgresql.org/docs/9.1/static/ddl-constraints.html#DDL-CONSTRAINTS-FK y específicamente:

Finalmente, debemos mencionar que una clave foránea debe hacer referencia a columnas que son una clave primaria o que forman una restricción única.

El énfasis es mío.

Matteo Tassinari
fuente
21
¿Por qué el PK declarado no se considera una restricción única? no es como si pudieras tener un PK no único ...
anfibio
2
Debe ser único en la tabla a la que "apunta", porque si no lo es, el motor de la base de datos no tendrá forma de saber a qué fila se refiere realmente.
Matteo Tassinari
Teclas compuestas? @amphibient
Robot encantador
1
Creo que tener una clave única en la columna a la que se hace referencia en la tabla primaria no solo se requiere en postgresql, sino también en otros RDBMS, como Oracle, SQL Server, etc.
Mufachir Hossain
2
Tenga en cuenta que la respuesta es verdadera también para claves foráneas compuestas, donde se requiere una restricción única compuesta o clave primaria en la tabla primaria.
Ninjakannon
8

cuando lo hace UNIQUEcomo una restricción de nivel de tabla como lo ha hecho, entonces lo que define es un poco como una clave primaria compuesta, vea las restricciones ddl , aquí hay un extracto

"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."

Esto significa que cualquiera de los campos podría tener un valor no único siempre que la combinación sea ​​única y no coincida con la restricción de clave externa.

lo más probable es que desee que la restricción esté en el nivel de columna. así que en lugar de definirlos como restricciones de nivel de tabla, 'anexar' UNIQUEal final de la definición de columna como name VARCHAR(60) NOT NULL UNIQUEo especificar restricciones de nivel de tabla individuales para cada campo.

TI
fuente
La restricción de nivel de columna en mi situación no funcionará Realmente debería definir una clave primaria compuesta, pero me alejé de ella porque asignarla a JPA es un poco doloroso :)
ams
6

Debe tener una columna de nombre como restricción única. Aquí hay 3 líneas de código para cambiar sus problemas

  1. Primero descubra las restricciones de la clave principal escribiendo este código

    \d table_name

    te muestran así en la parte inferior "some_constraint" PRIMARY KEY, btree (column)

  2. Descarte la restricción:

    ALTER TABLE table_name DROP CONSTRAINT some_constraint
  3. Agregue una nueva columna de clave principal con una existente:

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

Eso es todo.

Hari Bharathi
fuente