1 Востаннє редагувалося ailkiv (27.07.2015 13:02:14)

Тема: Mysql multi update, важливий нюанс

Важлива інформація, яка врятує вас від потенційного підступного багу в вашій системі.
Якщо ви раптом захотіли виконати подібний запит:

UPDATE foo JOIN bar ON foo.id = bar.id SET foo.cnt = foo.cnt + bar.cnt

І зв'язок foo до bar як один до багатьох

Майте на увазі що він робить для кожного foo.id не більше одного оновлення, навіть коли є декілька відповідних ключів bar.id

Підтвердження: https://dev.mysql.com/doc/refman/5.5/en/update.html

For the multiple-table syntax, UPDATE updates rows in each table named in table_references that satisfy the conditions. Each matching row is updated once, even if it matches the conditions multiple times. For multiple-table syntax, ORDER BY and LIMIT cannot be used.

2

Re: Mysql multi update, важливий нюанс

Ну взагалі то, з самого початку невірно приєднувати таблицю з відношенням один до багатьох, при цьому оновлюючи таблицю з меншою кількістю значень.

3

Re: Mysql multi update, важливий нюанс

ktretyak написав:

Ну взагалі то, з самого початку невірно приєднувати таблицю з відношенням один до багатьох, при цьому оновлюючи таблицю з меншою кількістю значень.

Чому?

4

Re: Mysql multi update, важливий нюанс

Давайте візьмемо конкретний приклад, нехай у нас у перші таблиці буде один запис, у другій - п'ять записів. Ми з'єднуємо ці таблиці, і намагаємось оновити першу таблицю. Само собою що результат буде невизначеним. Не знаю як ще більш очевидно це показати.

5

Re: Mysql multi update, важливий нюанс

У прикладі, який я навів все цілком логічно і визначено). Але MySQL так робити не дозволяє

6

Re: Mysql multi update, важливий нюанс

Давайте створимо таблиці як у вашому прикладі

drop temporary table if exists foo;
drop temporary table if exists bar;

create temporary table foo(id int, cnt int);
create temporary table bar(id int, cnt int);

insert into foo values(1, 2);
insert into bar values(1, 3), (1, 4), (9, 5);

select
    foo.cnt as cnt_from
    ,bar.cnt as cnt_to
    ,foo.cnt + bar.cnt as result
from foo
    join bar
        on foo.id = bar.id

В результаті виведеться

"cnt_from"    "cnt_to"    "result"
"2"           "3"      "5"
"2"           "4"      "6"

Тобто у полі cnt_from йде значення з першої таблиці, а у полі cnt_to - значення з другої таблиці. В даному випадку початкове значення 2 з першої таблиці припадає два значення 3 та 4 з другої таблиці.

Коли ви робите таке з'єднання таблиць, то де ви бачите логіку? Яким значенням оновлювати першу таблицю?

7

Re: Mysql multi update, важливий нюанс

Так все дуже логічно. Я читаю запит update, так...
До результату вибірки застосувати все те що міститься в у блоці SET

Тобто у голові уявляю що спочатку робиться select, такий як ви навели, а потім проходжуся по ньому циклом і роблю foo.cnt = foo.cnt + bar.cnt

8

Re: Mysql multi update, важливий нюанс

Якщо дуже логічно, то можна однозначно відповісти на питання - який результат ставити в першу таблицю, 3 чи 4?

Я кажу що це точно не логічно, бо результат таки не визначений. Він буде визначеним при зв'язці один до одного або якщо ми зв'язуємось "один до багатьох" і при цьому оновлюємо таблицю з більшою кількістю результатів.

9

Re: Mysql multi update, важливий нюанс

Ви не читаєте те що я пишу.

З тієї логіки, яку я описав вище випливає очевидний результат: 9