2011-11-10 19 views
-1

初めての投稿では、ベストプラクティスを遵守しようとします。MySQLの列データのグループ化

私は、ユーザの場所を測定するMySQLクエリを作成しようとしています(クエリでは、それぞれ緯度と経度については$Latと)。クエリは、ユーザーに最も近い50のステーションを返す必要があります。

問題は、私のテーブルのデータに各ステーションの位置が含まれていることです。入り口 1ステーションあたり最も近い駅入口が必要です!

これは私のクエリです:

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、緯度、LNG、STATION_NAMEとルートからのデータを選択します各ステーションの緯度と経度をユーザーの緯度と経度で測定し、そのデータを「距離」として保存する
  2. は駅ごとに1つのレコードのみが返されるように、私は一緒にグループにこれらの結果を必要とする50件の最も近い結果

、ユーザーに最も近い駅の入り口である距離の列、で最も低い値を持つものを返します。 。

私はGROUP BYを使用しようとしましたが、返された結果が目的のものではないため、正しく実装されていないようです。

答えて

0

これは、サンプル・データベースを設定せずに知ることは難しいのですが、私は、あなたが次の変更をしたいと思われる:

  1. は、クエリ

  2. の最後にすべてのselectgroup by station_name, id, lat, lngを追加しますgroup by句の一部ではないフィールドには、集約関数が必要です。ほとんど明らかに、distanceは私がorderlimit句を使用することができますかどうかわからないんだけどmin(...)

  3. を必要とすべきです。問題がある場合は、それらを取り出して(一時的に)これを大いに活用してください。私の便宜のために、このクエリをQ1と呼んでください。

  4. limit節を使用できない場合(実験と参照)、ネストされたクエリが必要です。それはselect * from (...Q1...) t1 ORDER BY distance LIMIT 0,50のようになります。 t1には、内部選択に一時的な名前が割り当てられています。このクエリでは実際には使用されませんが、構文には必要です。

  5. 最適化として、内部Q1クエリにhaving句を追加することができます。つまり、境界距離がわかっている場合は、HAVING distance<XXXXXを追加します。ステップ3

注 - 5が必要とされないことが、私はあなたがPHPで駅ごとに最も近い入り口を取得して簡単に時間を持っているかもしれないステップ3.

+0

'station_name、id、lat、lngのグループ'をクエリに追加すると、基本的にグループ化しないのと同じになります。 –

+0

私は、 'station_name'が一意的に' id'、 'lat'、' lng'を一意のキーとして 'id'を定義していると仮定しました。しかし、「id」のようなオリジナルの質問を読み返すことは、おそらく個々の入り口を指しているのかもしれません。あなたはおそらく正しいでしょう。私は再検討している。 – Pursuit

+0

@Samあなたの答えが正しいようです。元の質問に答えるために 'order by'と' limit'節を追加するだけです。 (私の評判は、それが所属するあなたの質問にこのコメントをするにはまだ十分ではありません)。 – Pursuit

0

あなただけの各ステーションの1件の最小記録が必要な場合は、LIMITを必要としない... ただこれが最短距離と駅ごとに1つのレコードのみを返します

$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

についてはよく分かりません。

これは実際には一般的な問題です。これを解決するにはサブクエリを使用する必要があります。 私は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 OR で各ステーションの最短距離を取得 - 上記の内部クエリを実行しますが、その結果を挿入します一時テーブルに計算された距離で置き換えられた計算された距離を除いて、上記のクエリに相当する操作を行います。