PostgreSQL:左結合は空白行を作成します
-
14-12-2019 - |
質問
この説明の終わりに重要な新しい発見1と2を参照してください。
私はPostgres 9.1.3を実行していて、奇妙な残りの結合問題を持っています。
私は200万の行を超える conssisent.master という名前のテーブルを持っています。 cittion_id という名前の列を持ち、その列にはNULLがありません。これで確認できます。
SELECT COUNT(*)
FROM consistent.master
WHERE citation_id IS NULL
.
0 を返します。
これはそれが変わったところです。 :
error: "cittion_id"のnull値 "ctitution_id"はnull constraintに違反します 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
.
これは私の頭をこのものに傷つけます。これが左結合の場合、 conssisent.master が結合の左のテーブルである場合、このクエリは catute_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
を使用したCOUNTは、WHERE
句のない同じクエリよりも大きくなる可能性がありますか?
重要発見2 [OK]、以下のコメントごとに、私はすべての空の値を持つ行があることを発見しました、そしてこれはに依存しています。
バム行を削除しました。今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;
.
何を推測しますか? id
には1つのインスタンスがあります。そのため、NOT NULL
およびの 1583804 の 1583804 の左のテーブルは、左のテーブルからのみ来ることができます。この誤りがどうやって起こる可能性がありますか?このようなconsistent.master
は、最終結果を左のテーブルよりも多くの行を右にすることを右にすることはありません。
解決
特に複雑なものでは、常にターゲット列を定義する必要があります。だからそれを作ります:
INSERT INTO consistent.masternew (citation_id, col1, col2, ...).
付随するSELECT文に何が悪い場合は、次のようにします。
the_geom geometry
.
(タイプ名を指定して列の名前を変更することは意味がありません。
PostgreSQLは、ターゲットテーブルのようにSELECTステートメント内の同じ数の列を強制しません。 その
:明示的または暗黙的な列リストに存在しない各列は 宣言されたデフォルト値またはその宣言されたデフォルト値で埋められます。 がない場合はnull。
(太字の強調鉱山。)列リストに不一致がある場合、これはNULL値が「どこにもない」と表示される可能性があります。
また、SELECT文のの順序は、挿入する列の順序と一致する必要があります。ターゲット列がスペルアウトされていない場合、これはそれが作成されたときにテーブル内の列の順序になります。
列が自動的に名前で一致していることを期待しているようですが、そうではありません。 SELECTステートメント内の列名は、挿入の最後のステップには完全に無関係です。左から右への彼らの順序だけが重要です。
他の人がを黙示したものとは反対に、節が完全に合法的なです。 マニュアル:
クエリ(SELECTステートメント)にも付いていることが可能です。 句。そのような場合、両方のセットの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);
. 他のヒント
あなたが停止していることがunull、city_id列に挿入することができるが、テーブル構造を知らずに私が確かに言うことができずに:)
編集:@ vol7ronの提案と列に名前を付けてみてください...