2

この説明の最後にある重要な新発見 1 と 2 を参照してください。

Postgres 9.1.3 を実行していますが、奇妙な左結合の問題が発生しています。

200 万行を超える、consistent.masterという名前のテーブルがあります。citation_idという名前の列があり、その列には null がありません。これで確認できます:

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

それは0を返します。

ここで奇妙なことがあります: このテーブルを一時テーブルにLEFT JOIN すると、 citation_idフィールドに null を挿入しようとしているというエラーが表示されます。

エラー: 列 "citation_id" の null 値が not-null 制約に違反しています SQL 状態: 23502

クエリは次のとおりです。

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

私はこれに頭を悩ませています。これがLEFT JOINで、consistent.masterが結合の左側のテーブルである場合、そもそも何もないのに、このクエリでcitation_id列にnull 値を作成するにはどうすればよいでしょうか?

テーブルの作成に使用した SQL コードは次のとおりです。

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

重要な発見 1

面白いことを発見しました。このクエリ:

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

結果は次のとおりです。

2085344
2085343
0

どうすればそれを説明できますか?句WHERE citation_id IS NOT NULLのない同じクエリよりもカウントが高くなる可能性があるのはなぜですか?WHERE

IMPORTANT DISCOVERY 2 OK、以下のコメントに従って、すべて空の値を持つ行があることを発見しました。これは、テーブルにシリアル列といくつかの制約があるにもかかわらずです。idNOT NULL

お尻の行を削除しました。現在、null エラーは発生していません。代わりに、私はこれを得ています:

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.

念のため、次のクエリを実行します。

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

何だと思う?consistent.masterこれは 1 つのインスタンスしかありません。1583804LEFT JOIN唯一の 1 つのインスタンスの左側のテーブルと、左側のテーブルからのみid列を取得できることを考えると、このエラーはどのように発生するのでしょうか? このようなことで、最終結果に左のテーブルよりも多くの行が含まれるようになるべきではありませんよね?citation_id LEFT JOIN

4

2 に答える 2

3

INSERT を使用する場合、特に複雑な INSERT を使用する場合は、常にターゲット列を定義する必要があります。だからそれを作る:

INSERT INTO 一貫性のある.masternew (citation_id、col1、col2、...)

付随する SELECT ステートメントで何か問題が発生した場合 - 次のように:

the_geom geometry

(列の名前を型名で変更しても意味がありません-これは意図的ではないと思います)-または、基になるテーブル定義が変更された場合、ターゲット列が定義されていない INSERT ステートメントはひどく間違っている可能性があります。

PostgreSQL は、ターゲット テーブルにあるものと同じ数の列を SELECT ステートメントに強制しません。その上で素晴らしいマニュアルを引用します:

明示的または暗黙的な列リストに存在しない各列には、宣言されたデフォルト値または存在しない場合は nullのいずれかのデフォルト値が入力されます。

(太字は私のものです。) 列リストに不一致がある場合、これにより NULL 値が「どこからともなく」表示される可能性があります。

また、 SELECT ステートメント内のの順序は、挿入先の列の順序と一致する必要があります。対象の列が綴られていない場合、これはテーブルが作成されたときの列の順序になります。
列は自動的に名前で照合されることを期待しているようですが、そうではありません。SELECT ステートメントの列名は、INSERT の最終ステップにはまったく関係ありません。左から右への順序のみが重要です。

他の人が暗示していることとは反対に、WITH 句は完全に合法です。INSERT のマニュアルを引用します。

クエリ (SELECT ステートメント) に WITH 句を含めることもできます。このような場合、with_query の両方のセットをクエリ内で参照できますが、2 番目のほうがより密接にネストされているため、優先されます。

ステートメントは次のようになります。

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);
于 2012-03-15T04:36:48.523 に答える
2

推測では、ヌルの可能性があるstops.stopをcitation_id列に挿入していると思いますが、テーブル構造を知らなければ、確かなことは言えません:)

編集:@ vol7ronの提案を試して、列に名前を付けてください...

于 2012-03-15T03:27:42.523 に答える