Как преобразовать оператор выбора MySQL с подзапросом в ту же таблицу в оператор обновления?

0

У меня есть следующее рабочее предложение выбора.

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  |

Результат оператора update должен быть таким:

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

Я хочу обновить option_value с помощью tblfoo используя связанные данные из content из tblbar. К сожалению, tblbar может иметь несколько записей для refid с одинаковым значением. Вот почему существует необходимость в LIMIT 1 (или GROUP BY t,id или DISTINCT) с подзапросом.

Я выяснил, что запрос значительно быстрее, когда я делаю подзапрос с LIMIT 1 вместо подзапроса с SELECT DISTINCT или объединение в сочетании с GROUP BY t1.id Так что после оптимизации времени выполнения я закончил с утверждением select выше.

Есть также улов с исходной таблицей, которая должна быть обновлена. option_value - фактическое поле, которое также существует в исходной таблице (но со значением NULL).

Проблемы, с которыми я столкнулся при попытке преобразовать оптимизированный оператор выбора выше в оператор обновления, были главным образом в том, что я не могу получить доступ к t1.id из подзапроса.

Как преобразовать оператор выбора в оператор обновления, не теряя при этом оптимизации производительности?

  • 1
    Какие таблицы / столбцы обновляются с какими данными?
  • 0
    В подзапросе, почему вы присоединяетесь к table2 и table3; Я считаю, что вы можете напрямую использовать table3
Показать ещё 4 комментария
Теги:
sql-update
subquery

3 ответа

2
Лучший ответ

Просто используйте объединение обновлений с подзапросом, который находит различные значения в tblbar:

UPDATE tblfoo f
INNER JOIN
(
    SELECT DISTINCT refid, content
    FROM tblbar
) b
    ON f.id = b.refid
SET f.option_value = b.content;
  • 0
    спасибо, ваш SQL работает, но с одним изменением: это SET f.content = b.option_value; , Можете ли вы обновить свой ответ? Тогда я могу принять это :)
  • 0
    @burnersk На самом деле мой ответ кажется правильным, основываясь на таблицах, которые вы нам показали. Если нет, то обновите свой вопрос.
Показать ещё 1 комментарий
1

Ваш коррелированный подзапрос может быть дополнительно оптимизирован, избегая 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;
  • 1
    Ваше обновление заявления работает. Однако версия @TimBiegeleisen работает быстрее (1 минута против 10 минут)
  • 0
    @burnersk да, Тим оптимизировал дальше. Я не оптимизировал ваш исходный запрос в целом; просто часть подзапроса.
0

Если вы обновляете все строки, то наиболее эффективным методом может быть:

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

В частности, это может использовать индекс tblbar(refid, content).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню