2011-11-10 109 views
-1

首次發佈時,我會盡量遵守最佳做法。對MySQL列數據進行分組

我試圖構建一個用於測量用戶位置的MySQL查詢(分別表示爲緯度和經度爲$Lat$Lng的查詢)。查詢應該返回距離用戶最近的50個電臺。

問題是我的表中的數據包含每個站的位置入口每個站我只需要每個站最近的站入口!

這是我的查詢:

SELECT id, lat, lng, station_name, routes, 
    (3959 * acos(cos(radians($Lat)) 
    * cos(radians(lat)) * cos(radians(lng) - 
    radians($Lng)) + sin(radians($Lat)) * sin(radians(lat)))) AS distance 
FROM subway_stations ORDER BY distance LIMIT 0 , 50; 

上述MySQL查詢完成以下操作:

  1. 選擇從ID,緯度,經度,站的班次數據和路線
  2. 測量每個站點的lat和lng與用戶的數據 - 將該數據存儲爲'distance'
  3. 返回50個最近的結果

我需要組這些結果在一起,使得每個站只有一個記錄被返回,所述一個隨着距離列中的最低值,這是最接近用戶站入口。

我試過使用GROUP BY但我似乎正在實施它不正確,因爲返回的結果不是所需的。

回答

0

很難知道沒有建立樣本數據庫,但我懷疑你想要做如下修改:

  1. 添加group by station_name, id, lat, lng到您的查詢的末尾

  2. 所有select不屬於group by子句的字段需要一個聚合函數。最明顯的是,distance應該需要一個min(...)

  3. 我不知道是否可以使用orderlimit條款。如果你有問題,把它們拿出來(暫時),讓這個工作很多。爲了方便起見,請調用此查詢Q1。

  4. 如果order bylimit子句不能使用(實驗,觀察),那麼你要嵌套查詢。這看起來像select * from (...Q1...) t1 ORDER BY distance LIMIT 0,50t1爲內部選擇分配了一個臨時名稱,在該查詢中沒有實際使用,但是語法是必需的。

  5. 作爲優化,您可能希望將having子句添加到內部Q1查詢中。也就是說,如果您知道邊界距離,請添加HAVING distance<XXXXX

注意步驟3 - 5可能不需要,我不知道第3步

+0

如果您向查詢添加了「group by station_name,id,lat,lng」,它基本上與根本不分組相同。 –

+0

我假設'station_name'唯一定義了'id','lat','lng','id'作爲可能的主鍵。但重讀原來的問題,似乎'id'可能是指個人入口。所以你可能是對的。我正在重新考慮。 – Pursuit

+0

@Sam看起來你的回答是正確的。你只需要添加'order by'和'limit'子句來回答原來的問題。 (我的名聲還不夠高,無法對你的問題發表評論)。 – Pursuit

0

如果你只需要爲每個站一個最小的記錄,你不需要LIMIT .. 只是做

$result = mysql_query("SELECT id, lat, lng, station_name, routes, MIN(
    (3959 * acos(cos(radians($Lat)) * cos(radians(lat)) * 
    cos(radians(lng) - radians($Lng)) + sin(radians($Lat)) * 
    sin(radians(lat)))) AS distance) 
FROM subway_stations 
GROUP BY station_name; 

這將返回每個站只有一條記錄與最小距離。

+0

這不起作用。當您選擇'GROUP BY'子句中未指定的字段時,結果是未定義的 - 您將從任意行獲得結果。 –

0

你可能有更容易得到每個站用PHP最接近入口。

這實際上是一個常見問題,您需要使用子查詢來解決這個問題。 我假設id只是一個行ID,並不是每個電臺唯一的。

SELECT subway_stations.* FROM (
    SELECT station_name, MIN(
     (3959 * acos(cos(radians($Lat)) * cos(radians(lat)) * 
     cos(radians(lng) - radians($Lng)) + sin(radians($Lat)) * 
     sin(radians(lat)))) 
    ) AS distance 
    FROM subway_stations 
    GROUP BY station_name 
) AS min_distances 
JOIN subway_stations ON (
    min_distances.station_name = subway_stations.station_name 
    AND (3959 * acos(cos(radians($Lat)) * cos(radians(lat)) * 
     cos(radians(lng) - radians($Lng)) + sin(radians($Lat)) * 
     sin(radians(lat))) 
    ) = min_distances.distance 
) 

這是針對您的問題的典型「純粹mysql」解決方案。但是,由於計算距離的計算程度,您可能希望: - 使用您的初始查詢,並使用php獲取每個工作站的最短距離或運行上面的內部查詢,但插入其結果轉換爲臨時表,然後執行上述查詢的等效操作,但將計算的距離替換爲距離臨時表的計算距離。