使用multi_query复制带自增键记录返回1却未插入,SQL是否正确?
嘿,我来帮你拆解下这个问题~你的SQL确实存在逻辑问题,再加上对multi_query返回值的理解偏差,才导致了“返回1但记录没插入”的情况:
1. 先澄清multi_query的返回值误区
你以为返回TRUE就代表所有SQL都执行成功?不对哦!mysqli::multi_query()的返回值仅表示第一条SQL语句执行成功,后续语句的执行状态需要用next_result()逐个检查。所以你看到的返回1(也就是TRUE),其实只是临时表创建成功了,后面的INSERT大概率已经失败,但你没检测到这个错误。
2. 你的INSERT语句核心逻辑错误
看这条关键的INSERT语句:
INSERT INTO TESTY SELECT MAX(TESTY_ID)+1 FROM tmp where TESTY_ID = 88;
问题很明显:你只从临时表tmp里选择了MAX(TESTY_ID)+1这一个值插入到TESTY表,但TESTY表肯定不止TESTY_ID这一个字段吧?如果其他字段设置了NOT NULL约束,这条INSERT会直接失败;就算允许NULL,插入的记录也只有ID有值,其他字段全是空的,这显然不是你想要的“复制整条记录”的效果。
另外还有个隐藏坑:就算你想手动生成ID,MAX(TESTY_ID)+1的写法在并发场景下会有主键冲突风险——如果在你执行这段SQL的间隙,有另一个请求插入了新记录,你算出来的ID就已经被占用了。
正确的写法参考
既然TESTY_ID是自增键,完全可以让数据库自动生成新ID,既安全又省事:
方法1:用临时表(保留你的原有思路,修正逻辑)
$sql = "CREATE TEMPORARY TABLE tmp SELECT * FROM TESTY WHERE TESTY_ID = 88; INSERT INTO TESTY SELECT NULL, 字段2, 字段3, ... FROM tmp;"; // 一定要检查所有查询的执行结果! if ($mysqli->multi_query($sql)) { do { if (!$mysqli->store_result()) { echo "查询出错: " . $mysqli->error; break; } } while ($mysqli->next_result()); }
这里的NULL是留给自增键TESTY_ID的,数据库会自动填充新的自增值;后面的字段2,字段3...要替换成TESTY表中除了TESTY_ID之外的所有字段。
方法2:跳过临时表,一步完成复制(更简洁)
如果不需要临时表做其他操作,直接用单条SQL就能完成复制:
$sql = "INSERT INTO TESTY (字段2, 字段3, ...) SELECT 字段2, 字段3, ... FROM TESTY WHERE TESTY_ID = 88;"; $mysqli->query($sql);
最后提醒
永远不要只看multi_query的第一个返回值,一定要通过next_result()遍历检查所有语句的执行状态,否则很容易忽略后续的错误。另外,自增键尽量交给数据库自动管理,避免手动计算带来的并发问题。
内容的提问来源于stack exchange,提问作者Lixo

