MySQL 在商店定位器-Google map 应用程序的分组查询中选择错误的列值

标签 mysql group-by geolocation query-optimization aggregate-functions

首先我必须声明我是一个极端的新手。现在刚刚使用 PHP 和 MySQL 大约 4 周。如果我没有正确地格式化这个问题或者没有使用正确的艺术术语,请提前接受我的歉意。

我正在构建一个商店定位器应用程序。为了进行测试,我有一个名为“位置”的表,其中包含 5 家不同链式餐厅的名称、地址和纬度/经度数据,总共 1500 条(位置)记录。

我让应用程序作为标准商店定位器运行良好,用户输入他们的地址和以英里为单位的距离进行搜索。当删除 GROUP BY 语句时,下面的代码可以正确返回这些结果。例如,当用户输入地址和距离进行搜索时,SELECT 语句会返回该距离内的所有餐馆。

我的应用要求仅返回并显示用户指定距离内每个链式餐厅的最近位置。我添加了 GROUP BY 语句来完成此任务。返回正确的记录数以及正确的 loc_name 和与用户的距离。然而,所有其他字段永远都不正确。它们似乎是从 MIN 值之外的其他记录中随机选择的。例如,返回的第一条记录是距离 4.38 英里的 DAIRY QUEEN - 正确。但是,距离 4.38 英里的 DAIRY QUEEN 的地址、州、城市等不正确

我已经阅读了大量有关 GROUP BY 的问题以及使用 INNER JOIN 的要求也许可以解决我的问题? stackoverflow 中最近的一个问答非常具体地解决了这个问题,请参阅 MySQL Selecting wrong column value in Group By query 。到目前为止,我读过的所有解决方案都让我使用计算出的距离作为执行 JOIN 的关键,但我不明白这是怎么可能的。

问题 1:如何构造 SELECT 语句以获得所需的结果:位置表中仅针对每个链式餐厅的完整数据字段行?

关于我的代码的注释,它不像看起来那么可怕,并且不需要理解即可解决我的问题:

MIN() 中的三角公式计算用户地址(转换为纬度/经度)与每个位置记录的纬度/经度之间的距离(以英里为单位)。相信我,这工作正常。

ORDER BY 13 语句:表示按 SELECT 中列出的第 13 个字段进行 ORDER,在本例中是别名“distance”。我提到这一点是因为我注意到这种语法并不为人所知。

WHERE 语句后面的代码检查用户的地址(以纬度/经度为单位)是否位于具有纬度/经度角的框中,这些角是用户指定的要搜索位置的距离。这称为“边界框”。它用于优化搜索时间。人们可以简单地测试“距离”是否小于用户输入的距离,但这需要读取整个位置文件。生产版本将包含大约一百万条记录。位置表有一个索引:(loc_lat,loc_lon,loc_id)。我的理解是,在WHERE语句中使用Bounding Box会限制需要读取的索引的范围。问题2:我的实现方式是这样吗,会按照我描述的方式进行处理吗?问题1的解决方案会保留优化吗?

提前感谢大家的帮助。我真的才刚接触 mySQL 和 PHP 4 周,正如你所看到的,这超出了我的理解范围?

<小时/>

我的问题归结为这一点。应该如何修改此 SELECT 以仅返回 1 个位置表记录,其中每个 loc_name 都有相应的字段,即距用户输入地址的最小距离?

SELECT loc_id,loc_name,loc_address_1,loc_address_2,loc_city,
       loc_state,loc_postal_code,loc_phone,loc_fax,
       loc_lat,loc_lon,loc_geocoded_status,
       MIN( ((ACOS( SIN( $lat * PI( ) /180 ) * SIN( loc_lat * PI( ) /180 ) + 
               COS( $lat * PI( ) /180 ) * COS( loc_lat * PI( ) /180 ) *
               COS( ($long - loc_lon) * PI( ) /180 ) ) *180 / PI( )) *60 * 1.1515) )
       AS distance  
FROM locations WHERE (loc_lat between $lat1 and $lat2
                  AND loc_lon between $lon1 and $lon2)
                  AND loc_geocoded_status = 1
GROUP BY loc_name
ORDER BY 13

最佳答案

四个星期内你已经取得了长足的进步。它有助于包含最少的 DDL 和 INSERT 语句,以鼓励更多人做出响应。

I added the GROUP BY statement to accomplish this. The correct number of records are returned with the correct loc_name and distance from the user. However, all of the other fields are never correct. They seem randomly selected from other records that are outside of the MIN value.

是的,这对于 MySQL 来说是正常的。文章MySQL Standard Group By解释了这种行为。

An indeterminate result set is returned when one or more non-aggregated columns in a SELECT clause aren’t listed in the GROUP BY clause. The columns listed in the SELECT clause but excluded from the GROUP BY clause return meaningless values because they’re column values chosen indeterminately from all pre-aggregated rows.

您需要一个确定的结果集,而不是不确定的结果集。此语句应该为您提供一个两列结果集,其中每个位置名称包含一行。

SELECT loc_name, MIN( ((ACOS( . . . ) AS distance  
FROM locations
GROUP BY loc_name

您应该能够使用该语句以及位置名称和距离上的 JOIN 表达式来获取您需要的其他列。

我将算术包装在名为“distance”的函数中,然后

SELECT L1.*, C.*
FROM locations L1
INNER JOIN (SELECT L2.loc_name, 
                   MIN(distance($lat, $lon, 
                                L2.loc_lat, L2.loc_lon)) AS distance
            FROM locations L2
            GROUP BY L2.loc_name) C
ON   L1.loc_name = C.loc_name
 AND C.distance  = distance($lat, $lon, 
                          L1.loc_lat, L1.loc_lon)

您需要添加边界框信息。当我试图确保 JOIN 正常工作时,我忽略了它。我在内部 SELECT 子句中有一个不必要的 ORDER BY,但那是一个前咖啡因子句,所以我删除了它。

您可能还需要 loc_name 上的索引,因为它在 GROUP BY 中使用。请参阅 MySQL 的文档 EXPLAIN syntax .

关于MySQL 在商店定位器-Google map 应用程序的分组查询中选择错误的列值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4840230/

相关文章:

android - locationListener 只被调用一次

python - 用于根据提交的字符串推断国家/地区的库或 API?

geolocation - Lucene.net 邻近搜索

c# - 无法连接到任何指定的 MySql 主机远程数据库

mysql - 使用 MySQL 作为作业队列

mysql - 为什么在特定日期创建的 WP_User 数量中返回的记录很少

使用 group by 进行 SQL Server 更新

mysql - 使用 TFDConnection 以编程方式设置 "Server"

mysql - 为什么这两个看似相似的 MySQL 查询返回完全不同的结果?

mysql - SQL group by 按列分组内的自定义分组集