如何在 CTE 上的 MySQL 中运行更新查询?

Posted

技术标签:

【中文标题】如何在 CTE 上的 MySQL 中运行更新查询?【英文标题】:How do I run an update query in MySQL on a CTE? 【发布时间】:2020-06-16 17:20:55 【问题描述】:

我正在尝试创建一个 CTE,我认为它运行良好。但是,我想在此 CTE 上运行更新查询,但我在 mysql WorkBench 中不断收到以下错误,

"Error Code: 1288. The target table pptest of the UPDATE is not updatable"

我环顾四周,但没有不了解任何变通方法,最重要的是,我对我的 MySQL 也不太了解。我的目标基本上是创建一个表/视图,其中包含一堆已分区的记录,并且每行都有一个索引号,由“row_num”表示。这是将表中的重复数据分组在一起,然后我希望在 row_num 大于 1 的结构上简单地运行更新查询。如此简单的逻辑,但我想不出任何其他方法来实现我的目标。请问有人可以帮忙吗?

我之前运行的完整查询是,

WITH cte as (select *, row_number() over (partition by col_a order by col_a) row_num from db_name.table_name) 
update cte set col_b='test' where row_num > 1

【问题讨论】:

【参考方案1】:

MySQL 不支持此语法。实际上,这看起来像 SQL Server 语法...您不能只是将查询从一个数据库移植到另一个数据库并期望它们正常工作。

在 MySQL 中,您可以使用 update ... join 语法。但是,您需要一个唯一标识每一行的主键列(或一组列)作为连接条件。假设该列 id 是您的主键,那就是:

update db_name.table_name t
inner join (
    select id
    row_number() over (partition by col_a order by col_a) row_num 
    from db_name.table_name) 
) t1 on t1.id = t.id
set t.col_b = 'test' 
where t1.row_num > 1

旁注:

据我了解,您的查询旨在标记 col_a 上的重复项。但是您使用row_number() 的方式,不确定哪些重复行将被标记,因为您的order by 子句不是确定性的;你最好有一个over() 子句,例如:over (partition by col_a order by id)

row_number() 等窗口函数仅在 MySQL 8.0 中可用

【讨论】:

【参考方案2】:

更新和删除在 mysql 临时表中不起作用。一种解决方法是将原始表与临时表 CTE 连接并更新原始表:

    WITH cte as (select *, row_number() 
over (partition by col_a order by col_a) row_num 
from db_name.table_name) 
    
    update db_name.table_name T1 
Join 
cte on T1.col_a = cte.col_a set t1.col_b='test' where cte.row_num > 1

这也适用于删除指令。

【讨论】:

以上是关于如何在 CTE 上的 MySQL 中运行更新查询?的主要内容,如果未能解决你的问题,请参考以下文章

表数据子集上的递归 CTE

带有子查询的 CTE 查询在小型索引表上很慢;如何在 MySQL 上进行优化?

在 MySQL 中使用 CTE 更新或删除

如何在 MySQL 5 .7 中实现 CTE 功能?

如何使用cte删除mysql中的重复数据

mysql递归查询cte