Laravel RawQuery中使用用户表radius字段实现动态半径坐标搜索
问题描述
之前通过ENV常量定义固定50km半径,查找特定坐标范围内的用户。现在希望调整逻辑:使用用户自身设定的radius字段作为判断依据,若该字段为NULL则默认采用50km,筛选出处于给定坐标自身设定半径范围内的用户。
现有查询代码:
User::selectRaw('*, (6371 * acos (cos ( radians('.$lat.') ) * cos( radians( addressLat ) ) * cos( radians( addressLong ) - radians('.$lng.') ) + sin ( radians('.$lat.') ) * sin( radians( addressLat ) ))) AS distance') ->orderBy('distance') ->having('distance', '<', $radius) ->whereNotNull('phone_number') ->where('should_receive_quotes', '!=', '0') ->get();
当前变量定义:
$radius = env('RADIUS',50);
相关表结构:
用户表
| id | lat | lng | radius |
|---|---|---|---|
| 1 | 51.500836 | -1.159058 | 80 |
| 2 | 51.164490 | -0.466919 | NULL |
| 3 | 52.39103 | -2.91020 | NULL |
报价表
| id | lat | lng |
|---|---|---|
| 1 | 51.267715 | -0.214233 |
预期结果:针对报价ID1,返回用户1和2。用户1在自身设定的80km范围内,用户2使用默认50km且在范围内;用户3因超出默认50km范围,不返回。
解决方案
可以实现该需求,核心是用COALESCE函数处理用户的radius字段,同时修复原代码的SQL注入风险,修改后的查询逻辑如下:
$defaultRadius = env('RADIUS', 50); $users = User::selectRaw(' *, (6371 * acos ( cos(radians(?)) * cos(radians(addressLat)) * cos(radians(addressLong) - radians(?)) + sin(radians(?)) * sin(radians(addressLat)) )) AS distance, COALESCE(radius, ?) AS effective_radius ', [$lat, $lng, $lat, $defaultRadius]) ->orderBy('distance') ->havingRaw('distance < effective_radius') ->whereNotNull('phone_number') ->where('should_receive_quotes', '!=', '0') ->get();
关键说明:
- COALESCE函数:
COALESCE(radius, ?)会优先取用户表的radius值,若为NULL则使用传入的默认50km,将结果命名为effective_radius作为每个用户的判断半径。 - 参数绑定:将
$lat、$lng、$defaultRadius作为参数传入selectRaw,避免直接拼接字符串导致的SQL注入风险。 - 条件调整:把原固定的
$radius判断改为distance < effective_radius,让每个用户都使用自身的有效半径进行范围校验。
该代码会按照预期返回用户1和2,满足需求。
内容的提问来源于stack exchange,提问作者user26547113
相关产品推荐
相关产品推荐

