Domanda

Vedi importanti nuove scoperte 1 e 2 alla fine di questa spiegazione.

Sto eseguendo postgres 9.1.3 e sto avendo un problema di join sinistro strano.

Ho un tavolo denominato Coent.master con oltre 2 milioni di righe. Ha una colonna denominata Citation_id , e quella colonna non ha null. Posso verificarlo con questo:

SELECT COUNT(*)
FROM consistent.master
WHERE citation_id IS NULL
.

che restituisce 0 .

Ecco dove diventa strano: se i sinistra join questa tabella a una tabella temporanea, ottengo un errore che sto cercando di inserire un NULL nel campo Citation_id :

Errore: valore nullo nella colonna "Citation_id" viola il vincolo non-null Stato SQL: 23502

Ecco la query:

WITH stops AS (
    SELECT citation_id,
           rank() OVER (ORDER BY offense_timestamp,
                     defendant_dl,
                     offense_street_number,
                     offense_street_name) AS stop
    FROM   consistent.master
    WHERE  citing_jurisdiction=1
)

INSERT INTO consistent.masternew (arrest_id, citation_id, defendant_dl, defendant_dl_state, defendant_zip, defendant_race, defendant_sex, defendant_dob, vehicle_licenseplate, vehicle_licenseplate_state, vehicle_registration_expiration_date, vehicle_year, vehicle_make, vehicle_model, vehicle_color, offense_timestamp, offense_street_number, offense_street_name, offense_crossstreet_number, offense_crossstreet_name, offense_county, officer_id, offense_code, speed_alleged, speed_limit, work_zone, school_zone, offense_location, id, source, citing_jurisdiction, the_geom)

SELECT stops.stop, master.citation_id, defendant_dl, defendant_dl_state, defendant_zip, defendant_race, defendant_sex, defendant_dob, vehicle_licenseplate, vehicle_licenseplate_state, vehicle_registration_expiration_date, vehicle_year, vehicle_make, vehicle_model, vehicle_color, offense_timestamp, offense_street_number, offense_street_name, offense_crossstreet_number, offense_crossstreet_name, offense_county, officer_id, offense_code, speed_alleged, speed_limit, work_zone, school_zone, offense_location, id, source, citing_jurisdiction, the_geom
FROM consistent.master LEFT JOIN stops
ON stops.citation_id = master.citation_id
.

Mi sto grattando la testa su questo. Se questo è un Sinistra Join , e se Coent.master è la tabella sinistra del join, come potrebbe questa query creare valori null nella colonna citation_id Quando non ci sono da cominciare?

Ecco il codice SQL che ho usato per creare la tabella:

CREATE TABLE consistent.masternew
(
  arrest_id character varying(20),
  citation_id character varying(20) NOT NULL,
  defendant_dl character varying(20),
  defendant_dl_state character varying(2),
  defendant_zip character varying(9),
  defendant_race character varying(10),
  defendant_sex character(1),
  defendant_dob date,
  vehicle_licenseplate character varying(10),
  vehicle_licenseplate_state character(2),
  vehicle_registration_expiration_date date,
  vehicle_year integer,
  vehicle_make character varying(20),
  vehicle_model character varying(20),
  vehicle_color character varying,
  offense_timestamp timestamp without time zone,
  offense_street_number character varying(10),
  offense_street_name character varying(30),
  offense_crossstreet_number character varying(10),
  offense_crossstreet_name character varying(30),
  offense_county character varying(10),
  officer_id character varying(20),
  offense_code integer,
  speed_alleged integer,
  speed_limit integer,
  work_zone bit(1),
  school_zone bit(1),
  offense_location point,
  id serial NOT NULL,
  source character varying(20), -- Where this citation came from--court, PD, etc.
  citing_jurisdiction integer,
  the_geom geometry,
  CONSTRAINT masternew_pkey PRIMARY KEY (id ),
  CONSTRAINT citing_jurisdiction FOREIGN KEY (citing_jurisdiction)
      REFERENCES consistent.jurisdictions (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT offenses FOREIGN KEY (offense_code)
      REFERENCES consistent.offenses (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT enforce_dims_the_geom CHECK (st_ndims(the_geom) = 2),
  CONSTRAINT enforce_geotype_the_geom CHECK (geometrytype(the_geom) = 'POINT'::text OR the_geom IS NULL),
  CONSTRAINT enforce_srid_the_geom CHECK (st_srid(the_geom) = 3081)
)
WITH (
  OIDS=FALSE
);
ALTER TABLE consistent.masternew
  OWNER TO postgres;
COMMENT ON COLUMN consistent.masternew.source IS 'Where this citation came from--court, PD, etc.';

CREATE INDEX masternew_citation_id_idx
  ON consistent.masternew
  USING btree
  (citation_id COLLATE pg_catalog."default" );

CREATE INDEX masternew_citing_jurisdiction_idx
  ON consistent.masternew
  USING btree
  (citing_jurisdiction );

CREATE INDEX masternew_defendant_dl_idx
  ON consistent.masternew
  USING btree
  (defendant_dl COLLATE pg_catalog."default" );

CREATE INDEX masternew_id_idx
  ON consistent.masternew
  USING btree
  (id );

CREATE INDEX masternew_offense_street_name_idx
  ON consistent.masternew
  USING btree
  (offense_street_name COLLATE pg_catalog."default" );

CREATE INDEX masternew_offense_street_number_idx
  ON consistent.masternew
  USING btree
  (offense_street_number COLLATE pg_catalog."default" );

CREATE INDEX masternew_offense_timestamp_idx
  ON consistent.masternew
  USING btree
  (offense_timestamp );

CREATE INDEX masternew_the_geom_idx
  ON consistent.masternew
  USING gist
  (the_geom );
.

Importante Discovery 1

Ho appena scoperto qualcosa di interessante. Questa query:

SELECT COUNT(*)
FROM consistent.master
WHERE citation_id IS NOT NULL
UNION
SELECT COUNT(*)
FROM consistent.master
UNION
SELECT COUNT(*)
FROM consistent.master
WHERE citation_id IS NULL
.

I risultati sono:

2085344
2085343
0
.

Come posso spiegarlo? Come può il conteggio con WHERE citation_id IS NOT NULL possibilmente essere più alto della stessa query senza clausola WHERE?

Importante Discovery 2 OK, per i commenti qui sotto, ho scoperto che ho una riga con tutti i valori vuoti, e questo è nonostante il fatto che la tabella ha una colonna id seriale e alcuni limiti NOT NULL.

Ho cancellato la riga del bum. Ora non sto ottenendo l'errore null. Invece, sto ottenendo questo:

ERROR:  duplicate key value violates unique constraint "masternew_pkey"
DETAIL:  Key (id)=(1583804) already exists.

********** Error **********

ERROR: duplicate key value violates unique constraint "masternew_pkey"
SQL state: 23505
Detail: Key (id)=(1583804) already exists.
.

Quindi solo per essere sicuro, faccio questa query:

SELECT COUNT(id)
FROM consistent.master
WHERE id=1583804;
.

Indovina cosa? consistent.master ha solo 1 istanza di questo! Quindi, dato che la tavola sinistra nel LEFT JOIN solo 1 istanza di 1583804 in citation_id e che la colonna ID può provenire solo dalla tabella sinistra, Come potrebbe accadere questo errore? Un LEFT JOIN come questo non dovrebbe causare il risultato finale di avere più righe rispetto al tavolo a sinistra, giusto?

È stato utile?

Soluzione

Con un inserto, specialmente con uno complesso, dovresti Definire sempre le colonne di destinazione . Quindi fai questo:

INSERT INTO consistent.masternew (citation_id, col1, col2, ...)
.

Se qualcosa va storto nell'istruzione Select Accompagnamento, come questa:

the_geom geometry
.

(non ha senso rinominare la colonna con un nome di tipo - Suppongo che ciò non sia intenzionale) - o se la definizione della tabella sottostante cambia, un'istruzione Inserisci senza colonne target definite può andare terribilmente sbagliato.

PostgreSQL non impone lo stesso numero di colonne nell'istruzione SELECT come nella tabella di destinazione. Quote Il manuale fine su quello :

.

Ogni colonna non presente nell'elenco di colonna esplicito o implicito lo farà essere riempito con un valore predefinito, sia il valore predefinito dichiarato o null se non c'è nessuno .

(Bold enfasi Miniera.) Se si dispone di una mancata corrispondenza nell'elenco delle colonne, questo potrebbe rendere un valore nullo come "fuori da nessuna parte".

Inoltre, l'ordine delle colonne nell'istruzione Seleziona è necessario corrispondere all'ordine delle colonne da inserire. Se le colonne di destinazione non sono scritte, questo sarebbe l'ordine delle colonne nella tua tabella come è stata creata.
Sembri aspettarti che le colonne siano abbinate al nome automaticamente, ma non è così. I nomi delle colonne nell'istruzione SELECT sono completamente irrilevanti per il gradino finale dell'inserto. Solo il loro ordine da sinistra a destra è significativo.

Contrariamente a ciò che gli altri hanno implicito la con la clausola è perfettamente legittimabile . Quote Il manuale su insert :

.

è possibile per la query (istruzioni selezionate) per contenere anche a con clausola. In tal caso, entrambi i set di with_query possono essere referenziati all'interno della query, ma il secondo richiede la precedenza poiché è di più strettamente annidato.

La tua dichiarazione potrebbe sembrare così:

WITH stops AS (
    SELECT citation_id
          ,rank() OVER (ORDER BY
                    offense_timestamp
                   ,defendant_dl
                   ,offense_street_number
                   ,offense_street_name) AS stop
    FROM   consistent.master
    WHERE  citing_jurisdiction = 1
    )
INSERT INTO consistent.masternew (citation_id, col1, col2, ...) -- add columns
SELECT m.citation_id -- order colums accordingly!
      ,s.stop
      ,m.defendant_dl
        -- 27 more columns
      ,m.citing_jurisdiction
      ,m.the_geom
FROM   consistent.master m
LEFT   JOIN stops s USING (citation_id);
.

Altri suggerimenti

Ai suoi indovinai direi che stai inserendo fermate. Sostoppo, che potrebbe essere nullo, nella colonna citation_id, ma senza conoscere la struttura del tavolo che non posso dire per certo :)

Modifica: prova @ suggerimento di Vol7ron e nominare le colonne ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top