Arreglando la estructura de la tabla para evitar `Error: el valor clave duplicado viola la restricción única`


15

Tengo una tabla que se crea de esta manera:

--
-- Table: #__content
--
CREATE TABLE "jos_content" (
  "id" serial NOT NULL,
  "asset_id" bigint DEFAULT 0 NOT NULL,
   ...
  "xreference" varchar(50) DEFAULT '' NOT NULL,
  PRIMARY KEY ("id")
);

Más tarde se insertan algunas filas especificando la identificación:

INSERT INTO "jos_content" VALUES (1,36,'About',...)

En un momento posterior se insertan algunos registros sin identificación y con el error: Error: duplicate key value violates unique constraint.

Aparentemente, la identificación se definió como una secuencia:

ingrese la descripción de la imagen aquí

Cada inserción fallida aumenta el puntero en la secuencia hasta que se incrementa a un valor que ya no existe y las consultas tienen éxito.

SELECT nextval('jos_content_id_seq'::regclass)

¿Qué hay de malo con la definición de la tabla? ¿Cuál es la forma inteligente de solucionar esto?


En PostgreSQL, no necesita citar columnas y nombres de tablas si todos están en minúsculas.
Rodrigo

Respuestas:


19

No hay nada malo con la definición de su tabla.
(Excepto el sombrero que usaría jos_content_ido algo así en lugar del nombre de columna no descriptivo id.
Y probablemente usaría en textlugar devarchar(50) .

Tu INSERTdeclaración es el problema.

Con su idcolumna definida como serial, no debe insertar valores manuales para id. Esos pueden colisionar con el siguiente valor de la secuencia asociada.

Proporcione una lista explícita de columnas de destino (que casi siempre es una buena idea para INSERTdeclaraciones persistentes ) y omita por completo las columnas en serie .

INSERT INTO jos_content(asset_id, some_column, ...)
VALUES (36,'About',...);

Si necesita los valores de las columnas generadas automáticamente de inmediato, use la RETURNINGcláusula :

INSERT ...
RETURNING id;  -- possibly more

Más detalles en esta respuesta relacionada sobre SO:

Si tiene entradas manuales en serialcolumnas que pueden entrar en conflicto más adelante, configure su secuencia al máximo actual idpara solucionar esto una vez :

SELECT setval('jos_content_id_seq', max(id))
FROM   jos_content;

¿Dónde jos_content_id_seqestá el nombre predeterminado para una secuencia propiedad de jos_content.id, que ya se encuentra en la columna predeterminada? Parece estar xhzt8_content_id_seqen su caso;


Actualización: surgió un problema similar en SO y se me ocurrió una nueva solución:


¿El texto no es más lento que varchar (50)?
Rodrigo

2
@ Rodrigo: No en Postgres. Hay un enlace arriba para obtener más explicaciones: dba.stackexchange.com/a/21496/3684 . O aquí. dba.stackexchange.com/a/89433/3684
Erwin Brandstetter

La última prueba aquí < depesz.com/2010/03/02/charx-vs-varcharx-vs-varchar-vs-text > me convenció de que varchar (n) es más rápido para la mayoría de los campos donde es conveniente una restricción de tamaño (personas nombres, correos electrónicos, direcciones, nombres de especies, etc.). El texto es más rápido (o lo mismo) si parece que no verificará la longitud.
Rodrigo
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.