Обработка конфликтов Postgres с несколькими уникальными ограничениями

Я хотел бы использовать вставку.. на confict do update.. синтаксис с таблицей, которая имеет уникальные ограничения на два столбца. Возможно ли это?

например. mytable имеет отдельные уникальные ограничения на col1 и col2.

Я могу написать:

INSERT INTO mytable(col1, col2, col3) values ('A', 'B', 0) ON CONFLICT DO NOTHING;

Однако это не работает:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0) 
ON CONFLICT 
DO UPDATE SET col3 = EXCLUDED.col3 + 1;

ОШИБКА: ON CONFLICT DO UPDATE требует спецификации вывода или имени ограничения

Это также не работает:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0)
ON CONFLICT (col1, col2) 
DO UPDATE SET col3 = EXCLUDED.col3 + 1;

ОШИБКА: нет единственного ограничения исключения или исключения, соответствующего спецификации ON CONFLICT

Этот синтаксис, по-видимому, предназначен для единого составного уникального ограничения по двум столбцам, а не для двух ограничений.

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

Ответы

Ответ 1

В предложении ON CONFLICT требуется одно уникальное ограничение, когда мы запрашиваем его DO UPDATE. Когда первичный ключ определен, достаточно просто указать имя столбца; который является доминирующим примером, который, как правило, находит.

Вы упомянули, что у вас есть "отдельные уникальные ограничения на col1 и col2", поэтому я могу предположить, что определение вашей таблицы аналогично этому:

CREATE TABLE mytable(       
    col1 varchar UNIQUE,    
    col2 varchar UNIQUE,    
    col3 int
);

Но ваш запрос ссылается на составное ограничение; а не отдельные ограничения. Модифицированное определение таблицы:

CREATE TABLE mytable2(  
    col1 varchar UNIQUE,
    col2 varchar UNIQUE,
    col3 int,
    CONSTRAINT ux_col1_col2 UNIQUE (col1,col2)
);

будет работать с вашим запросом выше:

INSERT INTO mytable(col1, col2, col3) VALUES ('A', 'B', 0)
ON CONFLICT (col1, col2) 
DO UPDATE SET col3 = EXCLUDED.col3 + 1;

Вы можете ссылаться на это уникальное ограничение как на ON CONFLICT (col1, col2), так и на ON CONFLICT ON CONSTRAINT ux_col1_col2.

Но подождите, там еще...

Идея состоит в том, чтобы обновить счетчик столбцов, который соответствует либо уникальный столбец, либо вставить ноль, если не существует...

Это другой путь, чем вы здесь. "совпадения в любом уникальном столбце" допускают совпадение на обоих, либо ни один из них. Если я понимаю ваши намерения, просто поставьте одну метку и увеличьте счетчики на соответствующих записях. Итак:

CREATE TABLE mytable2(  
    col1 varchar PRIMARY KEY,
    col3 int
);
INSERT INTO mytable2(col1,col3)
SELECT incr_label,0
FROM (VALUES ('A'),('B'),('C')) as increment_list(incr_label)
ON CONFLICT (col1)
DO UPDATE SET col3 = mytable2.col3 + 1
RETURNING col1,col3;