2011-02-23 23 views
5

me siguen dando:¿Por qué no puedo establecer esta restricción única en PostgreSQL?

SQL error: ERROR: could not create unique index "service_import_checksum_key" DETAIL: Key (checksum)=() is duplicated.

En declaración:

ALTER TABLE "public"."service_import" ADD CONSTRAINT "service_import_checksum_key" UNIQUE ("checksum")

Pero esta limitación no es un duplicado. No hay otra restricción como esta en ninguna parte de toda la base de datos y no tengo idea de por qué en la tierra insiste en que es un duplicado. Asumo que este es un extraño matiz de postgres que me falta aquí.

¿Qué estoy haciendo mal?

Mesa de Descarga:

-- 
-- PostgreSQL database dump 
-- 

SET statement_timeout = 0; 
SET client_encoding = 'UTF8'; 
SET standard_conforming_strings = off; 
SET check_function_bodies = false; 
SET client_min_messages = warning; 
SET escape_string_warning = off; 

SET search_path = public, pg_catalog; 

SET default_tablespace = ''; 

SET default_with_oids = false; 

-- 
-- Name: service_import; Type: TABLE; Schema: public; Owner: cvs_tar; Tablespace: 
-- 

CREATE TABLE service_import (
    id integer NOT NULL, 
    name character varying(32) NOT NULL, 
    importfile character varying(64) NOT NULL, 
    reportfile character varying(64) NOT NULL, 
    percent smallint NOT NULL, 
    message text NOT NULL, 
    stamp timestamp without time zone DEFAULT now() NOT NULL, 
    complete smallint DEFAULT 0 NOT NULL, 
    checksum character varying(40) NOT NULL 
); 


ALTER TABLE public.service_import OWNER TO cvs_tar; 

-- 
-- Name: service_imports_id_seq; Type: SEQUENCE; Schema: public; Owner: cvs_tar 
-- 

CREATE SEQUENCE service_imports_id_seq 
    START WITH 1 
    INCREMENT BY 1 
    NO MINVALUE 
    NO MAXVALUE 
    CACHE 1; 


ALTER TABLE public.service_imports_id_seq OWNER TO cvs_tar; 

-- 
-- Name: service_imports_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: cvs_tar 
-- 

ALTER SEQUENCE service_imports_id_seq OWNED BY service_import.id; 


-- 
-- Name: id; Type: DEFAULT; Schema: public; Owner: cvs_tar 
-- 

ALTER TABLE service_import ALTER COLUMN id SET DEFAULT nextval('service_imports_id_seq'::regclass); 


-- 
-- Name: service_import_name_key; Type: CONSTRAINT; Schema: public; Owner: cvs_tar; Tablespace: 
-- 

ALTER TABLE ONLY service_import 
    ADD CONSTRAINT service_import_name_key UNIQUE (name); 


-- 
-- Name: service_import_pkey; Type: CONSTRAINT; Schema: public; Owner: cvs_tar; Tablespace: 
-- 

ALTER TABLE ONLY service_import 
    ADD CONSTRAINT service_import_pkey PRIMARY KEY (id); 


-- 
-- Name: service_import_complete_idx; Type: INDEX; Schema: public; Owner: cvs_tar; Tablespace: 
-- 

CREATE INDEX service_import_complete_idx ON service_import USING btree (complete); 


-- 
-- Name: service_import_stamp_idx; Type: INDEX; Schema: public; Owner: cvs_tar; Tablespace: 
-- 

CREATE INDEX service_import_stamp_idx ON service_import USING btree (stamp); 


-- 
-- PostgreSQL database dump complete 
-- 
+0

¿Puede mostrarnos el completo 'CREATE TABLE', u ofrecer otra descripción de la tabla? Además, ¿funciona 'CREATE UNIQUE INDEX'? – Charles

Respuesta

14

Leer el mensaje de error:

SQL error: ERROR: could not create unique index "service_import_checksum_key" DETAIL: Key (checksum)=() is duplicated.

parece que le está diciendo que hay valores duplicados en la columna de la checksum y que está tratando de hacer cumplir la unicidad en esa columna con tu restricción. La restricción no está duplicada, los datos tienen duplicados.

Además, la parte "()" indica que tiene múltiples cadenas vacías en la columna checksum. Las restricciones exclusivas permiten valores múltiples NULL (ya que NULL = NULL es NULL que no es verdadero) pero las cadenas vacías no son NULL.

un ejemplo para aclarar lo que está pasando:

=> CREATE TABLE x (s VARCHAR NULL); 
CREATE TABLE 
=> INSERT INTO x (s) VALUES (''), ('a'), (''); 
INSERT 0 3 
=> ALTER TABLE x ADD CONSTRAINT ux UNIQUE(s); 
NOTICE: ALTER TABLE/ADD UNIQUE will create implicit index "ux" for table "x" 
ERROR: could not create unique index "ux" 
DETAIL: Key (s)=() is duplicated. 
=> delete from x where s=''; 
DELETE 2 
=> INSERT INTO x (s) VALUES ('a'); 
INSERT 0 1 
=> ALTER TABLE x ADD CONSTRAINT ux UNIQUE(s); 
NOTICE: ALTER TABLE/ADD UNIQUE will create implicit index "ux" for table "x" 
ERROR: could not create unique index "ux" 
DETAIL: Key (s)=(a) is duplicated. 

En particular, tenga en cuenta lo que el ERROR y DETALLE están diciendo y que para comparar los insertos.

+1

Este es un excelente ejemplo de la necesidad de una restricción de verificación adicional para evitar que los desarrolladores hagan trampa. El campo NO es NULO, pero es una cadena sin marcar, por lo que ponen la cadena vacía para eludir la restricción NOT NULL. Mi reino para agregar al estándar SQL un tipo de cadena que no permite el uso de cadenas "vacías" (de cualquier longitud). –

+1

@Matthew Wood: Usaría una restricción CHECK explícita para asegurarme de que la suma de verificación tenga exactamente la longitud deseada (ni más ni menos) y solo contenga caracteres válidos para la suma de comprobación; la suma de comprobación es probablemente un valor hexadecimal de tamaño fijo y los desarrolladores pueden rellenarlo si es necesario. Dejaremos toda la "cadena vacía es NULL porque! Empty_string es verdadero y mi ORM es demasiado tonto como para decir la diferencia" tonterías por otro día :) No soy DBA pero sé que '' y NULL son cosas diferentes incluso fuera de la base de datos. –

+0

En relación con: "Las restricciones exclusivas permiten valores NULL múltiples (dado que NULL = NULL es falso) pero las cadenas vacías no son NULL." DING! Dado en el clavo. Todo arreglado. Lo estúpido fue autocompletar en cadenas vacías cuando creé la columna y luego agregar el índice fue imposible. –

Cuestiones relacionadas