MySQL跨表按名称更新tags列报错,用ID匹配正常求解决方案
错误原因
- 用
name关联的子查询报错,是因为products表中存在多个记录共享同一个name值,导致子查询返回了多行结果。而UPDATE语句的SET子句要求赋值的子查询必须返回唯一单行值,因此触发Subquery returns more than 1 row错误。 - 用
id关联能正常执行,核心原因是id是表的唯一主键(或带唯一约束的字段),每个id在products表中只会匹配到一行记录,子查询始终返回单行值,完全符合UPDATE的语法要求。
符合需求的正确写法
根据按name或slug匹配同步tags的诉求,结合不同业务场景,提供以下可行方案:
方案1:JOIN式更新(推荐,逻辑清晰)
用JOIN关联两张表直接匹配更新,写法更直观:
UPDATE product p INNER JOIN products ps ON p.name = ps.name OR p.slug = ps.slug SET p.tags = ps.tags;
提醒:如果
name或slug在products表中对应多条记录,这条语句会让product的tags被最后匹配到的行覆盖。若要避免这种情况,可先对products表做去重处理,或使用下面的聚合方案。
方案2:合并所有匹配的tags
如果需要把products表中所有匹配name/slug的tags合并到product对应行(比如用逗号分隔),可使用聚合函数(以MySQL为例):
UPDATE product p SET p.tags = ( SELECT GROUP_CONCAT(DISTINCT ps.tags SEPARATOR ',') FROM products ps WHERE p.name = ps.name OR p.slug = ps.slug );
这里的
DISTINCT用来过滤重复的tags,SEPARATOR可根据需求替换成其他分隔符(比如分号)。
方案3:只取匹配到的第一条记录的tags
如果业务逻辑允许只取products表中匹配的第一条记录的tags,可给子查询加上LIMIT 1:
UPDATE product p SET p.tags = ( SELECT ps.tags FROM products ps WHERE p.name = ps.name OR p.slug = ps.slug ORDER BY ps.id DESC -- 可根据需求排序,比如取最新的一条 LIMIT 1 );
注意:必须加上
ORDER BY子句明确取数逻辑,否则LIMIT 1返回的结果是随机的,可能不符合预期。
内容的提问来源于stack exchange,提问作者Malik Presentations
相关产品推荐
相关产品推荐

