PostgreSQL UPDATE子查询返回多行报错如何修改获取单条记录
问题背景
需要更新VIDEO_TAGS表数据,该表共包含3个字段:fk_video_id、principal(非重要字段)、tag_value。
原计划执行的更新语句如下:
UPDATE VIDEO_TAGS SET tag_value= :newTag where tag_value= :oldTag and fk_video_id = (SELECT FROM VIDEO_TAGS fk_video_id where tag_value= :productName)
执行时触发more than one row returned by a subquery used as an expression(用作表达式的子查询返回多行)错误,原因为等值匹配(=)仅支持右侧传入单个值,但当前子查询会返回多条结果。
问题根因
- 子查询存在基础语法错误:要查询的字段
fk_video_id被错写在表名位置,正确写法应为SELECT fk_video_id FROM VIDEO_TAGS - 等值运算符
=要求右侧子查询必须返回单个标量值,当存在多个视频都绑定了值为:productName的标签时,子查询会返回多个fk_video_id,直接触发报错
修改方案
根据实际业务需求二选一即可:
方案1:批量更新所有匹配视频的标签(绝大多数场景适用)
如果你的业务目标是:把所有打了:productName标签的视频下,值为:oldTag的标签统一更新为:newTag,不需要强制限制单条,直接把等值匹配=换成多值匹配IN即可,修正后SQL如下:
UPDATE VIDEO_TAGS SET tag_value = :newTag WHERE tag_value = :oldTag AND fk_video_id IN ( SELECT fk_video_id FROM VIDEO_TAGS WHERE tag_value = :productName )
方案2:仅更新单条匹配的视频标签
如果业务逻辑确认只需要更新其中1个视频对应的标签,需要给子查询追加条数限制,确保子查询仅返回1个fk_video_id。
以MySQL/PostgreSQL为例的写法:
UPDATE VIDEO_TAGS SET tag_value = :newTag WHERE tag_value = :oldTag AND fk_video_id = ( SELECT fk_video_id FROM VIDEO_TAGS WHERE tag_value = :productName -- 建议加明确排序规则,避免返回不确定的记录,排序字段可根据业务调整 ORDER BY fk_video_id ASC LIMIT 1 )
不同数据库的单条限制语法有区别:SQL Server需要将
LIMIT 1替换为TOP 1写在SELECT关键字后;Oracle需要将LIMIT 1替换为FETCH FIRST 1 ROW ONLY写在子查询WHERE条件末尾。
注意事项
- 不要不加排序直接写
LIMIT 1,这种写法返回的记录没有确定性,很容易更新错目标数据 - 如果业务上规定
:productName标签只会绑定1个视频,说明当前表内已经存在脏数据,建议先单独执行子查询排查重复记录,确认数据逻辑后再做更新
内容的提问来源于stack exchange,提问作者Fatima
相关产品推荐
相关产品推荐

