MySQL中使用ROW_NUMBER()函数执行DELETE时报1288错误:目标表不可更新问题咨询
解决MySQL中使用CTE+ROW_NUMBER()删除重复数据时的1288错误
我之前也碰到过这个MySQL的坑!咱们来一步步拆解问题和解决办法:
问题原因分析
你遇到的Error Code: 1288本质原因是:MySQL不允许直接对CTE(公共表表达式)执行DELETE/UPDATE操作,哪怕你的CTE和基表同名。
当你写WITH idpublisher AS (...) DELETE FROM idpublisher时,MySQL会把这个idpublisher识别为CTE生成的临时结果集(相当于一个不可更新的视图),而不是你实际的物理表。即使CTE包含了主键,它依然是一个虚拟的数据集,不支持直接修改操作,所以会抛出“目标表不可更新”的错误。
解决方案
这里提供两种可靠的解决方法,都能实现你删除重复publisher数据的需求:
方法一:通过JOIN关联CTE删除基表数据
这种方法的核心是直接对物理表执行DELETE,用CTE作为筛选条件的来源,而不是去删除CTE本身:
WITH idpublisher_cte AS ( SELECT id, -- 这里必须选你的表的主键/唯一标识字段 ROW_NUMBER() OVER(PARTITION BY publisher ORDER BY id) AS RowNumber -- 建议用主键排序,保证保留固定行 FROM idpublisher ) DELETE ip FROM idpublisher ip JOIN idpublisher_cte cte ON ip.id = cte.id WHERE cte.RowNumber > 1;
注意:把
ORDER BY id换成你需要保留的行的排序规则(比如created_at DESC保留最新行),如果只按publisher排序,行号的顺序是不确定的,可能导致每次删除的行不一致。
方法二:使用嵌套子查询(无CTE)
如果你的MySQL版本不支持CTE(比如5.7及以前),可以用两层嵌套子查询来绕开“不能直接引用正在修改的表”的限制:
DELETE FROM idpublisher WHERE id IN ( SELECT id FROM ( SELECT id, ROW_NUMBER() OVER(PARTITION BY publisher ORDER BY id) AS RowNumber FROM idpublisher ) AS temp_table -- 必须给内层子查询加别名 WHERE RowNumber > 1 );
这里的内层子查询会生成一个临时结果集,外层查询通过这个临时集找到要删除的主键,再对原表执行删除操作,完美避开MySQL的限制。
内容的提问来源于stack exchange,提问作者Muhammad Saleh
相关产品推荐
相关产品推荐

