Лучший способ перенести таблицу MySQL с дубликатами в другую таблицу с ограничением UNIQUE - PullRequest
2 голосов
/ 03 сентября 2010

Я пытаюсь выработать наилучший подход для миграции данных.

Я перенесу некоторые данные (~ 8000 строк) из таблицы следующим образом:

CREATE TABLE location (
    location_id INT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
    addr VARCHAR(1000) NOT NULL,
    longitude FLOAT(11),
    latitude FLOAT(11)
) Engine = InnoDB, DEFAULT CHARSET=UTF8;

к столу вроде этого:

CREATE TABLE location2 (
    location_id INT NOT NULL AUTO_INCREMENT UNIQUE PRIMARY KEY,
    addr VARCHAR(255) NOT NULL UNIQUE,
    longitude FLOAT(11),
    latitude FLOAT(11)
) Engine = InnoDB, DEFAULT CHARSET=UTF8;

Не важно сохранять первичный ключ.

Адреса в «локации» дублируются много раз. В большинстве случаев с одинаковой широтой и долготой. Но в НЕКОТОРЫХ случаях есть строки с одинаковым значением для addr, но с РАЗНЫМИ значениями для широты и долготы.

В итоговой таблице location2 должна быть одна запись для каждой уникальной записи addr в location. При наличии более одного возможного значения широты / долготы следует использовать самое последнее (самый высокий location_id).

Я создал процедуру для этого, но ей не нравятся строки, в которых addr одинаков, но широта / долгота разные.

DROP PROCEDURE IF EXISTS migratelocation;
DELIMITER $$
CREATE PROCEDURE migratelocation()
BEGIN
    DECLARE done INT DEFAULT 0;
    DECLARE a VARCHAR(255);
    DECLARE b, c FLOAT(11);
    DECLARE cur CURSOR FOR SELECT DISTINCT addr, latitude, longitude FROM location;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
    OPEN cur;
    REPEAT
        FETCH cur INTO a, b, c;
        IF NOT done THEN
            INSERT INTO location2 (addr, latitude, longitude) VALUES (a, b, c);
        END IF;
    UNTIL done END REPEAT;
    CLOSE cur;
END $$
DELIMITER ;
CALL migratelocation();

Есть ли хороший способ сделать это? Я продолжаю хотеть сдаться и написать небольшую прогу PHP, чтобы сделать это, но я бы лучше выучил правильный способ SQL, если смогу.

Возможно, мне просто нужно найти правильный SELECT из первой таблицы, и я могу использовать:

INSERT INTO location2 SELECT ... ;

для переноса данных.

Спасибо!

1 Ответ

4 голосов
/ 03 сентября 2010

Вы можете использовать INSERT IGNORE напрямую или REPLACE - я предполагаю, что это одноразовый процесс или, по крайней мере, тот, в котором производительность не является основным фактором.

В этом случае запись с наибольшим значением location_id выигрывает:

INSERT IGNORE
INTO   location2
SELECT *
FROM   location
ORDER BY
       location_id DESC

Последующие записи с тем же значением первичного ключа просто отбрасываются вставкой.

Вам нужен строгий режим SQL, чтобыотключено, в противном случае усечение поля addr приведет к ошибкам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...