Ei, estou tentando inserir ou atualizar (se as restrições estiverem duplicadas) com base em um resultado da consulta, estas são a instrução create table:
CREATE TABLE IF NOT EXISTS public.inventory (
inventory_id serial PRIMARY KEY,
arrive_date date NOT NULL,
arrive_location character varying NOT NULL,
thing_type integer NOT NULL,
quantity integer NOT NULL
);
CREATE TABLE IF NOT EXISTS public.preprocess_things (
preprocess_id serial PRIMARY KEY,
arrive_date date NOT NULL,
arrive_location character varying NOT NULL,
data jsonb NOT NULL,
CONSTRAINT preprocess_things_arrive_date_arrive_location_bo_key UNIQUE (arrive_date, arrive_location)
);
Esta é a consulta upsert:
WITH result_query AS (
SELECT DATE_TRUNC('day', arrive_date) AS date,
arrive_date,
arrive_location,
thing_type,
SUM(quantity) AS total_things
FROM inventory
GROUP BY date, arrive_location, thing_type
)
INSERT INTO preprocess_things (
arrive_date,
arrive_location,
data
)
SELECT r.date AS arrive_date,
r.arrive_location,
jsonb_build_object(r.thing_type, r.total_things)
FROM result_query r
ON CONFLICT (arrive_date, arrive_location) DO
UPDATE SET data = preprocess_things.data || EXCLUDED.data
As linhas result_query são:
date | arrive_location | thing_type | thing_count
2018-05-30 00:00:00-00 | location_00 | 3 | 2
2018-05-31 00:00:00-00 | location_00 | 3 | 8
2018-05-31 00:00:00-00 | location_00 | 4 | 7
Tentando inserir em preprocess_things
, onde data é um jsonb
tipo e o resultado esperado é:
id | arrive_date | arrive_location | data
1 | 2018-05-30 00:00:00-00 | location_00 | { "3": 2 }
2 | 2018-05-31 00:00:00-00 | location_00 | { "3": 8, "4": 7 }
Problema
Seu CTE
result_query
produz duas linhas com os mesmos valores para(arrive_date, arrive_location)
. O primeiro é inserido, o segundo gera um conflito noINSERT
e tentaUPDATE
a mesma linha que acabou de ser inserida - o que não é possível, como a mensagem de erro informa. Se a linha já existir, você receberá o mesmo erro ao tentar atualizar a mesma linha duas vezes.Para mais explicações, consulte:
Vários alvos de conflito
Como incluir linhas excluídas em RETURNING from INSERT ... ON CONFLICT
Solução
Dobre as duplicatas no
SELECT
, seja no CTE diretamente, ou noSELECT
anexo aoINSERT
. Você não divulgou como lidar com duplicatas exatamente, mas desde que você adotou minha sugestão comUPDATE
,preprocess_things.data || EXCLUDED.data
suponho que você queira substituir as mesmas chaves (mesmothing_type
) pelo mesmo(arrive_date, arrive_location)
, mas mesclar todas as chaves distintas (distintasthing_type
). Eu faço issojsonb_object_agg()
no CTE. A concatenação nasUPDATE
substitui as mesmas chaves.db<>fique aqui
Tudo é preparado no CTE, então usei a sintaxe curta
TABLE result_query
no arquivoINSERT
. Sobre isso:Sobre a
WHERE
cláusula adicionada para suprimir atualizações vazias: