You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中编写原始查询并传递坐标参数?

Laravel中正确传递ST_DistanceSpheroid坐标参数的实现方案

问题背景

已知可用原生SQL查询:

SELECT doctors.user_id, (ST_DistanceSpheroid(geometry(location), ST_GeomFromText('POINT(37.857397 55.690576)'), 'SPHEROID["WGS 84",6378137,298.257223563]')
       ) as distance FROM users INNER JOIN doctors ON doctors.user_id = users.id ORDER BY distance ASC

需要在Laravel中实现该查询并正确传递坐标参数,以下是之前的错误尝试及问题分析:

错误尝试1

代码:

$point = "37.854289 55.685333";
return DB::table('users')
      ->select(DB::raw('ST_DistanceSpheroid(geometry(location), ST_GeomFromText(\'POINT(?)\'), \'SPHEROID["WGS 84",6378137,298.257223563]\''), [$point])
      ->get();

报错:

"message": "stripos(): Argument #1 ($haystack) must be of type string, array given",

问题原因:DB::raw()仅接受字符串参数,不支持直接传入参数数组,参数绑定不能通过DB::raw的第二个参数实现。

错误尝试2

代码:

$lon = 37.857397;
$lat = 55.685333;

return DB::table('users')
    ->selectRaw(
        "(ST_DistanceSpheroid(
        geometry(location),
        ST_GeomFromText('POINT(? ?)'),
        'SPHEROID[?, ?, ?]'
    )) as distance",
        [$lon, $lat, 'WGS 84', 6378137, 298.257223563]
    )->leftJoin('doctors', 'doctors.user_id', 'users.id')->orderBy('distance', 'ASC')->get();

报错:

{
    "message": "PDO: SQLSTATE[XX000]: Internal error: 7 ОШИБКА:  SPHEROID parser - couldnt parse the spheroid\nLINE 4:             'SPHEROID[?, ?, ?]'\n                    ^ (SQL: select (ST_DistanceSpheroid(\n            geometry(location),\n            ST_GeomFromText('POINT(37.857397 55.685333)'),\n            'SPHEROID[WGS 84, 6378137, 298.257223563]'\n        )) as distance from \"users\" left join \"doctors\" on \"doctors\".\"user_id\" = \"users\".\"id\" order by \"distance\" asc)"
}

问题原因:SPHEROID的格式要求必须用双引号包裹名称,参数绑定后丢失了双引号,导致PostGIS无法解析;且SPHEROID为固定参数,无需动态绑定。

正确实现方式

方法一:使用selectRaw安全绑定坐标参数(推荐)

用ST_MakePoint直接传入经纬度参数,避免字符串拼接风险,SPHEROID固定写入SQL:

$lon = 37.857397;
$lat = 55.690576;

return DB::table('users')
    ->selectRaw(
        'doctors.user_id, ST_DistanceSpheroid(geometry(location), ST_MakePoint(?, ?)::geometry, ?) as distance',
        [$lon, $lat, 'SPHEROID["WGS 84",6378137,298.257223563]']
    )
    ->join('doctors', 'doctors.user_id', '=', 'users.id')
    ->orderBy('distance', 'ASC')
    ->get();

方法二:使用DB::raw结合addBinding实现绑定

若需使用DB::raw,可通过addBinding手动绑定参数:

$lon = 37.857397;
$lat = 55.690576;

$query = DB::table('users')
    ->select(DB::raw('doctors.user_id, ST_DistanceSpheroid(geometry(location), ST_MakePoint(?, ?)::geometry, \'SPHEROID["WGS 84",6378137,298.257223563]\') as distance'))
    ->join('doctors', 'doctors.user_id', '=', 'users.id')
    ->orderBy('distance', 'ASC');

$query->addBinding([$lon, $lat], 'select');

return $query->get();

关键注意点

  • SPHEROID为固定格式参数,直接写入SQL即可,不要动态绑定,避免格式错误。
  • 优先使用ST_MakePoint(?, ?)构造点几何,比拼接POINT()字符串更安全,防止SQL注入。
  • selectRaw是Laravel处理带参数原生查询的标准方式,语法更简洁清晰。

内容的提问来源于stack exchange,提问作者Dalama

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 23:25:20