首先,我必须声明我是一个极端的新手。刚刚使用PHP和MySQL大约4周了。如果我没有正确格式化这个问题或者没有使用正确的艺术条款,请提前接受我的道歉。
我正在构建商店定位器应用程序。为了测试,我有一个名为'locations'的表,其中包含5个不同餐厅连锁店的名称,地址和纬度/经度数据,总共有1500个(位置)记录。
我让应用程序正常运行,作为标准商店定位器,用户输入他们的地址和以英里为单位的距离进行搜索。删除GROUP BY语句时,下面的代码会正确返回这些结果。例如,当用户输入他们的地址和距离进行搜索时,SELECT语句会返回该距离内的所有餐馆。
我的应用要求返回并显示用户指定距离内仅每个连锁餐厅的最近位置。我添加了GROUP BY语句来完成此任务。返回正确的记录数,其中包含正确的loc_name和与用户的距离。但是,所有其他字段永远都不正确。它们似乎是从MIN值以外的其他记录中随机选择的。例如,返回的第一条记录是针对DAIRY QUEEN,距离为4.38英里 - 这是正确的。但是,DAIRY QUEEN在4.38英里的地址,州,城市等不正确。
我已经广泛阅读了GROUP BY的问题以及使用INNER JOIN来解决我的问题的要求? stackoverflow中最近的一个问题和答案非常具体地解决了这个问题,请参阅MySQL Selecting wrong column value in Group By query。到目前为止我读过的所有解决方案都会让我使用计算出的距离作为执行JOIN的键,我不知道这是怎么回事。
问题1:如何构造SELECT语句以获得我想要的结果:位置表中每个连锁店的完整行数据字段?
关于我的代码不那么可怕的注意事项,因为它看起来并没有必要理解解决我的问题:
MIN()中的trig公式计算用户地址(转换为纬度/经度)与每个位置记录的纬度/经度之间的距离(以英里为单位)。相信我,这很好用。
ORDER BY 13语句:表示按SELECT中列出的第13个字段进行ORDER,在这种情况下,它是别名'distance'。我之所以提到这一点是因为我注意到这种语法并不为人所知。
WHERE语句后面的代码检查用户的地址(在lat / lon中)是否位于具有lat / lon角的框中,该角是用户指定的搜索位置距离。这被称为“边界框”。它用于优化搜索时间。可以简单地测试以查看“距离”是否<=比用户输入距离,但是这将需要读取整个位置文件。生产版本将包含大约一百万条记录。位置表的索引是:(loc_lat,loc_lon,loc_id)。我的理解是在WHERE语句中使用Bounding Box将限制需要读取的索引的范围。问题2:这是我实现它的方式,是否按照我的描述进行处理?问题1的解决方案是否会保留优化?
提前感谢大家的帮助。我真的只有4周的时间进入mySQL和PHP,你可以看到,在我脑海里?
我的问题归结为此。如何修改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
答案 0 :(得分:1)
你在四周内走了很长一段路。它有助于包含最少的DDL和INSERT语句,以鼓励更多人做出回应。
我添加了GROUP BY语句 完成这个。正确的数量 记录返回正确 loc_name和用户的距离。 但是,所有其他领域都是 从不纠正。他们似乎随意 从其他记录中选择 超出MIN值。
是的,这对MySQL来说是正常的。文章MySQL Standard Group By解释了这种行为。
不确定的结果集是 一个或多个时返回 SELECT中的非聚合列 子句未列在GROUP BY中 条款。列中列出的列 SELECT子句但从中排除 GROUP BY子句返回无意义 值因为它们是列值 从所有人中不确定地选择 预聚合行。
您需要一个确定的结果集,而不是一个不确定的结果集。该语句应该为您提供一个两列结果集,每个位置名称包含一行。
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,但这是一个pre-caffeine子句,所以我删除了它。
您可能还需要loc_name的索引,因为它在GROUP BY
中使用。请参阅MySQL的EXPLAIN syntax文档。