3分钟短文 | Laravel 自定义 SQL 查询参数绑定

2020-08-27 13:46:46 浏览数 (1)

引言

laravel使用模型进行数据库操作时,并不是所有的字段或者关联关系 都能满足查询需求,有时候会有一些MySQL的函数计算等功能放在数据库 层面执行。

本文说一说自定义的参数绑定办法。

学习时间

假如有一个需求,已知经纬度手动计算两点之间的近距离。我们会使用类似下面的计算公式:

代码语言:javascript复制
3959 * acos( cos( radians(  ?  ) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(?) )   sin( radians(  ?  ) ) * sin( radians( lat ) ) )

其中问号位置就是我们需要填入的变量数据,也就是一个经纬度坐标,根据参照点,计算出数据库内每条记录内的该点距离参照点的距离。那么如果写到程序里,应该如何把绑定参数按顺序传入呢。

既然是自定义的字段名,我们可以使用 DB::raw 方式传入。代码如下:

代码语言:javascript复制
$property =
    Property::select(
        DB::raw("title, lat, lng, (
            3959 * acos(
                cos( radians(  ?  ) ) *
                cos( radians( lat ) ) *
                cos( radians( lng ) - radians(?) )  
                sin( radians(  ?  ) ) *
                sin( radians( lat ) )
            )
       ) AS distance")
    )
    ->having("distance", "<", "?")
    ->orderBy("distance")
    ->take(20)
    ->setBindings([$lat, $lng, $lat,  $radius])
    ->get();

这个查询语句有些复杂,可是有章可循。首先是使用select方法指定了返回字段名, 对于自定义的字段 distance 使用 having 子句进行进一步条件限定。最重要就是 setBindings 方法了,传送的是前面自定义SQL语句的位置参数。只需一一对应上就可以了。

如果大家经常使用laravel的调试功能的话,应该会注意到,这种问号的写法是laravel本身封装SQL语句用的。而对于写惯了PDO原生SQL语句查询的,则可以使用PDO方式的绑定方式:

代码语言:javascript复制
$property = Property::select(DB::raw("title, lat, lng, ( 3959 * acos( cos( radians(:lat) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians(:lng)   sin(radians(:lat_i) ) * sin( radians( lat ) ) ) ) AS distance"), ["lat" => $lat, "lng" => $lng, "lat_i" => $lat]);

上面的语句只用了select方法,其他的筛选和排序,与上一节代码相同,不需要调用 setBindings 方法。

为了方便查看,我们也可以不画蛇添足地使用 DB::raw 方法。而直接使用 selectRaw ,更为简洁直观:

代码语言:javascript复制
$select = <<<SQL
    title,
    lat,
    lng,
    (3959*acos(cos(radians( ? ))*cos(radians(lat))*cos(radians(lng)-radians( ? )) sin(radians( ? ))*sin(radians(lat)))) AS distance
SQL;

首先拼装好SQL语句的字段,然后使用laravel模型的方法:

代码语言:javascript复制
$property = Property::selectRaw($select, [$lat, $lng, $lat])->having('distance', '<', $radius)->orderBy('distance')->take(20)->get();

写在最后

本文通过三种方式实现了laravel模型进行复杂的自定义查询, 其中提供了两种参数绑定的方式,我们推荐使用 selectRaw 的方式, 更为直观。

0 人点赞