Doporučil bych použít INSERT...ON DUPLICATE KEY UPDATE
.
Pokud používáte INSERT IGNORE
, pak se řádek ve skutečnosti nevloží, pokud výsledkem bude duplicitní klíč. Ale příkaz nevygeneruje chybu. Místo toho generuje varování. Mezi tyto případy patří:
- Vložení duplicitního klíče do sloupců pomocí
PRIMARY KEY
neboUNIQUE
omezení. - Vložení hodnoty NULL do sloupce s hodnotou
NOT NULL
omezení. - Vložení řádku do rozdělené tabulky, ale vložené hodnoty se nemapují na oddíl.
Pokud použijete REPLACE
, MySQL ve skutečnosti provádí DELETE
následuje INSERT
interně, což má některé neočekávané vedlejší účinky:
- Je přiděleno nové ID automatického zvýšení.
- Závislé řádky s cizími klíči mohou být smazány (pokud používáte kaskádové cizí klíče) nebo jinak zabránit
REPLACE
. - Spouštěče, které se spouštějí při
DELETE
jsou prováděny zbytečně. - Nežádoucí účinky se šíří i do replik.
oprava: oba REPLACE
a INSERT...ON DUPLICATE KEY UPDATE
jsou nestandardní, proprietární vynálezy specifické pro MySQL. ANSI SQL 2003 definuje MERGE
příkaz, který může vyřešit stejnou potřebu (a další), ale MySQL nepodporuje MERGE
prohlášení.
Uživatel se pokusil upravit tento příspěvek (úprava byla zamítnuta moderátory). Úprava se pokusila přidat nárok, který INSERT...ON DUPLICATE KEY UPDATE
způsobí přidělení nového ID automatického zvýšení. Je pravda, že nové ID je vygenerováno , ale ve změněném řádku se nepoužívá.
Viz ukázka níže, testováno s Percona Server 5.5.28. Konfigurační proměnná innodb_autoinc_lock_mode=1
(výchozí):
mysql> create table foo (id serial primary key, u int, unique key (u));
mysql> insert into foo (u) values (10);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 10 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
mysql> insert into foo (u) values (10) on duplicate key update u = 20;
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> show create table foo\G
CREATE TABLE `foo` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`u` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `u` (`u`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
Výše uvedené ukazuje, že příkaz IODKU detekuje duplikát a vyvolá aktualizaci za účelem změny hodnoty u
. Všimněte si AUTO_INCREMENT=3
označuje, že ID bylo vygenerováno, ale nebylo použito v řádku.
Zatímco REPLACE
odstraní původní řádek a vloží nový řádek, vygeneruje a uložení nového ID automatického zvýšení:
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 1 | 20 |
+----+------+
mysql> replace into foo (u) values (20);
mysql> select * from foo;
+----+------+
| id | u |
+----+------+
| 3 | 20 |
+----+------+