5

私のサイトでは、近くの場所を取得しようとしています。

これには、Haversine 式を使用しようとしています。

次のクエリを使用して、半径 25 km 以内のすべての場所を取得しています。

SELECT id, ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) AS distance
FROM shops
HAVING distance < 25
ORDER BY name asc

ただし、次のエラーが発生するため、一部の関数は MySQL のみである可能性があると思います。

警告: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[42883]: 未定義の関数: 7 エラー: 関数 radians(text) が存在しません 行 1: ...id, ( 6371 * acos( cos( radians( 51.8391) ) * cos( radians( l... ^ ヒント: 指定された名前と引数の型に一致する関数はありません。明示的な型キャストを追加する必要があるかもしれません。in ...

あるいはlat、クエリのテキストを変更しなければならないという事実に関係しているのかもしれません。しかし、私はそれがどうあるべきかわかりません。

51.8391 と 4.6265 は、私の「出発点」の経度と緯度です。

何を変更すればよいかわからないので、どんな助けも大歓迎です:-)

編集

問題は私がやろうとしているところにあるようです: radians(lat).

lat は私のテーブルの列です。

rad()hakre が提案したように使用しようとすると、エラーが次のように変わります。function rad(numeric) does not exist

編集2

今、私たちはどこかに到達しています。

実際にテキストとして設定されている列のデータ型 (mu で提案されているように短すぎます)。

倍精度に変更しました。

ただし、別のエラーが発生します。

警告: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[42703]: 未定義の列: 7 エラー: 列 "距離" が存在しません LINE 1: ...adians( lat ) ) ) AS 距離 FROM ショップ HAVING距離 <... ^ in ...

しかし、selectでエイリアスを作成したと思いました。何か案は?

また、これを別の質問にすべきだと思う場合は、私に知らせてください。これを閉じます。

4

2 に答える 2

8

PostgreSQL には次のradians機能があります。

radians(dp)
度からラジアン

しかしradians、浮動小数点引数が必要で、何らかの文字列を指定しようとしています:

未定義の関数: 7 エラー: function radians( text )
[...] ヒント: 指定された名前と引数の型に一致する関数はありません。明示的な型キャストを追加する必要がある場合があります。

鉱山を強調します。どうやらあなたlatlng列はchar(n)、、、varchar(n)またはtext列です。と の列の型をlat、、またはその他の浮動小数点型に修正する必要があります。それまでの間、文字列を手でキャストして、壊れたデータがないことを願っています。lngnumericfloat

radians(cast(lat as double precision))

MySQL は多くの暗黙的な型変換を行いますが、PostgreSQL はかなり厳密であり、意味を正確に言う必要があります。


2 番目の問題の更新:HAVING句は句の前に評価されるSELECTため、通常、クエリ内の他の場所ではカラム エイリアスをSELECT使用できません。いくつかのオプションがあります。大きな醜いHaversineを繰り返すことができます:

SELECT id, ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) AS distance
FROM shops
HAVING ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) < 25
ORDER BY name asc

または、派生テーブルを使用して、同じことを繰り返さないようにします。

select id, distance
from (
    select id, name, ( 6371 * acos( cos( radians(51.8391) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(4.6265) ) + sin( radians(51.8391) ) * sin( radians( lat ) ) ) ) as distance
    from shops
) as dt
where distance < 25.0
order by name asc
于 2011-08-07T20:58:02.830 に答える
2

ラジアンへの変換は簡単です:

radians(n) = n * PI / 180.0
于 2011-08-07T20:48:27.433 に答える