简体   繁体   English

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

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

I have the following working select 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

The table structure looks like the following: 表结构如下所示:

| 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  |

The result of the update statement should be this: 更新语句的结果应为:

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

I want to update option_value with tblfoo with the related data from content from tblbar . 我想更新option_valuetblfoo从相关的数据contenttblbar Unfortunately, tblbar may have multiple entries for the refid with the same value. 不幸的是, tblbar可能有多个具有相同值的refid条目。 This is why there is a need for LIMIT 1 (or GROUP BY t,id or DISTINCT ) with the subquery. 这就是为什么子查询需要LIMIT 1 (或GROUP BY t,idDISTINCT )的原因。

I have figured out, that the query is significant faster, when I do subquery with LIMIT 1 instead of subquery with SELECT DISTINCT or a join in combination with GROUP BY t1.id . 我已经知道,当我使用LIMIT 1进行子查询而不是使用SELECT DISTINCT或与GROUP BY t1.id组合的GROUP BY t1.id进行子查询时,查询速度显着提高。 So after execution time optimization, I ended up with the select statement above. 因此,在执行时间优化之后,我得到了上面的select语句。

There is also a catch with the source table, which should be updated. 源表还有一个问题,应该进行更新。 option_value is a actual field, that also exists in the source table (but with a NULL value). option_value是一个实际字段,也存在于源表中(但具有NULL值)。

The issues I ran into while trying to convert the optimized select statement above into an update statement was mainly that I cannot access t1.id from inside the subquery. 尝试将上面的优化选择语句转换为更新语句时遇到的问题主要是我无法从子查询内部访问t1.id

How to convert the select statement into an update statement without losing the performance optimization? 如何在不损失性能优化的情况下将select语句转换为update语句?

Just use an update join with a subquery which finds distinct values in tblbar : 只需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;

Your correlated subquery can further be optimized by avoid the Left Join between the two tables. 通过避免两个表之间的Left Join ,可以进一步优化您的相关子查询。 Instead, you can directly get the content value from the second table. 相反,您可以直接从第二个表中获取content值。

For updating, you can use your select query as a Derived table, and join it to the source table: 要进行更新,可以将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;

If you are updating all rows, then the most efficient method might be: 如果要更新所有行,则最有效的方法可能是:

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

In particular, this can take advantage of an index on tblbar(refid, content) . 特别是,这可以利用tblbar(refid, content)上的索引。

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

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