2016-07-17 13 views
1

whereを使用して浮動小数点検索を検索するのが、以下のように機能しない理由を理解できますか?ActiveRecordここで、Float == Floatが空の配列を返す

> latitude = 37.9763 

    37.9763 

> Branch.first.latitude 
    # Branch Load (0.4ms) SELECT `branches`.* FROM `branches` ORDER BY `branches`.`id` ASC LIMIT 1 

    37.9763 

> Branch.first.latitude.class 

    Float < Numeric 

> latitude.class 

    Float < Numeric 

> Branch.where(latitude: latitude) 
    # Branch Load (11.7ms) SELECT `branches`.* FROM `branches` WHERE `branches`.`latitude` = 37.9763 

    [] 

私もBranch.where("latitude = ?", latitude)を試してみましたが、私は私の心を失うことをしなければならない[]

を得ます。好奇心旺盛な人のため

> Branch.where('latitude = ?', Branch.first.latitude) 
    # Branch Load (0.4ms) SELECT `branches`.* FROM `branches` ORDER BY `branches`.`id` ASC LIMIT 1 
    # Branch Load (11.3ms) SELECT `branches`.* FROM `branches` WHERE (latitude = 37.9763) 
    [] 

、私はこれはおそらくどのようfloating point numbers are representedに起こっている重複

hash = Branch.group(:business_name, :latitude, :longitude).count 
hash.select{|k,v| v > 1}.each do |groupings, count| 
    business_name = groupings[0] 
    latitude = groupings[1] 
    longitude = groupings[2] 
    branches = Branch.where(
    business_name: business_name, 
    latitude: (latitude - 0.0001)..(latitude + 0.0001), 
    longitude: (longitude - 0.0001)..(longitude + 0.0001) 
) 
    puts "#{business_name} Count = #{count}" 
    puts "#{business_name} Branch Count = #{branches.count}" 
    puts "no match" if count != branches.count 
end 
+0

あなたは(Branch.whereを試してみました緯度:緯度.to_f)? – power

+0

はい、ありましたが、クラスが既に一致しているため、実際には必要ありません。 – Abram

+0

ActiveRecordがクエリに対して生成する生のSQLを提供してください。アプリケーションログから取得できます。リレーションに対して '.to_sql'を呼び出すこともできます。 –

答えて

1

を見つけるために、以下の手順を使用してno match 2000全体の枝の唯一の3例を見つけることができました。通常の等価比較を使用することによって、それらを確実に比較することはできません。正確な一致を確認する代わりに、数値が範囲内にあるかどうかを確認するか、比較する前に両方の数値をある精度に丸める方が良いでしょう。

地理座標を使用した特定の例(latitudeが使用されていると仮定します)については、floatの代わりにdecimal列型を使用することをお勧めします。

あなたが例えば、値が範囲内にある場合、私はチェックをお勧めすることができ、float列に固執したい場合:

Branch.where("latitude > ? AND latitude < ?", latitude - 0.00001, latitude + 0.00001) 

または

Branch.where(latitude: (latitude - 0.00001)..(latitude + 0.00001)) 
+1

ここで 'BETWEEN'は動作しますか? –

+1

はい、うまくいきます。私は、SQLで 'BETWEEN'が使用されるという例で答えを更新しました。 – lest

+0

@lest答えは正しいですが、私も 'decimal'に切り替えることをお勧めします。 'between'を使用すると、より大きな問題の回避策をとっているだけです:「間違ったタイプを使用しています!」小数に変換! – coorasse

関連する問題