在MySQL中使用CTE更新或删除

时间:2018-06-11 13:41:07

标签: mysql sql-update common-table-expression sql-delete mysql-8.0

新版本的MySQL 8.0现在支持Common Table Expressions

根据手册:

  

在SELECT,UPDATE和DELETE语句的开头允许使用WITH子句:

WITH ... SELECT ...
WITH ... UPDATE ...
WITH ... DELETE ...

所以,我想,如下表所示:

ID lastName firstName
----------------------
1  Smith    Pat
2  Smith    Pat
3  Smith    Bob

我可以使用以下查询:

;WITH ToDelete AS 
(
   SELECT ID,
          ROW_NUMBER() OVER (PARTITION BY lastName, firstName ORDER BY ID) AS rn
   FROM mytable
)   
DELETE FROM ToDelete

为了删除表格中的重复项,就像我在SQL Server中所做的那样。

事实证明我错了。当我尝试从MySQL Workbench执行DELETE时,我得到错误:

  

错误代码:1146。表'todelete'不存在

当我尝试使用CTE UPDATE时,我也收到错误消息。

所以,我的问题是,如何在MySQL中WITHUPDATE语句的上下文中使用DELETE子句(如8.0版手册中所述)?

2 个答案:

答案 0 :(得分:3)

这似乎是MySQL 8.x中已发布的错误。从bug report

开始
  

在2015版SQL标准中,无法在UPDATE中定义CTE; MySQL允许它,但使CTE只读(我们现在更新文档提到这一点)。   这就是说,人们可以使用视图而不是CTE;然后视图可以更新,但是由于窗口函数的存在,它被实现为临时表(它没有被合并),因此不可更新(我们也将在doc中提及它)。

     

以上所有内容也适用于DELETE。

如果您按照上述错误链接,您将看到建议使用CTE的解决方法,但它涉及以一对一的映射方式将CTE加入原始目标表。根据您的示例(即全面删除),您不清楚需要使用CTE进行删除。

答案 1 :(得分:1)

由于CTE不可更新,因此您需要引用原始表来删除行。我想你正在寻找这样的东西:

WITH ToDelete AS 
(
   SELECT ID,
          ROW_NUMBER() OVER (PARTITION BY lastName, firstName ORDER BY ID) AS rn
   FROM mytable
)   
DELETE FROM mytable USING mytable JOIN ToDelete ON mytable.ID = ToDelete.ID
WHERE ToDelete.rn > 1;