MariaDB 10.3版本实现数据不存在即插入功能报错如何解决?
问题根因
- 1064语法报错原因:MariaDB 10.3及更低版本不支持无
FROM子句的SELECT语句直接跟随WHERE条件,你需要查询固定常量并附加判断条件时,要使用内置虚拟表DUAL作为查询来源。 - 添加
FROM bot_onet.Accuse后无报错但插入失败原因:此时SELECT的结果行数和accuse表的行数强绑定,若表为空则返回0行自然无法插入;若表有数据要么插入N条重复记录(N为表行数),要么NOT IN条件不生效时返回0行,不符合业务预期。 - 额外注意:
NOT IN语法如果子查询返回NULL值,整体判断条件会变为未知,会直接导致插入逻辑失效,稳定性较差。
推荐解决方案(兼容所有MariaDB版本,性能最优)
通过唯一约束+INSERT IGNORE实现不存在则插入的逻辑,避免子查询带来的各种问题:
- 先给
accuse表的去重标识字段lienFaceit添加唯一索引:
ALTER TABLE `bot_onet`.`accuse` ADD UNIQUE INDEX `uk_lienFaceit` (`lienFaceit`);
- 替换存储过程中的插入和ID取值逻辑即可:
CREATE DEFINER=`root`@`localhost` PROCEDURE `close_ticket`(IN idT INT,IN accuse VARCHAR(45),IN lienAccuse VARCHAR(60), IN lienG VARCHAR(60),IN jours INT,IN reason VARCHAR(250), IN isclosed BOOLEAN) BEGIN -- 重复lienFaceit自动跳过插入,无报错 INSERT IGNORE INTO bot_onet.accuse (`Pseudo`,`lienFaceit`) VALUES (accuse, lienAccuse); -- 加LIMIT 1避免多匹配行导致的取值错误 SELECT `idAccuse` INTO @ID FROM bot_onet.accuse WHERE `lienFaceit` = lienAccuse LIMIT 1; INSERT INTO bot_onet.ticket_has_accuse (`Ticket_idTicket`,`Accuse_idAccuse`,`duree`,`timecode`,`unbaned`,`raison`) VALUES (idT,@ID,jours,unix_timestamp(),FALSE,reason) ; UPDATE bot_onet.ticket SET `Fermeture` = unix_timestamp(),`closed` = isclosed, `LienGame` = LienG WHERE idTicket = idT; END
可选方案(无法添加唯一索引时使用)
如果你不能修改表结构加唯一索引,可以修正NOT IN写法,使用DUAL虚拟表并规避NULL值问题:
INSERT INTO bot_onet.accuse (`Pseudo`,`lienFaceit`) SELECT accuse, lienAccuse FROM DUAL -- 子查询加IS NOT NULL避免NULL导致NOT IN失效 WHERE lienAccuse NOT IN (SELECT `lienFaceit` FROM `bot_onet`.`accuse` WHERE `lienFaceit` IS NOT NULL);
内容的提问来源于stack exchange,提问作者C0casio45
相关产品推荐
相关产品推荐

