MySQL同表INSERT SELECT遇1093错误:迁移数据库保留父子层级问题
解决MySQL 1093错误:插入时引用同一表的子查询问题
嘿,我太懂你遇到的这个#1093错误了——MySQL的这个限制确实有点磨人,本质原因是你不能在INSERT/UPDATE操作的目标表中,直接用子查询引用它自己。在你的迁移场景里,就是插入UnitTree表的同时,又在VALUES子句里直接查询UnitTree的TMP列,MySQL会认为这是不安全的(毕竟表正在被修改,查询可能拿到不一致的数据),所以直接抛出了错误。
不过别担心,有两种简单靠谱的方法可以绕开这个限制,完美保留你的父子层级迁移需求:
方法一:将子查询包装成派生表
最直接的修复方式,就是把引用UnitTree的子query多套一层SELECT,变成派生表。这样MySQL会先执行派生表的查询,生成一个独立的临时结果集,再用这个结果集来做插入操作,就不会和正在修改的UnitTree表冲突了。
修改后的代码示例:
INSERT INTO UnitTree (DealerID, Label, TMP) VALUES ( (SELECT ID FROM Dealer WHERE Name='Dealer1'), 'Folder1', (SELECT t.ID FROM (SELECT ID FROM UnitTree WHERE TMP=2) AS t) ), ( (SELECT ID FROM Dealer WHERE Name='Dealer2'), 'Folder2', (SELECT t.ID FROM (SELECT ID FROM UnitTree WHERE TMP=3) AS t) );
方法二:改用INSERT ... SELECT语法(更推荐)
如果你的批量插入行数较多,用INSERT ... SELECT搭配UNION ALL的方式会更清晰,也更符合MySQL的最佳实践,同样能避开1093错误:
INSERT INTO UnitTree (DealerID, Label, TMP) SELECT d1.ID, 'Folder1', ut1.ID FROM (SELECT ID FROM Dealer WHERE Name='Dealer1') d1, (SELECT ID FROM UnitTree WHERE TMP=2) ut1 UNION ALL SELECT d2.ID, 'Folder2', ut2.ID FROM (SELECT ID FROM Dealer WHERE Name='Dealer2') d2, (SELECT ID FROM UnitTree WHERE TMP=3) ut2;
这种写法把每个插入行的数据源都明确封装成子查询,可读性更强,而且MySQL对这种语法的优化也更好。
简单总结:核心就是避免直接在插入的VALUES子句里查询目标表,通过派生表或者切换语法的方式,让查询和插入操作的数据源相互独立,就能顺利完成迁移啦。
内容的提问来源于stack exchange,提问作者Daniel Kahle
相关产品推荐
相关产品推荐

