2015-01-07 2 views
1

Итак, я столкнулся с странной ситуацией, которая не ведет себя вообще так, как я ожидал.Операции обновления с соединением один-ко-многим

Скажем, у меня есть следующие таблицы:

DROP TABLE IF EXISTS test; 
CREATE TABLE test (somekey char(1) PRIMARY KEY, value1 int, value2 int); 

INSERT INTO test VALUES 
("a", 1, 1), 
("b", 2, 2), 
("c", 3, 3); 

DROP TABLE IF EXISTS test2; 
CREATE TABLE test2 (somekey char(1), thing int, value int); 

INSERT INTO test2 VALUES 
("a", 100, 10), 
("a", 200, 10), 
("b", 100, 20), 
("b", 200, 20), 
("c", 100, 30), 
("c", 200, 30); 

А теперь я хочу, чтобы обновить test на основе test2:

UPDATE 
    test AS t 
    JOIN test2 AS t2 
     ON t.somekey = t2.somekey 
SET 
    t.value1 = IF(t2.thing = 100, t2.value, t.value1), 
    t.value2 = IF(t2.thing = 200, t2.value, t.value2); 

Это мой выход:

SELECT * FROM test; 
+---------+--------+--------+ 
| somekey | value1 | value2 | 
+---------+--------+--------+ 
| a  |  10 |  1 | 
| b  |  20 |  2 | 
| c  |  30 |  3 | 
+---------+--------+--------+ 

Для по какой-то причине, value2 не обновляется.

Я обнаружил, что если я изменю test2 так, что 200 вставлен до 100, происходит полная противоположность. Это заставляет меня думать, что MySQL по существу группируется на somekey и полностью игнорирует половину строк в test2. Но если я сделаю то же самое соединение и просто что-то обновить в test2 на основе test, он не выполняет группировку, и все шесть строк в test2 обновляются.

Простое решение заключается в простой присоединиться к test2 в два раза, так как:

UPDATE 
    test AS t 
    JOIN test2 AS t100 
     ON t100.somekey = t.somekey 
     AND t100.thing = 100 
    JOIN test2 AS t200 
     ON t200.somekey = t.somekey 
     AND t200.thing = 200 
SET 
    t.value1 = t100.value, 
    t.value2 = t200.value; 

, но я просто не чувствую, что я должен сделать это таким образом. Что случилось с первым обновлением? Почему MySQL ведет себя таким образом?

ответ

1

При обновлении с помощью JOIN без фильтра (ГДЕ) будет декартовой продукт. В этом случае, поскольку есть две строки из test2 за одну строку test, это означает, что в строке test будет два обновления.

От the Docs:

Каждая соответствующая строка обновляется один раз, даже если он соответствует условиям несколько раз. Для синтаксиса с несколькими таблицами нельзя использовать ORDER BY и LIMIT.

который, насколько я могу видеть, означает, что мы не имеем никакого контроля над каким из 2-х возможных значений строк будет использоваться во время обновления - MySql выбрал вариант value = value.

Ваш второй запрос на обновление определяет только одно возможное значение для test.value1 и test.value2, тем самым устраняя двусмысленность.

+0

Ах, спасибо, что нашли это в документах. По крайней мере, это похоже на намеренное поведение. –

Смежные вопросы