MySQL 错误 1242 - 子查询 returns 多于 1 行

MySQL error 1242 - Subquery returns more than 1 row

我在具有以下结构的数据库中有两个 table:

table 1:3 行 - category_id、product_id 和位置

table 2:3 行 - category_id、product_id 和位置

我正在尝试将 table 1 个位置设置为 table 2 个位置,其中类别和产品 ID 与 table 相同。

下面是 sql 我试图做到这一点但是 returns MySQL 错误 1242 - 子查询 returns 超过 1 行

UPDATE table1 
SET position = (
    SELECT position 
    FROM table2 
    WHERE table1.product_id = table2.product_id AND table1.category_id = table2.category_id
)

您可以运行这个查询来查看发生了什么:

SELECT product_id, category_id, count(*), min(position), max(position)
FROM table2
GROUP BY product_id, category_id
HAVING COUNT(*) > 1;

这将为您提供在 table2 中多次出现的 product_idcategory_id 对的列表。然后你可以决定做什么。您想要 position 的任意值吗? position 的值总是一样的吗?您需要修复 table 吗?

使用 limit 1 或聚合函数很容易解决特定问题。但是,您可能真的需要修复 table 中的数据。修复看起来像:

UPDATE table1 t1
    SET t1.position = (SELECT t2.position 
                       FROM table2  t2
                       WHERE t2.product_id = t1.product_id AND t2.category_id = t1.category_id
                       LIMIT 1
                      );

解决方法非常简单,只需简单两步即可完成。第一步只是预览将要更改的内容,以避免破坏数据。如果您对 WHERE 子句有信心,可以跳过它。

第 1 步:预览更改

使用您要匹配的字段加入 tables,select 一切用于匹配的视觉验证。

SELECT t1.*, t2.*
FROM table1 t1
    INNER JOIN table2 t2
        ON t1.category_id = t2.category_id
        AND t1.product_id = t2.product_id

如果只有部分行必须修改,您还可以添加 WHERE 子句。

第 2 步:进行实际更新

SELECT子句和FROM关键字替换为UPDATE,在其所属的地方添加SET子句。保留 WHERE 子句:

UPDATE table1 t1
    INNER JOIN table2 t2
        ON t1.category_id = t2.category_id
        AND t1.product_id = t2.product_id
SET t1.position = t2.position

就这些了。

技术考虑

当 table 的行数超过数百行时,两个 table 的 JOIN 子句中使用的列的索引是必须的。如果查询没有 WHERE 条件,则 MySQL 将仅对最大的 table 使用索引。 WHERE 条件中使用的字段索引将加快查询速度。将 EXPLAIN 添加到 SELECT 查询以检查执行计划并决定您需要哪些索引。

您可以添加 SORT BYLIMIT 以使用 WHERE 无法实现的标准进一步减少已更改行的集合(例如,只有最多 recent/oldest 100 行等)。首先将它们放在 SELECT 查询中以验证结果,然后将 SELECT 变形为 UPDATE,如所述。 当然,SORT BY 子句中使用的列的索引是必须的。