我目前使用的mySQL数据库有两个表:一个称为source,另一个称为siteinfo

siteinfo表如下所示:

+-----------+----------+----------+
| longitude | latitude | sitecode |
+-----------+----------+----------+
|    1.3009 | 1.900989 |        2 |
+-----------+----------+----------+
|    1.7034 | 1.20034  |        3 |
+-----------+----------+----------+


同样,源表如下所示:

+-----------+----------+----------+
| longitude | latitude | sitecode |
+-----------+----------+----------+
|    1.3009 | 1.900989 |   NULL   |
+-----------+----------+----------+


我的基本目标是:

对于source表中的每一行,我要使用名为经度和纬度的列,并将它们与siteinfo表中相应的经度和纬度列进行比较。

在源表中,长行和纬度行与siteinfo表中的行最相似的那些行,然后将sitecode列更新为sitecode表中sitecode列的相应siteinfo

例如,源表中的long和lat值与siteinfo表的第一行中的值最接近,因此sitecode被更新为2。

为了解决这个问题,我知道我必须创建两个ResultSet并使用while(next())遍历每个结果集的每一行。问题是,如何比较才能找到最相似的条目?

我考虑过使用蛮力,使用For循环将Source Resultset的第一行条目与Siteinfo Resultset的每一行进行比较,然后递增到第二行。

但是,我了解next()函数对每一行进行迭代的结果集工作,这与for循环不同,因为我想将一个结果集的第一行与另一结果集的每一行进行比较。

其次,如何找到两个结果表的列条目的区别?

最佳答案

不,您不必创建两个结果集。您可以只创建一个MySQL函数来计算两点之间的Great Circle Distance ...



CREATE FUNCTION great_circle_km (lon1 DOUBLE, lat1 DOUBLE, lon2 DOUBLE, lat2 DOUBLE)
RETURNS DOUBLE
RETURN 6371 * acos(cos(radians(lat1)) * cos(radians(lat2)) * cos(radians(lon2) - radians(lon1)) + sin(radians(lat1)) * sin(radians(lat2)))


...然后像这样使用UPDATE查询

UPDATE `source` SET `source`.`sitecode` = (
    SELECT `sitecode` FROM `siteinfo`
    ORDER BY great_circle_km(`source`.`longitude`, `source`.`latitude`, `siteinfo`.`longitude`, `siteinfo`.`latitude`)
    LIMIT 1
    )


请注意,以上查询将执行CROSS JOIN(笛卡尔积)的等效操作,因此对于较大的源表,处理的有效行数将急剧增加。例如,使用两个500行表将有效处理250,000行,而使用两个5,000行表将有效处理25,000,000行。

如果表之间存在大量精确匹配,那么首先更新它们可能会更快。

UPDATE
    `source`
    INNER JOIN
    `siteinfo`
        ON `source`.`longitude` = `siteinfo`.`longitude`
            AND `source`.`latitude` = `siteinfo`.`latitude`
SET `source`.`sitecode` = `siteinfo`.`sitecode`


...然后更新剩余的行

UPDATE `source` SET `source`.`sitecode` = (
    SELECT `sitecode` FROM `siteinfo`
    ORDER BY great_circle_km(`source`.`longitude`, `source`.`latitude`, `siteinfo`.`longitude`, `siteinfo`.`latitude`)
    LIMIT 1
    )
WHERE `source`.`sitecode` IS NULL

08-04 16:21