Consider the following SQL:
CREATE TABLE external_item (
id SERIAL PRIMARY KEY,
external_id TEXT UNIQUE,
enabled BOOLEAN NOT NULL CHECK (enabled = false OR external_id IS NOT NULL)
);
INSERT INTO external_item (id, enabled, external_id)
VALUES (1, true, 'ext_id_1');
INSERT INTO external_item (id, enabled)
VALUES (1, true)
ON CONFLICT (id)
DO UPDATE
SET enabled = excluded.enabled;
--> ERROR: new row for relation "external_item" violates check constraint "external_item_check"
--> DETAIL: Failing row contains (1, null, t).
The query fails because it the insert doesn't pass the check constraint. Everything works fine if you omit the CHECK from the table definition. Is there some way to set constraint priority or something so that Postgres would resort to the ON CONFLICT DO UPDATE statement before asserting other checks?
Im doing a bulk insert to PostgreSQL using PG_Admin tools, the table field anamnesa_id contain ForeignKey relation to other table pasien_anamnesa,
Is there a way to ignore or skip (which is not exist in other table) the error while inserting all the query? because deleting the error query 1 by 1 is just impossible for this many data (25.000 records),
i've trying:
INSERT INTO "pasien_item" ("id", "anamnesa_id") VALUES (1, 2) ON CONFLICT ON CONSTRAINT pasien_item_pkey DO NOTHING;
resulting error:
ERROR: insert or update on table "pasien_item" violates foreign key constraint "pasien_item_anamnesa_id_dc66b31b_fk_pasien_anamnesa_id"
DETAIL: Key (anamnesa_id)=(2) is not present in table "pasien_anamnesa".
SQL state: 23503
from that error i also tried:
INSERT INTO "pasien_item" ("id", "anamnesa_id") VALUES (1, 2) ON CONFLICT ON CONSTRAINT pasien_item_anamnesa_id_dc66b31b_fk_pasien_anamnesa_id DO NOTHING;
resulting error:
ERROR: constraint in ON CONFLICT clause has no associated index
SQL state: 42809
ON CONFLICT can only deal with unique constraints, not foreign key or check constraints.
You need to rewrite your query to use a SELECT that only returns the rows where the foreign keys exist:
INSERT INTO pasien_item(id, anamnesa_id)
select v.id, v.anamnesa_id
from (
VALUES (1, 2), ...
) v(id, anamnesa_id)
WHERE EXISTS (select *
from pasien_anamnesa pa
where pa.anamnesa_id = v.anamnesa_id)
ON CONFLICT ON CONSTRAINT pasien_item_pkey DO NOTHING;
Online example
I have a PostgeresDB with the following constraint:
CONSTRAINT "Car_Data_3PM_pkey" PRIMARY KEY ("F_ID", "Date"),
CONSTRAINT "Car_Data_3PM_F_ID_fkey" FOREIGN KEY ("F_ID")
REFERENCES "Bike_Data" ("F_ID") MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
When I try to insert multiple values using:
INSERT INTO "Car_Data_3PM" ("F_ID","Date","Price_Type","O","H","L","LT","EQ","V","NAD") VALUES (38,'2016-10-02 08:19:40.056679','x',0,0,0,112.145,0,0,112.145),(14,'2016-10-02 08:19:40.056679','x',0,0,0,5476,0,0,5476),(13,'2016-10-02
I get this error:
ERROR: insert or update on table "Car_Data_3PM" violates foreign key
constraint "Car_Data_3PM_F_ID_fkey" SQL state: 23503 Detail: Key
(F_ID)=(38) is not present in table "Bike_Data".
NO ROWS are inserted.
How can I make Postgres ONLY miss out the rows where the constraint is an issue? i.e Insert most of them?
You can't make Postgres ignore the values, but you can rewrite your statement to not insert those rows:
INSERT INTO "Car_Data_3PM" ("F_ID","Date","Price_Type","O","H","L","LT","EQ","V","NAD")
select *
from (
VALUES
(38,'2016-10-02 08:19:40.056679','x',0,0,0,112.145,0,0,112.145),
(14,'2016-10-02 08:19:40.056679','x',0,0,0,5476,0,0,5476),
... -- all other rows
) as x (id, date, price_type, o, h, l, lt, eq, v nad)
where exists (select 1
from "Bike_Data" bd
where bd."F_ID" = x .id)
One way is to write a trigger that filters out the bad values, like this:
CREATE FUNCTION car_insert_filter() RETURNS trigger
LANGUAGE plpgsql AS
$$BEGIN
IF EXISTS(SELECT 1 FROM "Bike_Data" WHERE "F_ID" = NEW."F_ID")
THEN
RETURN NEW;
ELSE
RAISE NOTICE 'Skipping row with "F_ID"=% and "Date"=%',
NEW."F_ID", NEW."Date";
RETURN NULL;
END IF;
END;$$;
CREATE TRIGGER car_insert_filter
BEFORE INSERT ON "Car_Data_3PM" FOR EACH ROW
EXECUTE PROCEDURE car_insert_filter();
Consider the following two tables:
CREATE TABLE public.parent
(
id bigint NOT NULL DEFAULT nextval('parent_id_seq'::regclass),
CONSTRAINT pk_parent PRIMARY KEY (id)
);
CREATE TABLE public.child
(
child_id bigint NOT NULL DEFAULT nextval('child_child_id_seq'::regclass),
parent_id bigint NOT NULL,
CONSTRAINT pk_child PRIMARY KEY (child_id),
CONSTRAINT inx_parent FOREIGN KEY (parent_id)
REFERENCES public.parent (id) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE INDEX fki_child
ON public.child
USING btree
(parent_id);
CREATE TRIGGER child_trg
BEFORE DELETE
ON public.child
FOR EACH ROW
EXECUTE PROCEDURE public.trg();
And the trg is defined as:
CREATE OR REPLACE FUNCTION public.trg()
RETURNS trigger AS
$BODY$BEGIN
INSERT INTO temp
SELECT p.id
FROM parent p
WHERE
p.id = OLD.parent_id;
return OLD;
END;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
To sum up what is happening, there're two tables with a simple parent-child relationship and a cascade on it. There's also a trigger defined on child listening to deletion. I need to access parent's data, in the trigger, when the child's records are deleted due to cascade on parent-child relation. But I can not since they are already deleted! Does anyone have any idea how?
One solution would be to create a BEFORE DELETE trigger on parent instead, which can see all data.
CREATE OR REPLACE FUNCTION public.trg_parent()
RETURNS trigger AS
$func$
BEGIN
INSERT INTO some_tbl (id) -- use target list !!
VALUES (OLD.parent_id);
RETURN OLD;
END
$func$ LANGUAGE plpgsql;
CREATE TRIGGER parent_trg
BEFORE DELETE ON public.parent
FOR EACH ROW EXECUTE PROCEDURE public.trg_parent();
I'm considering employing triggers for maintaining linking table. However my initial approach fails due to foreign key constraint violation. Is there any way to solve the issue without disabling constraints?
CREATE TABLE foo (
id SERIAL PRIMARY KEY,
data TEXT
);
CREATE TABLE bar (
id SERIAL PRIMARY KEY,
data TEXT
);
CREATE TABLE foo_bar_link (
foo_id INT NOT NULL REFERENCES foo(id),
bar_id INT NOT NULL REFERENCES bar(id),
UNIQUE (foo_id, bar_id)
);
CREATE OR REPLACE FUNCTION maintain_link()
RETURNS TRIGGER AS
$maintain_link$
DECLARE
bar_id INT;
BEGIN
INSERT INTO bar (data) VALUES ('not_important_for_this_example_bar_data') RETURNING id INTO bar_id;
INSERT INTO foo_bar_link (foo_id, bar_id) VALUES (NEW.id, bar_id);
RETURN NEW;
END;
$maintain_link$
LANGUAGE plpgsql;
CREATE TRIGGER maintain_link BEFORE INSERT ON foo
FOR EACH ROW EXECUTE PROCEDURE maintain_link();
Here is sqlfiddle.
Use AFTER insert, since using BEFORE insert fails because your parent row in foo doesn't exist yet.