0

首先我必須聲明我是一個極端的新手。現在剛剛使用PHP和MySQL大約4周。如果我沒有正確格式化這個問題或者沒有使用適當的藝術術語,請提前接受我的道歉。MySQL在商店定位器 - 谷歌地圖應用的分組查詢中選擇錯誤的列值

我正在構建商店定位器應用程序。爲了進行測試,我有一個名爲「位置」的表格,其中包含5個不同連鎖餐廳的名稱,地址和緯度/經度數據,總計(位置)記錄爲1500個。

我得到的應用程序運行良好,作爲標準的商店定位器,用戶輸入他們的地址和搜索距離。下面的代碼在刪除GROUP BY語句時正確返回這些結果。例如,當用戶輸入他們的地址和距離進行搜索時,SELECT語句將返回該距離內的所有餐館就好了。

我的應用程序要求只能返回並顯示用戶指定距離內各餐廳連鎖店的最近位置。我添加了GROUP BY語句來完成此操作。使用正確的loc_name和距離用戶的距離返回正確的記錄數。但是,其他所有領域都是不正確的。它們似乎是從MIN值以外的其他記錄中隨機選擇的。例如,返回的第一條記錄是在距離爲4.38英里的DAIRY QUEEN處 - ,這是正確的。然而,在4.38英里處的乳業女王的地址,州,城市等不正確

我已經詳細閱讀了有關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的解決方案是否保留了優化?

感謝你們所有人的幫助。我真的只是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

你在四周很長的路要走。它有助於包含最少的DDL和INSERT語句,以鼓勵更多的人作出迴應。

我加了GROUP BY語句到 完成這個。使用正確的 loc_name和距用戶的距離返回正確的 記錄數。 但是,所有其他字段都是 從不正確。他們似乎隨機 從其他記錄是從最小值以外的 選擇。

是的,這對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表達式來獲取所需的其他列。

我包的算術名爲「距離」的功能,然後

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