繁体   English   中英

如何将带有子查询的MySQL select语句转换为同一表的更新语句?

[英]How to convert a MySQL select statement with a subquery to the same table into an update statement?

我有以下工作选择语句。

SELECT t1.id, t1.option_key, ( 
    SELECT
        t3.content AS option_value
    FROM tblfoo t2
    LEFT OUTER JOIN tblbar t3 ON( t3.refid = t2.id )
    WHERE t2.id = t1.id
    LIMIT 1
) AS option_value
FROM tblfoo t1

表结构如下所示:

| tblfoo                         |
+----+------------+--------------+
| id | option_key | option_value |
+----+------------+--------------+
|  1 | foo        | NULL         |
|  2 | bar        | NULL         |
|  3 | baz        | NULL         |


| tblbar               |
+----+-----------------+
| id | refid | content |
+----+-----------------+
|  1 |     1 | value1  |
|  1 |     2 | value2  |
|  1 |     3 | value3  |

更新语句的结果应为:

| tblfoo                         |
+----+------------+--------------+
| id | option_key | option_value |
+----+------------+--------------+
|  1 | foo        | value1       |
|  2 | bar        | value2       |
|  3 | baz        | value3       |

我想更新option_valuetblfoo从相关的数据contenttblbar 不幸的是, tblbar可能有多个具有相同值的refid条目。 这就是为什么子查询需要LIMIT 1 (或GROUP BY t,idDISTINCT )的原因。

我已经知道,当我使用LIMIT 1进行子查询而不是使用SELECT DISTINCT或与GROUP BY t1.id组合的GROUP BY t1.id进行子查询时,查询速度显着提高。 因此,在执行时间优化之后,我得到了上面的select语句。

源表还有一个问题,应该进行更新。 option_value是一个实际字段,也存在于源表中(但具有NULL值)。

尝试将上面的优化选择语句转换为更新语句时遇到的问题主要是我无法从子查询内部访问t1.id

如何在不损失性能优化的情况下将select语句转换为update语句?

只需tblbar查询使用update join即可在tblbar找到不同的值:

UPDATE tblfoo f
INNER JOIN
(
    SELECT DISTINCT refid, content
    FROM tblbar
) b
    ON f.id = b.refid
SET f.option_value = b.content;

通过避免两个表之间的Left Join ,可以进一步优化您的相关子查询。 相反,您可以直接从第二个表中获取content值。

要进行更新,可以将select查询用作派生表,并将其联接到源表:

UPDATE tblfoo AS tfoo 
JOIN (
      SELECT t1.id, 
             (SELECT t3.content AS option_value
              FROM tblbar t3
              WHERE t3.refid = t1.id
              LIMIT 1
             ) AS option_value
      FROM tblfoo t1
     ) AS dt ON dt.id = tfoo.id 
SET tfoo.option_value = dt.option_value;

如果要更新所有行,则最有效的方法可能是:

UPDATE tblfoo f
    SET f.option_value = (SELECT b.content FROM tblbar WHERE f.id = b.refid LIMIT 1);

特别是,这可以利用tblbar(refid, content)上的索引。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM