2016-11-16 4 views
3

Ich muss Aktualisierung (über ON CONFLICT()) Zeile in einer partitionierten Tabellen erreichen.
Bisher meine Versuche:
Tabellenerstellung:PostgreSQL 9.5 Einfügen/Aktualisieren während der Partitionierung Tabelle

CREATE TABLE public.my_tbl 
(
    goid character varying(255) NOT NULL, 
    timestamps timestamp without time zone[], 
    somenumber numeric[], 
    CONSTRAINT my_tbl_pkey PRIMARY KEY (goid) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE public.my_tbl 
    OWNER TO postgres; 

Tabelle Sequenz:

CREATE SEQUENCE public.fixations_data_pkey_seq 
    INCREMENT 1 
    MINVALUE 1 
    MAXVALUE 9223372036854775807 
    START 1 
    CACHE 1; 
ALTER TABLE public.fixations_data_pkey_seq 
    OWNER TO postgres; 

Tabelle Partition Trigger, die mit dem Namen "table_YYYY_MM_DD" neue Tabelle erstellt, wobei "YYYY_MM_DD" - Strom Datum (Abfrage Ausführungsdatum):

CREATE OR REPLACE FUNCTION public.my_tbl_insert_trigger() 
    RETURNS trigger AS 
$BODY$ 
DECLARE 
    table_master varchar(255)  := 'my_tbl'; 
    table_part  varchar(255)  := '';  
BEGIN 
    -- Partition table name -------------------------------------------------- 
    table_part := table_master 
        || '_' || DATE_PART('year', NOW())::TEXT 
        || '_' || DATE_PART('month', NOW())::TEXT 
        || '_' || DATE_PART('day', NOW())::TEXT; 

    -- Check if partition exists -------------------------------- 
    PERFORM 
     1 
    FROM 
     pg_class 
    WHERE 
     relname = table_part 
    LIMIT 
     1; 

    -- If not exist, create new one -------------------------------------------- 
    IF NOT FOUND 
    THEN 
     -- Create parition, which inherits master table -------------------------- 
    EXECUTE ' 
     CREATE TABLE ' || table_part || ' 
     (
     goid character varying(255) NOT NULL DEFAULT nextval(''' || table_master || '_pkey_seq''::regclass), 
     CONSTRAINT ' || table_part || '_pkey PRIMARY KEY (goid) 
     ) 
     INHERITS (' || table_master || ') 
     WITH (OIDS=FALSE)'; 

     -- Create indices for current table------------------------------- 
     EXECUTE ' 
      CREATE INDEX ' || table_part || '_adid_date_index 
      ON ' || table_part || ' 
      USING btree 
      (goid)'; 
    END IF; 

    -- Insert row into table (without ON CONFLICT)-------------------------------------------- 
    EXECUTE ' 
     INSERT INTO ' || table_part || ' 
     SELECT ((' || QUOTE_LITERAL(NEW) || ')::' || TG_RELNAME || ').*'; 

    RETURN NULL; 
END; 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 
ALTER FUNCTION public.my_tbl_insert_trigger() 
    OWNER TO postgres; 

CREATE TRIGGER my_tbl_insert_trigger 
    BEFORE INSERT 
    ON my_tbl 
    FOR EACH ROW 
    EXECUTE PROCEDURE my_tbl_insert_trigger(); 

Danach kann ich neue Zeilen in die Tabelle einfügen :

INSERT INTO my_tbl (goid, timestamps, somenumber) 
VALUES ('qwe123SSsssa3', '{"2016-11-16 00:00:00", "2016-11-16 01:00:00"}', '{3, 12333}') 

Aber wenn ich versuche, UPSERT zu tun:

INSERT INTO my_tbl (goid, timestamps, somenumber) 
VALUES ('qwe123SSsssa3', '{"2016-11-16 02:00:00"}', '{999}') 
ON CONFLICT (goid) 
DO UPDATE 
SET timestamps=array_append(my_tbl.timestamps::timestamp[], '2016-11-16 02:00:00'), 
somenumber=array_append(my_tbl.somenumber,'999'); 

Ich bin geting DUPLICATE PKEY Fehler.
Ich denke, dass ich ON CONFLICT zur dritten EXECUTE in Trigger-Funktion hinzufügen muss. Aber wie soll ich das machen?

Antwort

1

Nun, ich habe meine dritte geändert EXECUTE:

-- Insert row into table (with ON CONFLICT)-------------------------------------------- 
EXECUTE ' 
INSERT INTO ' || table_part || ' 
SELECT ((' || QUOTE_LITERAL(NEW) || ')::' || TG_RELNAME || ').* 
ON CONFLICT (goid) 
DO UPDATE 
SET timestamps=' || table_part || '.timestamps::timestamp[] || ' || QUOTE_LITERAL(NEW.timestamps) || ', 
somenumber=' || table_part || '.somenumber::numeric[] || ' || QUOTE_LITERAL(NEW.somenumber) || ' 
'; 

RETURN NULL; 

Nun, wenn ich Abfrage ausführen:

INSERT INTO my_tbl (goid, timestamps, somenumber) 
VALUES ('potato_1', ARRAY['2016-11-16 12:00:00', '2016-11-16 15:00:00']::timestamp[], ARRAY[223, 211]::numeric[]); 

gibt es keine Fehler, und es erstreckt sich vom Array-Typ-Spalten als Ich erwartete
Ich kann zugeben, dass dies eine schmutzige Lösung ist, aber es scheint, dass es funktioniert.
Wenn jemand eine bessere Lösung hat, werde ich mich freuen, es zu betrachten.

Verwandte Themen