Как вернуть старое значение столбца в postgres INSERT ON CONFLICT DO UPDATE? - PullRequest
0 голосов
/ 05 сентября 2018

Я пытаюсь запустить "upsert" в postgres, например:

INSERT INTO my_table (
    id, -- unique key
    name,
    hash
) VALUES (
    '4b544dea-b355-463c-8fba-40c36ac7cb0c',
    'example',
    '0x0123456789'
) ON CONFLICT (
    id
) DO UPDATE SET
    name = 'example',
    hash = '0x0123456789'
RETURNING
    OLD.hash;

Я хотел бы вернуть предыдущее значение столбца hash (приведенный выше пример не является допустимым запросом, поскольку OLD не является допустимым псевдонимом таблицы). Важно отметить, что я пытаюсь найти метод, который делает это таким образом, чтобы не вызывать конфликты под нагрузкой. Это вообще возможно? Или это единственное решение для выполнения операции «чтение перед записью» в транзакции?

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

В итоге я нашел обходной путь, хотя он не строго гарантирует атомарность, но в целом может быть хорошей стратегией в зависимости от вашего варианта использования.

INSERT INTO my_table (
    id, -- unique key
    name,
    hash
) VALUES (
    '4b544dea-b355-463c-8fba-40c36ac7cb0c',
    'example',
    '0x0123456789'
) ON CONFLICT (
    id
) DO UPDATE SET
    name = 'example',
    hash = '0x0123456789'
RETURNING
    name,
    hash, -- will be the new hash
    (SELECT hash FROM my_table WHERE my_table.id = '4b544dea-b355-463c-8fba-40c36ac7cb0c') -- will be the old hash
    ;
0 голосов
/ 13 декабря 2018

Другой возможный ответ, если вы хотите обновить схему, - сохранить предыдущее значение в другом столбце:

ALTER table my_table add column prev_hash text;

INSERT INTO my_table (
    id, -- unique key
    hash
) VALUES (
    1,
    'a'
) ON CONFLICT (
    id
) DO UPDATE SET
    hash = excluded.hash,
    prev_hash = my_table.hash
RETURNING
    id,
    hash,      -- will be the new hash
    prev_hash  -- will be the old hash
0 голосов
/ 05 сентября 2018

Предложение RETURNING в INSERT не будет даже возвращать результаты для ветви UPDATE.

Использование SELECT ... FOR UPDATE RETURNING ... кажется вашим лучшим вариантом, но имейте в виду, что есть небольшая раса & ndash; конфликтующая строка может быть вставлена ​​между SELECT и последующим INSERT, что приведет к сбою последнего.

Использование транзакции REPEATABLE READ и повторение операции в случае проблем могут помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...