2013-08-14 5 views
2

Имеются две таблицы с именем мастера и версии. версии таблица содержит записи мастер таблица в разные моменты времени.Как обновить несколько столбцов на основе значений из связанной таблицы?

------------------------- 
masters 
------------------------- 
id | name | added_at 
----+-------+------------ 
    1 | a-old | 2013-08-13 
    2 | b-new | 2012-04-19 
    3 | c-old | 2012-02-01 
    4 | d-old | 2012-12-24 

Гарантируется, что существует по крайней мере одинверсии запись для каждого из мастеров запись.

--------------------------------------------- 
versions 
--------------------------------------------- 
id | name | added_at | notes | master_id 
----+-------+-------------------------------- 
    1 | a-new | 2013-08-14 | lorem |   1 
    1 | a-old | 2013-08-13 | lorem |   1 
    2 | b-new | 2012-04-19 | lorem |   2 
    3 | c-old | 2012-02-01 | lorem |   3 
    4 | d-new | 2013-02-20 | lorem |   4 
    5 | d-old | 2012-12-24 | lorem |   4 

Таблицы также можно найти в этом SQL Fiddle.
последняя версии каждого мастер записи может быть выбрана, как показан в этом примере для мастеров рекордных 2:

SELECT * FROM versions 
WHERE master_id = 2 
ORDER BY added_at DESC 
LIMIT 1; 

Как я могу обновить каждую запись из мастеров таблицы его последниеверсия в одна команда? Я хочу переписать значения как для столбцов name, так и для added_at. Обратите внимание, что есть дополнительные столбцы в версии таблицы, которых нет в таблице , такой как notes.

Может ли обновление выполнить с помощью JOIN, чтобы оно выполнялось быстро на больших таблицах?

ответ

1

Там нет необходимости стрелять подзапрос дважды.

Ниже приводится заявление обновления

update masters m, (
    select id, name, added_at, master_id 
    from versions 
    order by added_at desc 
) V 
set 
    m.name = v.name, 
    m.added_at = v.added_at  
where v.master_id = m.id; 
+0

Я удалил детали, соответствующие конкретному '..id = 2'. Запустив ваш пример, вы пропустили обновление строки * master * с 'id' =' 4', 'd-old' по какой-то причине. – JJD

+1

Теперь проверьте [эту ссылку] (http://sqlfiddle.com/#!2/e56eb9/1). если его правильно, то я изменю сообщение – Romesh

+0

Выглядит неплохо. Кажется, он также работает с дополнительными столбцами, поскольку я представил их на мой вопрос тем временем. Обновите свой ответ. Btw: Типо в «Fiddel». – JJD

0

Не можете проверить его на MySQL прямо сейчас, но это должно работать на MSSQL

UPDATE masters AS m 
SET 
    m.name = 
    (SELECT v.Name FROM versions AS v WHERE v.id = m.id AND v.added_at = 
    (SELECT MAX(v2.added_at) FROM versions As v2 WHERE v2.id = v.id)) 
    m.added_at = 
    (SELECT v.added_at FROM versions AS v3 WHERE v3.id = m.id AND v3.added_at = 
    (SELECT MAX(v4.added_at) FROM versions As v4 WHERE v4.id = v3.id)) 
+0

Я хотел бы избежать запуска отдельного 'заявления SELECT' для каждого отдельного столбца. – JJD

1

Это может делать то, что вам нужно:

REPLACE INTO masters 
    SELECT v.master_id,v.name,v.added_at 
    FROM versions v 
    WHERE v.added_at = (SELECT MAX(vi.added_at) 
         FROM versions vi 
         WHERE vi.master_id = v.master_id); 

Обратите внимание, что это зависит от мастеров, имеющих первичные ключ на id и является специфичным для MySQL.

+0

Это создает дубликаты в таблице * мастеров *. – JJD

+1

@JJD В таблице мастеров есть первичный ключ? Я отметил, что это не будет работать без него. – Jim

+0

Спасибо! Я добавил «ПЕРВИЧНЫЙ КЛЮЧ» в SQL Fiddle. – JJD

0
update masters set 
name = (SELECT name FROM versions 
     WHERE master_id = masters.id 
     ORDER BY added_at DESC 
     LIMIT 1), 
added_at = (SELECT added_at FROM versions 
     WHERE master_id = masters.id 
     ORDER BY added_at DESC 
     LIMIT 1) 
where id = 2; 
+0

Я хотел бы избежать запуска отдельных операторов SELECT для каждого отдельного столбца. – JJD

0

Это может работать для вас, попробуйте следующее:

UPDATE masters m 
SET m.name = (SELECT v.name FROM versions v WHERE 
m.id = v.master_id ORDER BY v.added_at DESC LIMIT 1), 
m.added_at = 
(SELECT v.added_at FROM versions v WHERE m.id = v.master_id ORDER BY 
v.added_at DESC LIMIT 1); 
+0

Я хотел бы избежать запуска отдельных операторов SELECT для каждого отдельного столбца. – JJD

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