После нескольких секунд игры с SQL я не могу достичь того, чего ожидаю. Я искал в документации PostgreSQL, но ничего не смог сделать так, как я хотел.
У меня есть таблица с 5 столбцами:
| id | some_serial | user_id | foo | bar |
|----|-------------|---------|--------|--------|
| 1 | 8000000 | 42 | AA | <null> |
| 2 | 8000001 | <null> | <null> | CC |
Я хочу вставить новые значения в таблице, возвращающие соответствующий серийный номер. Если новые значения соответствуют каким-либо данным в user_id , foo или bar , я хочу, чтобы строка была обновлена, и здесь снова return соответствующий серийный номер.
Требуемое поведение:
Например: вставка 42, AA, BB
обновит первую строку. bar станет BB, а 8000000 будет возвращено.
| id | some_serial | user_id | foo | bar |
|----|-------------|---------|--------|--------|
| 1 | 8000000 | 42 | AA | BB |
| 2 | 8000001 | <null> | <null> | CC |
Вставка 43, null, CC
обновит вторую строку. user_id станет 43, а 8000001 будет возвращено.
| id | some_serial | user_id | foo | bar |
|----|-------------|---------|--------|--------|
| 1 | 8000000 | 42 | AA | BB |
| 2 | 8000001 | 43 | <null> | CC |
Вставка 44, DD, EE
создаст новую строку, возвращающую новый серийный номер.
| id | some_serial | user_id | foo | bar |
|----|-------------|---------|--------|--------|
| 1 | 8000000 | 42 | AA | BB |
| 2 | 8000001 | 43 | <null> | CC |
| 3 | 8000002 | 44 | DD | EE |
Фактическое поведение:
Я пытался с уникальным ограничением на (user_id, foo, bar), но это не дает мне желаемого поведения. После первой вставки результат будет:
| id | some_serial | user_id | foo | bar |
|----|-------------|---------|--------|--------|
| 1 | 8000000 | 42 | AA | <null> |
| 2 | 8000001 | <null> | <null> | CC |
| 3 | 8000002 | 42 | AA | BB |
Насколько я понимаю, это связано с тем, что ограничение будет проверять уникальность трех столбцов вместе.
ОГРАНИЧЕНИЕ Iесть:
ALTER TABLE my_table
ADD CONSTRAINT my_table_user_id_foo_bar_unique
UNIQUE (user_id, foo, bar);
UPSERT У меня есть:
INSERT INTO my_table (user_id, foo, bar)
VALUES (42, 'AA', 'BB')
ON CONFLICT ON CONSTRAINT my_table_user_id_foo_bar_unique
DO UPDATE
SET user_id = 42,
foo = COALESCE(my_table.foo, EXCLUDED.foo),
bar = COALESCE(my_table.bar, EXCLUDED.bar)
RETURNING some_serial;
Любая помощь будет принята с благодарностью. : -)
Здесь мое решение в это время:
Сначала я пытаюсь обновить строку, возвращая ее, если она существует.
UPDATE my_table
SET user_id = $1
, foo = COALESCE(foo, $2)
, bar = COALESCE(bar, $3)
WHERE (foo = $2 AND foo <> NULL)
OR (bar = $3 AND bar <> NULL)
RETURNING some_serial
И если этот запрос ничего не дал, я просто вставляю его:
INSERT INTO my_table (user_id, foo, bar)
VALUES ( $1, $2, $3)
RETURNING some_serial