Как обновить одну таблицу на основе значений другой таблицы на лету?

41

У меня есть таблица на имя ips, как показано ниже:

CREATE TABLE `ips` (
 `id` int(10) unsigned NOT NULL DEFAULT '0',
 `begin_ip_num` int(11) unsigned DEFAULT NULL,
 `end_ip_num` int(11) unsigned DEFAULT NULL,
 `iso` varchar(3) DEFAULT NULL,
 `country` varchar(150) DEFAULT NULL
) ENGINE=InnoDB

Предположим, у меня есть countryidполе в этой таблице из таблицы стран, как показано ниже:

CREATE TABLE `country` (
 `countryid` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
 `ordering` smallint(5) unsigned NOT NULL DEFAULT '0',
 `iso` char(2) NOT NULL,
 PRIMARY KEY (`countryid`)
) ENGINE=InnoDB

В таблице ips около 100 000 записей. Есть ли запрос для следующего сценария:
Проверьте, ips.isoравен country.isoли он, равен ли он, то добавьте country.coutryid к этой записи. Я не мог придумать, как это сделать. У вас есть идеи, как это сделать?

ALH
источник

Ответы:

73
UPDATE ips INNER JOIN country
    ON ips.iso = country.iso
SET ips.countryid = country.countryid

Используя MySQL, обновите синтаксис нескольких таблиц:

14.2.11 Синтаксис ОБНОВЛЕНИЯ

Обратите внимание, что у вас есть две разные длины и типы данных в ваших столбцах iso. На самом деле существует два отдельных набора кодов ISO, двухбуквенный и трехбуквенный, поэтому в действительности вы не сможете присоединиться к этим столбцам:

ISO 3166-1

Условие соединения USING (iso)вместо того, чтобы ON ips.iso = country.isoработать тоже.

Кейд Ру
источник
Вы гений, вы ответили, сэкономили мое время
Хамфри
Меня удивляет, как мало кода необходимо для выполнения этого действия!
Мэтт Кременс
32

Решение @Cade Roux дает мне синтаксическую ошибку, правильная для mysql 5.5.29:

UPDATE ips 
INNER JOIN country
    ON ips.iso = country.iso
SET ips.countryid = country.countryid

без ключевого слова "ОТ".

linuxatico
источник
1
С тех пор это было исправлено, кажется ...
rogerdpack
10

Этот синтаксис может быть лучше читаемым

UPDATE country p, ips pp
SET pp.countryid = p.countryid
WHERE pp.iso = p.iso
SebastianLasse
источник
4

спасибо @Cade, но я нашел для этого простое решение:

update ips set countryid=(select countryid from country where ips.iso=country.iso )
ALH
источник
5
В моей версии есть различие в поведении - ваша версия установит его в NULL, если он не найден, мой не изменит существующее значение, если оно не найдено. Это может или не может быть желательным. Также план выполнения может отличаться в зависимости от оптимизатора.
Cade Roux
@ CadeRoux Я не думал о NULL части, спасибо.
ALH
1
@ john.locke Это, вероятно, не проблема - когда вы добавляете новый столбец, я предполагаю, что он будет иметь значение NULL, а также внешний ключ, поэтому недопустимые записи в любом случае не будут разрешены. Но из того, что было явно указано в вашем вопросе, трудно судить.
Cade Roux