Laravel Eloquent 多列 IN 子句

Posted

技术标签:

【中文标题】Laravel Eloquent 多列 IN 子句【英文标题】:Laravel Eloquent Multiple Column IN Clause 【发布时间】:2016-10-23 14:16:04 【问题描述】:

我最近开始使用 Laravel 进行开发,我的第一个项目是一个车辆预订应用程序。

我似乎做得很好,但是我一直在尝试使用 Eloquent 显示当前的预订。

系统通过将车辆添加到vehicles 表,并将员工添加到employees 表来工作。使用employee_vehicle 创建与数据透视表的多对多关系。

员工

+------------+-------------+------+-----+---------+----------------+
| Field      | Type        | Null | Key | Default | Extra          |
+------------+-------------+------+-----+---------+----------------+
| id         | int(10)     | NO   | PRI | NULL    | auto_increment |
| first_name | varchar(50) | NO   |     | NULL    |                |
| surname    | varchar(50) | NO   |     | NULL    |                |
+------------+-------------+------+-----+---------+----------------+

车辆

+--------------+-------------+------+-----+---------+----------------+
| Field        | Type        | Null | Key | Default | Extra          |
+--------------+-------------+------+-----+---------+----------------+
| id           | int(10)     | NO   | PRI | NULL    | auto_increment |
| registration | varchar(10) | NO   |     | NULL    |                |
| make         | varchar(50) | NO   |     | NULL    |                |
| model        | varchar(50) | NO   |     | NULL    |                |
+--------------+-------------+------+-----+---------+----------------+

employee_vehicle

+-------------+------------+------+-----+---------+----------------+
| Field       | Type       | Null | Key | Default | Extra          |
+-------------+------------+------+-----+---------+----------------+
| id          | int(10)    | NO   | PRI | NULL    | auto_increment |
| employee_id | int(10)    | NO   |     | NULL    |                |
| vehicle_id  | int(10)    | NO   |     | NULL    |                |
| direction   | varchar(3) | NO   |     | NULL    |                |
| date_booked | datetime   | NO   |     | NULL    |                |
| damaged     | tinyint(1) | NO   |     | NULL    |                |
| mileage     | int(10)    | NO   |     | NULL    |                |
+-------------+------------+------+-----+---------+----------------+

结果

+----+-------------+------------+-----------+---------------------+---------+---------+
| id | employee_id | vehicle_id | direction | date_booked         | damaged | mileage |
+----+-------------+------------+-----------+---------------------+---------+---------+
|  1 |           1 |          1 | OUT       | 2016-06-13 09:08:08 |       0 |    2357 |
|  2 |           1 |          1 | IN        | 2016-06-16 16:29:26 |       0 |    2401 |
|  3 |           2 |          1 | OUT       | 2016-06-20 10:47:28 |       0 |    2470 |
|  4 |           3 |          2 | OUT       | 2016-06-14 09:18:52 |       0 |    1403 |
+----+-------------+------------+-----------+---------------------+---------+---------+

这些表具有扩展 Eloquent 的 VehicleEmployee 模型。这些有调用belongsToMany的方法。

我想要做的是获取Vehicle 集合并急切地将员工加载到它上面。这样我就可以显示当前预订的车辆,以及当前已预订的车辆。

例如:

$vehicleBookings = Vehicle::with(['employees'])->get();

我将解释预订的工作方式......

基本上,车辆和员工使用数据透视表链接在一起。该表还记录了预订的日期、预订的方向(例如预订的 IN 或 OUT)以及有关其状况等的其他数据。

IN 和 OUT 都有一个条目很重要,以便在预订前后有车辆状况的审核日志。

我遇到的问题是能够从可用预订中获取车辆的最新状态,以确定它当前是否已预订完毕,或者是否可以预订。这决定了车辆可以做什么。

经过一番研究,我想出了以下查询:

SELECT * 
FROM `employee_vehicle` 
WHERE (`vehicle_id`, `date_booked`) IN (
   SELECT `vehicle_id`, MAX(`date_booked`)
    FROM `employee_vehicle`
    GROUP BY `vehicle_id`
)

(直到现在,我什至不知道可以将多个列与 IN 子句一起使用,但这太棒了!)。

这给了我:

+----+-------------+------------+-----------+---------------------+---------+---------+
| id | employee_id | vehicle_id | direction | date_booked         | damaged | mileage |
+----+-------------+------------+-----------+---------------------+---------+---------+
|  3 |           2 |          1 | OUT       | 2016-06-20 10:47:28 |       0 |    2470 |
|  4 |           3 |          2 | OUT       | 2016-06-14 09:18:52 |       0 |    1403 |
+----+-------------+------------+-----------+---------------------+---------+---------+

这让我每辆车都有一排已经预订(这是在加入任何员工之前)。

但是现在我真的被困住了。我只是不知道如何使用 Eloquent 编写一个等效的查询,该查询也加入了员工。 (它还需要只显示当前“OUT”的车辆,但我想这是微不足道的部分!)

可以只使用DB::raw('...')编写查询,不介意手动编写长SQL查询,但是我真的想好好尝试一下,尝试使用 Eloquent。

我注意到whereIn 方法,但它只接受一个列名的字符串而不是多列的数组,所以这是不行的。 (除非我遗漏了什么,或者它计划用于 Laravel 的未来版本?)

我从来都不是框架的粉丝,我需要一些令人信服的东西,并且不希望被打败,所以我坚持使用 Laravel。这让我很沮丧,因为我觉得不乱用 Eloquent 会更快。如果我能让这个工作,那么我会更接受它。

【问题讨论】:

所以您希望将employee_vehicle 与员工和车辆放在一起? 简短的回答是肯定的。长答案是肯定的,但是我如何编写我发布的查询 but 使用 Eloquent also 将所有内容放在一起。我不知道我的解释是否正确。 【参考方案1】:

假设你已经

员工模型:

class Employee extends Model 
  protected $table = 'employees';
  public $timestamps = false;

和车辆型号:

class Vehicle extends Model 
  protected $table = 'employees';
  public $timestamps = false;

并且您想获取按车辆 ID 分组的最新日志。

所以做一个模型:

class EmployeeVehicle extends Model 
  protected $table = 'employee_vehicle';
  public $timestamps = false;  

  public function employee() 
    return $this->belongsTo('App\Employee');
  

  public function vehicle() 
    return $this->belongsTo('App\Vehicle');
  

你对 DB 的请求会是这样的:

$EmployeeVehicles = EmployeeVehicle::with(['employee', 'vehicle'])
                                  ->where('date_booked', '>', date('Y-m-d H:i:s', (time() - 3*30*24*60*60)))
                                  ->groupBy('vehicle_id')
                                  ->selectRaw('*, MAX(`date_booked`) AS `last_date_booked`')
                                  ->paginate(50);

附言我添加了where('date_booked', '>', date('Y-m-d H:i:s', (time() - 3*30*24*60*60)),因为您对日志数据库的查询对于数据库引擎来说是一项非常繁重的工作,通常最好拥有过去 3 个月的数据以确保性能安全。

并尝试分页,而不是获取所有内容。

【讨论】:

啊,所以可以将数据透视表变成模型本身吗?这是标准/公认的方法吗?我对此很陌生:)。 是的,当然!口才很强大。如果你的想法有点不同(雄辩的方式)(: Bor me 数据透视表是有 2 个字段但没有 id 字段的表:employee_id、vehicle_id 和数据透视表也可以用作模型。但请记住,您向我们展示的employee_vehicle 不是数据透视表,它更像是一个“日志”表(:

以上是关于Laravel Eloquent 多列 IN 子句的主要内容,如果未能解决你的问题,请参考以下文章

laravel 使用 in 子句模型名称连接多态数据透视表

Laravel Eloquent 关系 - 表的多列引用相同的外键

Laravel 4 Eloquent 动态 Where 子句

如何使用 Laravel Eloquent 创建多个 Where 子句查询?

如何使用 Laravel Eloquent 创建多个 Where 子句查询?

使用 Eloquent 在 Laravel 中使用 where 子句访问嵌套的相关对象