将带有重复项的 MySQL 表迁移到带有 UNIQUE 约束的另一个表的最佳方法

发布于 2024-09-17 14:22:18 字数 1599 浏览 8 评论 0原文

我正在尝试找出数据迁移的最佳方法。

我正在将一些数据(约 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 表应该为 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 ... ;

来迁移数据。

谢谢!

I am trying to work out the best approach for a data migration.

I am migrating some data (~8000 rows) from a table like this:

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;

to a table like this:

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;

It is not important to preserve the primary key.

The addresses in "location" are duplicated many times. In most cases with the same latitude and longitude. But in SOME cases there are rows with the same value for addr but DIFFERENT values for latitude and longitude.

The final location2 table should have one entry for each unique addr entry in location. Where there is more than one possible value for latitude/longitude the latest (highest location_id) should be used.

I created a procedure to do this but it doesn't like the rows where addr is the same but latitude/longitude are different.

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();

Is there a good way to do this? I keep wanting to give up and write a little PHP prog to do it but I'd rather learn the right SQL way if I can.

Possibly I just need to find the right SELECT from the first table and I can use:

INSERT INTO location2 SELECT ... ;

to migrate the data.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

可可 2024-09-24 14:23:24

您可以直接使用 INSERT IGNORE,或者 REPLACE - 我'我假设这是一个一次性的过程,或者至少是一个性能不是主要考虑因素的过程。

在这种情况下,具有最高 location_id 的记录获胜:

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

具有相同主键值的后续记录将被插入丢弃。

您需要禁用严格的 SQL 模式,否则 addr 字段的截断将给出错误。

You could use INSERT IGNORE directly, or REPLACE - I'm assuming that this is a one-off process, or at least one where performance is not a major consideration.

In this case the record with the highest location_id wins:

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

Subsequent records wit the same primary key value are just discarded by the insert.

You'd need strict SQL mode to be disabled, otherwise the truncation of the addr field will give errors.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文