MariaDB执行带递归CTE的DELETE语句报1046未选择数据库错误
问题原因及解决方案
触发原因
该错误是MariaDB 10.5.11及更早版本的已知解析BUG:当预处理包含WITH RECURSIVE递归CTE子句的DML(DELETE/INSERT/UPDATE)语句时,解析器会丢失当前连接已配置的默认数据库上下文,因此误判没有选择数据库抛出1046错误。该问题对普通SELECT查询无影响,且官方已在MariaDB 10.6.5及后续稳定版本中完成修复,这也是同一份代码无需修改即可在MySQL 8上正常运行的原因。
可选解决方案
- 升级MariaDB版本:直接将MariaDB升级到10.6.5或更高的稳定版本,升级完成后原有代码无需任何修改即可正常运行,是成本最低的解决方案。
- 为所有表名增加数据库前缀:在你读取的SQL语句中,给所有显式声明的表名前加上所属数据库名,强制指定表的归属,即可绕开上下文丢失的问题,修改后的SQL示例如下(替换
your_db_name为实际的数据库名):
DELETE FROM `your_db_name`.`shares` WHERE `itemuuid` in ( WITH RECURSIVE files_paths (id, parent) AS ( SELECT uuid, parentuuid FROM `your_db_name`.`core_data` WHERE uuid = ? UNION ALL SELECT e.uuid, e.parentuuid FROM files_paths AS ep JOIN `your_db_name`.`core_data` AS e ON ep.id = e.parentuuid ) SELECT id FROM files_paths )
- 预处理前显式指定数据库:在执行
prepare操作前,先通过当前连接执行一次USE语句重新指定默认数据库,示例代码如下:
// 加在prepare之前 $this->dbcon->query("USE your_db_name"); $stmt = $this->dbcon->prepare($query);
- 改写SQL避免使用递归CTE:如果暂时无法升级也不想修改原有SQL结构,可以将递归查询逻辑改写为存储过程或者嵌套子查询实现,不过改造成本相对更高,不优先推荐。
内容的提问来源于stack exchange,提问作者Francesco Piraneo G.
相关产品推荐
相关产品推荐

