Postgresql: UPSERT / INSERT INTO, определяющий конфликт - PullRequest
2 голосов
/ 01 марта 2020

это мой первый пост на платформе.

Я надеюсь это изображение объясняет, что я пытаюсь сделать. Я пытаюсь объединить таблицу B с таблицей A. Если выполняется условие (A.cell = B.cell AND A.object = B.objet), то я хочу обновить A.cost с соответствующей стоимостью из таблицы B. Если условие не выполняется, я хочу вставить строку из B в A.

То, что я до сих пор пробовал, это упор, но он не работал:

INSERT INTO reached_points
SELECT B.cell_id, B.object_id, B.reached_cost
FROM test_reached_cells B
ON CONFLICT (cell_id, object_id)
WHERE (cell_id = B.cell_id AND object_id = B.object_id)
DO UPDATE SET cost = B.reached_cost

Я думал в предложении WHERE после КОНФЛИКТА, который я мог определить, когда этот конфликт «вызван». Разве это не так? Я так и думал, потому что в документации говорится что-то вроде "[ON CONFLICT target action;] Цель может быть: предикат WHERE - предложение WHERE с предикатом".

Есть ли способ добиться обновления, и если условие не выполняется, вставка? Я хотел избежать этого в два совершенно отдельных шага, потому что кажется неэффективным сравнивать таблицы дважды.

1 Ответ

0 голосов
/ 01 марта 2020

Я думал в предложении WHERE после КОНФЛИКТА, который я мог определить, когда этот конфликт «вызван». Разве это не так?

Нет. То, что определяет concflict - это target , выражение, которое следует сразу за ключевым словом ON CONFLICT. В вашем запросе это:

on conflict(cell_id, object_id)

... что вам нужно - обратите внимание, что для этого требуется наличие уникального индекса для этого набора столбцов (или ограничения первичного ключа). Таким образом, вам не нужно (и не нужно) это предложение where.

Кроме того, чтобы получить доступ к столбцу из другой таблицы в предложении do update, вы можете использовать псевдостол excluded.

Рассмотрим:

insert into reached_points(cell_id, object_id, cost)
select cell_id, object_id, reached_cost from test_reached_cells
on conflict(cell_id, object_id)
do update set cost = excluded.cost

Демонстрация на DB Fiddle :

Пример данных:

select * from reached_points;
cell_id | object_id | cost
------: | --------: | ---:
      1 |         2 |    3
select * from test_reached_cells;
cell_id | object_id | reached_cost
------: | --------: | -----------:
      1 |         2 |            4
      1 |         3 |            4

Запрос:

insert into reached_points(cell_id, object_id, cost)
select cell_id, object_id, reached_cost from test_reached_cells
on conflict(cell_id, object_id)
do update set cost = excluded.cost
-- 2 rows affected

Результаты:

select * from reached_points;
cell_id | object_id | cost
------: | --------: | ---:
      1 |         2 |    4
      1 |         3 |    4
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...