给定纬度和经度,找到对该位置感兴趣的用户

发布于 2024-08-10 10:52:56 字数 501 浏览 2 评论 0原文

给定一个表,

+-----+---------+---------+---------+---------+---------+
| user| min_lat | max_lat | min_lng | max_lng |
+-----+---------+---------+---------+---------+---------+
| a   |    46   |     407 |       6 |     367 | 
| b   |   226   |     227 |     186 |     188 | 

和一个 Point(x, y) 查找该点位于用户的最小和最大纬度和经度范围内的用户(其中​​最小和最大长和纬度 = 当前位置减去或加上半径)。

最小值可以小于 0,最大值可以大于 360,查询需要考虑这些。

例如,使用Point(7,5)进行过滤也应该返回用户A,因为367-360=7。

不确定我是否正确,但希望有人能给我一些见解。

Given a table,

+-----+---------+---------+---------+---------+---------+
| user| min_lat | max_lat | min_lng | max_lng |
+-----+---------+---------+---------+---------+---------+
| a   |    46   |     407 |       6 |     367 | 
| b   |   226   |     227 |     186 |     188 | 

And a Point(x, y) Find users where the point is within the min and max latitude and longitude ranges of users (where min and max long and lat = current position minus or plus radius).

Minimum values can be less than 0 and maximum values can be greater than 360, the query needs to take these into account.

E.g. filtering using Point(7,5) should also return user A, as 367-360=7.

Not sure if I'm getting this right, but hopefully somebody can give me some insight.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

逐鹿 2024-08-17 10:52:57

我建议限制纬度和范围表中存储的经度值范围为 [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)
;

I recommend limiting the latitude & longitude values stored in the table to the range [0, 360]. Create triggers before insert and update to enforce the mod 360 equivalency and, if max-min > 360, set the min and max values to 0 and 360, respectively. For example:

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 ;

You can then use the following query:

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)
;
一萌ing 2024-08-17 10:52:57

为了回答您的查询的一部分,如果您说 367 和 7 相同,我同样假设 727 也是相同的。

因此,您想要使用 360 的模数。例如除以 360 的余数。

例如(其中 % 是 C# 和 C++ 语法,您可能会找到 SQL 方法来执行此操作)

7 % 360 = 7
367 % 360 = 7
727 % 360 = 7

看起来像 SELECT b MOD 360 from table; 就是你想要的东西。

To answer one part of your query, if you are saying that 367 and 7 are the same, I assume equally that 727 is also.

Therefore, you want to use the modulus of 360. E.g. the remainder of dividing by 360.

e.g. (where % is the C# and C++ syntax, you'll probably find an SQL way to do this)

7 % 360 = 7
367 % 360 = 7
727 % 360 = 7

Looks like something like SELECT b MOD 360 from table; is the sort of thing you want.

你怎么敢 2024-08-17 10:52:57

我怀疑有一个更优雅的答案,但我认为 SQL where 子句的限制使这变得更加困难。

假设:

  • 0 <= x < 360
  • 0 <= y < 360
  • max_lat - min_lat <= 361
  • max_lng - min_lng <= 361
从 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))))  
和  
((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 < 0 则 x 必须介于 0 和 max 之间,或者 x 必须介于 min + 360 和 360 之间。类似地,如果 min >= 0 则 x 必须介于 min 和 max 之间,或者它必须介于 0 和 max - 360 之间。

上述格式是为了清楚起见而提出的。如果将 360 的加法和减法移至 x 和 y 参数,比较将变得恒定,并且可能会显着加快查询速度。

I suspect there is a more elegant answer, but I think the confines of a SQL where clause make this a little more difficult.

Assumptions:

  • 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))))

In one dimension, if min < 0 then x must fall between 0 and max or x must fall between min + 360 and 360. Similarly if min >= 0 then x must fall between min and max, or it must fall between 0 and max - 360.

The format above is presented for clarity. If you move the addition and subtraction of 360 to the x and y parameters, the comparisons become constant and probably speed the query dramatically.

挽心 2024-08-17 10:52:57

使用模来确保所有值都在 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 函数将阻止查询利用这些列上的任何索引。

Use a modulo to ensure all values are between 0 and 360, and the query becomes pretty simple. Assume {pointLat} and {pointLng} are the coordinates of the point that's being filtered on.

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)));

While this would work, I strongly recommend performing the MOD calculations outside the SQL query or adding extra columns with normalized values. Using the MOD function as in this code would prevent the query from taking advantage of any indexes on those columns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文