如何在laravel 5中的关系列上使用'having'和paginate

Mir*_* Vu 7 mysql laravel eloquent laravel-5

我需要抓住"经销商"关系距离<200的车辆

Vehicle::join('dealers', 'vehicles.dealer_id', '=', 'dealers.id')
     ->select(DB::raw("dealers.id, ( cos( radians(latitude) ) * cos( radians( longitude ) ) ) AS distance"))
     ->havingRaw('distance < 200');
Run Code Online (Sandbox Code Playgroud)

我试图在关系(belongsTo)经销商的别名"距离"上使用havingRaw.但失败了一个错误:

未找到列:1054'having子句'中的未知列'距离'

UPDATE

当我将paginate函数添加到上述查询中时,实际上会出现问题.

$vehicle = Vehicle::join('dealers', 'vehicles.dealer_id', '=', 'dealers.id')
 ->select(DB::raw("dealers.id, ( cos( radians(latitude) ) * cos( radians( longitude ) ) ) AS distance"))
 ->havingRaw('distance < 200');

$result = $vehicle->paginate(15);
Run Code Online (Sandbox Code Playgroud)

Pau*_*gel 7

更新

如果你使用paginate()你的查询,laravel 将尝试执行以下 SQL 代码来计算可能匹配的总数:

select count(*) as aggregate 
from `vehicles` inner join `dealers` 
  on `vehicles`.`dealer_id` = `dealers`.`id`
having distance < 200
Run Code Online (Sandbox Code Playgroud)

如您所见,distance此查询中没有这样的列或别名。

我原始答案中的选项 2也将解决该问题。

原答案

这似乎是一个 MySQL 严格模式问题。如果您使用 laravel 5.3 严格模式默认启用。您有两个选择:

选项 1:禁用 MySQL 的严格模式 config/database.php

...
'mysql' => [
    ...
    'strict' => false,
    ...
],
...
Run Code Online (Sandbox Code Playgroud)

选项 2:使用 WHERE 条件

Vehicle::join('dealers', 'vehicles.dealer_id', '=', 'dealers.id')
     ->select(DB::raw("dealers.id, ( cos( radians(latitude) ) * cos( radians( longitude ) ) ) AS distance"))
     ->whereRaw('cos( radians(latitude) ) * cos( radians( longitude ) ) < 200');
Run Code Online (Sandbox Code Playgroud)

文档:

MySQL 对标准 SQL 的扩展允许在 HAVING 子句中引用选择列表中的别名表达式。启用 ONLY_FULL_GROUP_BY 会禁用此扩展,因此需要使用非别名表达式编写 HAVING 子句。

服务器 SQL 模式 - ONLY_FULL_GROUP_BY


mai*_*o84 -1

我所做的事情似乎与您尝试做的事情类似:

public function scopeNearest($query, Geo $geo, $miles = 25)
{
    return $query
        ->select(DB::raw("*, ( 3959 * acos( cos( radians({$geo->lat}) ) * cos( radians( lat ) ) * cos( radians( lng ) - radians({$geo->lng}) ) + sin( radians({$geo->lat}) ) * sin( radians( lat ) ) ) ) AS distance"))
        ->groupBy('id')
        ->having('distance', '<', $miles)
        ->orderBy('distance');
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,我有一个单独的模型,用于处理纬度和经度坐标以及名为 的地址信息Geo。您可能不需要这种级别的分离,因此您可以重构为如下所示:

public function scopeNearest($query, $lat, $lng, $miles = 25)
{
    return $query
        ->select(DB::raw("*, ( 3959 * acos( cos( radians({$lat}) ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians({$lng}) ) + sin( radians({$lat}) ) * sin( radians( latitude ) ) ) ) AS distance"))
        ->groupBy('id')
        ->having('distance', '<', $miles)
        ->orderBy('distance');
}
Run Code Online (Sandbox Code Playgroud)

请记住,为了计算距离,您需要两个点。该模型将能够通过使用自己的列latitudelongitude作为参数提供给范围查询的纬度和经度来检查两点之间的距离。

您可以将其放入您的车辆模型中并像这样调用:

Vehicle::nearest($latitude, $longitude, 200);
Run Code Online (Sandbox Code Playgroud)

这尚未针对您的用例进行测试,因此我不能保证它可以开箱即用,但希望它能为您指明正确的方向。