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

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

我有这样的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#

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

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

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

SET @NEW_AI = (SELECT MAX(`the_id`)+1 FROM `table_blah`);
SET @ALTER_SQL = CONCAT('ALTER TABLE `table_blah` AUTO_INCREMENT =', @NEW_AI);
PREPARE NEWSQL FROM @ALTER_SQL;
EXECUTE NEWSQL; 
INSERT INTO `table_blah` (`the_col`) VALUES("the_value")
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,则以下两个语句具有类似的效果:

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

    UPDATE table SET c=c+1 WHERE a=1;

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

cuxqih21

cuxqih215#

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


## THE SETUP

# This is the table we're trying to insert into

DROP TABLE IF EXISTS items;
CREATE TABLE items (
  id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(100) UNIQUE,
  price INT
);

# Put a few rows into the table

INSERT INTO items (name, price) VALUES
  ("Bike", 200),
  ("Basketball", 10),
  ("Fishing rod", 25)
;

## THE INSERT/UPDATE

# Create a temporary table to help with the update

DROP TEMPORARY TABLE IF EXISTS itemUpdates;
CREATE TEMPORARY TABLE itemUpdates (
  name VARCHAR(100) UNIQUE,
  price INT,
  isNew BOOLEAN DEFAULT(true)
);

# Change the price of the Bike and Basketball and add a new Tent item

INSERT INTO itemUpdates (name, price) VALUES
  ("Bike", 150),
  ("Basketball", 8),
  ("Tent", 100)
;

# For items that already exist, set isNew false

UPDATE itemUpdates
JOIN items
ON items.name = itemUpdates.name
SET isNew = false;

# UPDATE the already-existing items

UPDATE items
JOIN itemUpdates
ON items.name = itemUpdates.name
SET items.price = itemUpdates.price
WHERE itemUpdates.isNew = false;

# INSERT the new items

INSERT INTO items (name, price)
SELECT name, price
FROM itemUpdates
WHERE itemUpdates.isNew = true;

# Check the results

SELECT * FROM items;

# Results:

# ID | Name        | Price

# 1  | Bike        | 150

# 2  | Basketball  | 8

# 3  | Fishing rod | 25

# 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吗?但我的案子不需要这个。

相关问题