关于重复键+自动递增的问题

vdzxcuhz  于 2021-06-25  发布在  Mysql
关注(0)|答案(6)|浏览(439)

我有这样的table结构

在表中插入行时,我使用以下查询: INSERT INTO table_blah ( material_item, ... hidden ) VALUES ( data, ... data ) ON DUPLICATE KEY UPDATE id = id, material_item = data, ... hidden = data; 当我第一次插入数据而不触发 ON DUPLICATE KEY id增量很好:

但是当 ON DUPLICATE KEY 触发器,然后我插入一个新行id看起来很奇怪:

我怎样才能保持 auto increment ,即使触发,也会正确递增 ON DUPLICATE KEY ?

nimxete2

nimxete21#

我只是想补充一句,因为我正试图找到我问题的答案。我无法停止重复的警告,并发现这是因为我把它设置为tinyint只允许127个条目,改为small/med/bigint允许更多

u5i3ibmn

u5i3ibmn2#

这个问题很老了,但我回答它可能对某些人有帮助,要解决自动递增的问题,请在插入/重复更新部分之前使用以下代码并一起执行它们:

  1. SET @NEW_AI = (SELECT MAX(`the_id`)+1 FROM `table_blah`);
  2. SET @ALTER_SQL = CONCAT('ALTER TABLE `table_blah` AUTO_INCREMENT =', @NEW_AI);
  3. PREPARE NEWSQL FROM @ALTER_SQL;
  4. EXECUTE NEWSQL;

在一个声明中,应该是这样的:

  1. SET @NEW_AI = (SELECT MAX(`the_id`)+1 FROM `table_blah`);
  2. SET @ALTER_SQL = CONCAT('ALTER TABLE `table_blah` AUTO_INCREMENT =', @NEW_AI);
  3. PREPARE NEWSQL FROM @ALTER_SQL;
  4. EXECUTE NEWSQL;
  5. INSERT INTO `table_blah` (`the_col`) VALUES("the_value")
  6. ON DUPLICATE KEY UPDATE `the_col` = "the_value";
c90pui9n

c90pui9n3#

INSERT INTO table_blah ( material_item, ... hidden ) VALUES ( data, ... data ) ON DUPLICATE KEY UPDATE material_item = data, ... hidden = data 是删除id=id,因为它会自动添加where primary key=primary key。。。

yws3nbqq

yws3nbqq4#

此行为记录在案(括号中的段落):
如果指定了on duplicate key update,并且插入了一行,这将导致在唯一索引或主键中出现重复值,mysql将执行旧行的更新。例如,如果列a被声明为unique并包含值1,则以下两个语句具有类似的效果:

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

(对于一个innodb表,其中a是一个自动递增列,其效果是不同的。对于自动增量列,insert语句会增加自动增量值,但update不会。)
这里有一个简单的解释。mysql尝试先执行insert。这是id自动递增的时候。一旦增加,它就会保持不变。然后检测到重复并进行更新。但是这个值被忽略了。
你不应该依赖 auto_increment 没有空隙的。如果这是一个要求,那么更新和插入的开销就要大得多。基本上,您需要在整个表上设置一个锁,并对需要重新编号的所有内容重新编号,通常使用触发器。更好的解决方案是计算输出的增量值。

cuxqih21

cuxqih215#

我经常通过创建一个临时表来处理这个问题,在临时表中记录记录是否是新的,只对不是新的行进行更新,并对新行进行插入。下面是一个完整的示例:

  1. ## THE SETUP
  2. # This is the table we're trying to insert into
  3. DROP TABLE IF EXISTS items;
  4. CREATE TABLE items (
  5. id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  6. name VARCHAR(100) UNIQUE,
  7. price INT
  8. );
  9. # Put a few rows into the table
  10. INSERT INTO items (name, price) VALUES
  11. ("Bike", 200),
  12. ("Basketball", 10),
  13. ("Fishing rod", 25)
  14. ;
  15. ## THE INSERT/UPDATE
  16. # Create a temporary table to help with the update
  17. DROP TEMPORARY TABLE IF EXISTS itemUpdates;
  18. CREATE TEMPORARY TABLE itemUpdates (
  19. name VARCHAR(100) UNIQUE,
  20. price INT,
  21. isNew BOOLEAN DEFAULT(true)
  22. );
  23. # Change the price of the Bike and Basketball and add a new Tent item
  24. INSERT INTO itemUpdates (name, price) VALUES
  25. ("Bike", 150),
  26. ("Basketball", 8),
  27. ("Tent", 100)
  28. ;
  29. # For items that already exist, set isNew false
  30. UPDATE itemUpdates
  31. JOIN items
  32. ON items.name = itemUpdates.name
  33. SET isNew = false;
  34. # UPDATE the already-existing items
  35. UPDATE items
  36. JOIN itemUpdates
  37. ON items.name = itemUpdates.name
  38. SET items.price = itemUpdates.price
  39. WHERE itemUpdates.isNew = false;
  40. # INSERT the new items
  41. INSERT INTO items (name, price)
  42. SELECT name, price
  43. FROM itemUpdates
  44. WHERE itemUpdates.isNew = true;
  45. # Check the results
  46. SELECT * FROM items;
  47. # Results:
  48. # ID | Name | Price
  49. # 1 | Bike | 150
  50. # 2 | Basketball | 8
  51. # 3 | Fishing rod | 25
  52. # 4 | Tent | 100

这个 INSERT IGNORE INTO 方法更简单,但它忽略了任何错误,这不是我想要的。我同意mysql的这种奇怪行为,但这是我们必须处理的。

展开查看全部
qlfbtfca

qlfbtfca6#

我也有同样的沮丧,我有一个解决办法。
让我先谈谈“间接费用”。当我第一次编写db更新代码时,它执行了太多单独的查询,花费了5个小时。一旦我把“复制密钥更新”我得到了大约50秒。太神了!无论如何,我解决它的方法意味着我必须做2个查询,所以我不是1分钟,而是延长到2分钟,我认为这是一个公平的成本考虑。
首先,我对所有数据(更新和插入)执行了一个标准的sql查询,但我包含了“忽略”,所以这只是绕过更新,只插入新内容。”在mytablename(stuff,stuff2)值中插入ignore“-不包含更新时的重复键。这意味着所有的新记录都会被输入。这些新记录还不能打破自动增量。
接下来,我对该sql语句执行了“on duplicate key update”版本。这不会破坏任何id,因为所有记录都已存在。它唯一中断的是自动递增值,在添加新记录时使用该值。因此,解决方案是在添加任何新记录之前修补这个自动增量值。
要修补自动增量值,请在php中使用以下sql:“alter table mytablename auto\u increment=”($表计数+1);
请记住将$tablecount实际设置为表计数,然后添加1,这样就可以进行进一步的更新了。
这既便宜又脏,但我喜欢。确保不要同时使用其他函数等写入数据库,因为它可能会出错。我想有办法锁table吗?但我的案子不需要这个。

相关问题