2017-02-12 4 views
3

Nach vielen meiner Frage googeln ist unten beschrieben:PostgreSQL Teil Indizes und UPSERT

CREATE TABLE security (
    id   SERIAL PRIMARY KEY, 
    vendor  VARCHAR(20), 
    external_id VARCHAR(20), 
    extinct  BOOLEAN DEFAULT FALSE 
); 

CREATE UNIQUE INDEX unique_vendor ON security(vendor, extinct) where vendor is not null; 
CREATE UNIQUE INDEX unique_external_id ON security(external_id, extinct) where external_id is not null; 

Der Versuch, Werte einzufügen:

insert into security (vendor, external_id, extinct) 
    values('Legion', 'LGNONE', false) 
    ON CONFLICT(vendor, external_id, extinct) DO UPDATE 
    SET vendor = 'Legion', external_id = 'LGNONE', extinct = false; 

Ergebnisse in:

[42P10] ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification 

Altho dieser Werke (pro Spezifikation):

insert into security (vendor, external_id, extinct) 
    values('Legion', 'LGNONE', false) 
    ON CONFLICT DO NOTHING; 

PostgreSQL documentation stands that it should work

PostgreSQL v9.5

Mein Ziel ist es Weg zu finden, eindeutigen Index für mehrere Spalten auf NULL festlegbare auf diese Tabelle zu erstellen und alte Zeilen mit neuen auf UPSERT

Antwort

6

Die conflict_target verwendete aktualisieren in on conflict muss einen vorhandenen eindeutigen Index identifizieren. Sie können nicht

on conflict (vendor, external_id, extinct) 

verwenden, weil Sie keinen Index für die drei Spalten haben. Postgres ist nicht so schlau, mehrere Indizes zu kombinieren, um Ihr Konfliktziel zu erfüllen.

Sie können jedoch einen einzelnen Teilindex wie diese erstellen:

create unique index unique_vendor_external_id 
    on security(vendor, external_id, extinct) 
    where coalesce(vendor, external_id) is not null; 

Jetzt können Sie die drei Spalten als Konflikt Ziel verwenden:

insert into security (vendor, external_id, extinct) 
    values('Legion', 'LGNONE', false) 
on conflict (vendor, external_id, extinct)   -- exact match to the index definition 
    where coalesce(vendor, external_id) is not null -- obligatory index_predicate 
do update set 
    vendor = excluded.vendor, 
    external_id = excluded.external_id, 
    extinct = excluded.extinct 

Beachten Sie die Verwendung des speziellen Rekord excluded . Für die Dokumentation:

Die SET und WHERE-Klauseln in ON CONFLICT aktualisiere haben Zugriff auf die vorhandene Zeile der Tabelle des Namen (oder einen Alias), und zu den Reihen für die Insertion vorgeschlagen, die spezielle ausgeschlossen Tabelle.

+0

Das ist brilliant Vorschlag und Antwort! Vielen Dank! – cingulata

Verwandte Themen