我的问题与Why does MySQL autoincrement increase on failed inserts?相同,但我不想增加id
字段,而是希望重写导致我麻烦的INSERT
查询。假设我的数据库包含两个字段id
和username
,其中id
是主键,username
是唯一键。我基本上在寻找能INSERT...IF NOT EXISTS
的语法。现在,我做了
INSERT INTO `table`(`username`)
VALUES ('foo')
ON DUPLICATE KEY UPDATE `id`=`id`
我只有一个线程写入数据库,因此我不需要任何类型的并发保护。建议?
答案 0 :(得分:5)
你应该用这个:
INSERT INTO tableX (username)
SELECT 'foo' AS username
FROM dual
WHERE NOT EXISTS
( SELECT *
FROM tableX
WHERE username = 'foo'
) ;
如果要包含更多列的值:
INSERT INTO tableX (username, dateColumn)
SELECT 'foo' --- the aliases are not needed
, NOW() --- actually
FROM dual
WHERE NOT EXISTS
( SELECT *
FROM tableX
WHERE username = 'foo'
) ;
答案 1 :(得分:3)
我认为你不能阻止计数器增加,因为答案中给出的原因是你所链接的问题。
您有三种选择:
使用跳过的标识符生活;你真的希望用64位吗?
在尝试INSERT
之前检查是否存在现有记录:
DELIMITER ;;
IF NOT EXISTS (SELECT * FROM `table` WHERE username = 'foo') THEN
INSERT INTO `table` (username) VALUES ('foo');
END IF;;
DELIMITER ;
或者,更好的是,使用@ypercube建议的FROM dual WHERE NOT EXISTS ...
表单。
每次插入后重置计数器。如果在存储过程中执行INSERT
操作,则可以使用处理程序执行此操作以获取重复键错误:
DELIMITER ;;
CREATE PROCEDURE TEST(IN uname CHAR(16) CHARSET latin1) BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' BEGIN
-- WARNING: THIS IS NOT SAFE FOR CONCURRENT CONNECTIONS
SET @qry = CONCAT(
'ALTER TABLE `table` AUTO_INCREMENT = ',
(SELECT MAX(id) FROM `table`)
);
PREPARE stmt FROM @qry;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @qry = NULL;
END;
INSERT INTO `table` (username) VALUES (uname);
END;;
DELIMITER ;
请记住@ypercube在关于此策略的评论中提出的(有效)问题,您可以改为使用:
SELECT AUTO_INCREMENT - 1
FROM INFORMATION_SCHEMA.TABLES
WHERE table_schema = 'db_name' AND table_name = 'table';
答案 2 :(得分:1)
您可以在插入失败后重置自动增量字段
ALTER TABLE table_name AUTO_INCREMENT = 1;
这不会将自动增量重置为1,但会将其重置为当前最大值加一
另请注意,与数据库连接的用户应具有对目标表的更改权限
答案 3 :(得分:0)
使用INSERT IGNORE INTO table
。查看以下帖子
http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html
你可以这样做:
INSERT INTO `table`(`username`)
VALUES ('foo')
ON DUPLICATE KEY UPDATE `username`= 'foo'
OR
INSERT IGNORE INTO `table`
SET `username` = 'foo'
答案 4 :(得分:0)
您也可以在插入之前检查该用户,如果之前插入了该用户,则会额外调用您的数据库,但是,如果该用户已经存在,您可以返回您找到的信息并避免伪插入。 / p>