Поведение MySQL ON DUPLICATE KEY UPDATE для нескольких UNIQUE полей

Начиная с MySQL 4.1.0, можно добавить оператор ON DUPLICATE KEY UPDATE, чтобы указать поведение, когда вставленные значения (с INSERT или SET или VALUES) уже находятся в целевой таблице w.r.t. PRIMARY KEY или какое-то UNIQUE поле. Если значение для PRIMARY KEY или какого-либо поля UNIQUE уже есть в таблице, INSERT заменяется на UPDATE.

  • Как ведет себя ON DUPLICATE KEY UPDATE, если в моей таблице несколько полей UNIQUE?

  • Могу ли я получить только одно обновление, если одно из полей UNIQUE совпадает?

  • Могу ли я получить обновление, только если оба поля UNIQUE совпадают одновременно?


person kiriloff    schedule 04.05.2013    source источник


Ответы (2)


Рассмотреть возможность

INSERT INTO table (a,b,c) VALUES (1,2,3)
    -> ON DUPLICATE KEY UPDATE c=c+1;

Если a и b являются полями UNIQUE, UPDATE возникает в a = 1 OR b = 2. Также, когда условие a = 1 OR b = 2 выполняется двумя или более записями, обновление выполняется только один раз.

Ex here table таблица с полями Id и Name UNIQUE

Id     Name     Value 
1      P        2 
2      C        3 
3      D        29 
4      A        6

Если запрос

INSERT INTO table (Id, Name, Value)
VALUES (1, C, 7);

тогда мы получаем

Id     Name     Value 
1      P        2 
2      C        3 
3      D        29 
4      A        6
1      C        7

что нарушает уникальность Id и Name. Теперь с

INSERT INTO table (Id, Name, Value)
VALUES (1, C, 7)
ON DUPLICATE KEY UPDATE Value = 7;

мы получаем

Id     Name     Value 
1      P        7 
2      C        7 
3      D        29 
4      A        6

Поведение нескольких ключей следующее

UPDATE в ON DUPLICATE KEY UPDATE выполняется, если одно из полей UNIQUE равно вставляемому значению. Здесь UPDATE выполняется на Id = 1 OR Name = C. Это эквивалентно

UPDATE table 
SET Value = 7
WHERE Id = 1 OR Name = C;

Что делать, если мне нужно только одно обновление для любого ключа

Можно использовать оператор UPDATE с ключевым словом LIMIT

UPDATE table 
SET Value = 7
WHERE Id = 1 OR Name = C
LIMIT 1;

что даст

Id     Name     Value 
1      P        7 
2      C        3 
3      D        29 
4      A        6

Что делать, если мне нужно одно обновление, только если значения для обоих ключей совпадают

Одним из решений является ALTER TABLE и заставить PRIMARY KEY (или уникальность) работать в обоих полях.

ALTER TABLE table 
DROP PRIMARY KEY,
ADD PRIMARY KEY (Id, Name);

Сейчас на

INSERT INTO table (Id, Name, Value)
VALUES (1, C, 7)
ON DUPLICATE KEY UPDATE Value = 7;

мы получаем

Id     Name     Value 
1      P        2 
2      C        3 
3      D        29 
4      A        6
1      C        7

так как дубликат (на обоих ключах) не найден.

person kiriloff    schedule 04.05.2013
comment
Если у вас есть таблица с двумя столбцами в качестве первичного ключа и вы хотите работать с КЛЮЧОМ ON DUPLICATE KEY, избегайте добавления уникального индекса в столбцы pk, потому что это будет обновляться, если в значениях присутствуют pk1 или pk2. - person jloria; 31.10.2014
comment
Есть ли способ иметь уникальное ограничение для 2-го столбца, но сделать так, чтобы оно не влияло на эту операцию обновления дублирующего ключа? Это означает, что вставка или обновление завершатся ошибкой, если уникальное ограничение не соблюдается. - person CMCDragonkai; 25.07.2015
comment
Мои тесты противоречат тому, что утверждает этот ответ (в MySQL 8.0.22). Обновляется только одна повторяющаяся строка, и это строка первого индекса, в котором найден дубликат. Раздражает, так как сложно контролировать порядок индексов, а порядок индексов не должен иметь значения. (Обратите внимание, что PK всегда является первым уникальным индексом, поэтому дубликат PK всегда будет первым претендентом на обновление — и это единственное, что кажется логичным во всем этом.) - person Timo; 18.03.2021

  1. как ведет себя MySQL ... Он ведет себя так, как ожидалось, то есть выполняет предложение ON DUPLICATE KEY.

  2. Могу ли я получить одно обновление для любого... На самом деле у вас есть только одно предложение ON DUPLICATE KEY, поэтому вам нужно поместить некоторый код, чтобы различать, какое ограничение было задействовано. К счастью, это возможно. Единственное, что вы должны знать, порядок назначения имеет значение, и вы можете назначать несколько раз. Предположим, у вас есть уникальное ограничение на a и b, и вы хотите обновить c, только если речь идет об уникальности: ... ОБНОВЛЕНИЕ КЛЮЧА c = IF(a = VALUES(a) and b ‹> VALUES(b), VALUES( в), в), б = ЗНАЧЕНИЯ(б)

    но если вы измените порядок присваиваний, второе условие внутри if всегда будет ложным.

  3. См. 2.

person newtover    schedule 04.05.2013