给出一张表,
+-----+---------+---------+---------+---------+---------+
| user| min_lat | max_lat | min_lng | max_lng |
+-----+---------+---------+---------+---------+---------+
| a | 46 | 407 | 6 | 367 |
| b | 226 | 227 | 186 | 188 |
点(x,y)查找点在用户的最小和最大纬度和经度范围内的用户(其中min和max long和lat =当前位置减去或加上半径)。
最小值可以小于0,最大值可以大于360,查询需要考虑这些。
E.g。使用Point(7,5)进行过滤也应该返回用户A,如367-360 = 7。
不确定我是否正确,但希望有人可以给我一些见解。
答案 0 :(得分:2)
我建议限制纬度和范围存储在表中的经度值到[0,360]范围。在插入和更新之前创建触发器以强制执行mod 360等效,并且如果max-min> 360,将最小值和最大值分别设置为0和360。例如:
delimiter ;;
CREATE TRIGGER normalize_inserted_ranges BEFORE INSERT
ON table
FOR EACH ROW BEGIN
IF NEW.max_lat - NEW.min_lat >= 360 THEN
SET NEW.min_lat=0;
SET NEW.max_lat=360;
ELSE
SET NEW.min_lat = NEW.min_lat % 360;
SET NEW.max_lat = NEW.max_lat % 360;
END IF;
IF NEW.max_lng - NEW.min_lng >= 360 THEN
SET NEW.min_lng=0;
SET NEW.max_lng=360;
ELSE
SET NEW.min_lng = NEW.min_lng % 360;
SET NEW.max_lng = NEW.max_lng % 360;
END IF;
END
;;
delimiter ;
然后您可以使用以下查询:
SELECT user FROM table
WHERE
IF(min_lng <= max_lng,
@x BETWEEN min_lng AND max_lng,
@x <= max_lng OR min_lng <= @x)
AND
IF(min_lat <= max_lat,
@y BETWEEN min_lat AND max_lat,
@y <= max_lat OR min_lat <= @y)
;
答案 1 :(得分:0)
要回答查询的一部分,如果你说367和7是相同的,我同样假设727也是。
因此,您希望使用360的模数。剩下的除以360。
e.g。 (其中%是C#和C ++语法,您可能会找到一种SQL方法来执行此操作)
7 % 360 = 7
367 % 360 = 7
727 % 360 = 7
看起来像SELECT b MOD 360 from table;
之类的东西就是你想要的东西。
答案 2 :(得分:0)
我怀疑有一个更优雅的答案,但我认为SQL where子句的限制使这有点困难。
假设:
0 <= x < 360
0 <= y < 360
max_lat - min_lat <= 361
max_lng - min_lng <= 361
SELECT user FROM user_location WHERE ((min_lat < 0 AND ((0 <= y AND y <= max_lat) OR (min_lat + 360 <= y AND y < 360))) OR (min_lat >= 0 AND ((min_lat <= y AND y <= max_lat) OR (0 <= y AND y <= max_lat - 360)))) AND ((min_lng < 0 AND ((0 <= x AND x <= max_lng) OR (min_lng + 360 <= x AND x <= 360))) OR (min_lng >= 0 AND ((min_lng <= x AND x <= max_lng) OR (0 <= x AND x <= max_lng - 360))))
在一个方面,如果min&lt; 0然后x必须落在0和max之间,或者x必须落在min + 360和360之间。类似地,如果min> = 0则x必须落在min和max之间,或者它必须落在0到max - 360之间。
上面的格式是为了清楚起见。如果将360的加法和减法移动到x和y参数,则比较将变为常量,并可能显着加快查询速度。
答案 3 :(得分:0)
使用模数来确保所有值都在0到360之间,并且查询变得非常简单。假设{pointLat}和{pointLng}是要过滤的点的坐标。
SELECT *
FROM table
WHERE IF(min_lat < max_lat,
MOD({pointLat}, 360) BETWEEN MOD(min_lat, 360) AND MOD(max_lat, 360)),
MOD({pointLat}, 360) NOT BETWEEN MOD(min_lat, 360) AND MOD(max_lat, 360)))
AND IF(min_lng < max_lng,
MOD({pointLng}, 360) BETWEEN MOD(min_lng, 360) AND MOD(max_lng, 360)),
MOD({pointLng}, 360) NOT BETWEEN MOD(min_lng, 360) AND MOD(max_lng, 360)));
虽然这可行,但我强烈建议在SQL查询之外执行MOD计算或添加带有规范化值的额外列。使用此代码中的MOD函数将阻止查询利用这些列上的任何索引。