首页 文章

将原始SQL迁移到Eloquent

提问于
浏览
4

我正在尝试将一些Raw SQL迁移到我的模型上的Eloquent(或Query Builder)范围 . 我的零件历史表如下所示:

+----+---------+--------+------------+
| id | part_id | status | created_at |
+----+---------+--------+------------+
|  1 |       1 |      1 | ...        |
|  2 |       1 |      2 | ...        |
|  3 |       2 |      1 | ...        |
|  4 |       1 |      2 | ...        |
|  5 |       2 |      2 | ...        |
|  6 |       1 |      3 | ...        |

请注意,相同的part_id可以有多个状态相同的条目 .

目前我使用以下内容选择最新状态:

$part = Part::leftjoin( DB::raw("
 (SELECT t1.part_id, ph.status, t1.part_status_at 
  FROM (
    SELECT part_id, max(created_at) part_status_at
    FROM part_histories
    GROUP BY part_id) t1 
  JOIN part_histories ph ON ph.part_id = t1.part_id AND t1.part_status_at = ph.created_at) as t2
  )", 't2.part_id', '=', 'parts.id')->where( ... )

我试图在这个部件模型上做一个范围,到目前为止我有这个:

public function scopeWithLatestStatus($query)
{
    return $query->join(DB::raw('part_histories ph'), function ($join) {
         $join->on('ph.part_id', '=', 't1.id')->on('t1.part_status_at', '=', 'ph.created_at');
      })
      ->from(DB::raw('(select part_id as id, max(created_at) part_status_at from part_histories GROUP BY part_id) t1'))
      ->select('t1.id', 'ph.part_status', 't1.part_status_at');
}

这是部分方式(但仍然使用一些原始SQL),我只是无法弄清楚其余的

1 回答

  • 2

    您可以将查询重写为左连接以获得相同的结果

    select a.* 
    from part_histories a
    left join part_histories b on a.part_id = b.part_id 
                                and a.created_at < b.created_at
    where b.part_id is null
    

    我想你可以在你的范围内轻松转换查询

    public function scopeWithLatestStatus($query)
    {
        return $query->leftJoin('part_histories as b', function ($join) {
                    $join->on('a.part_id', '=', 'b.part_id')
                         ->where('a.created_at', '<', 'b.created_at');
                })
            ->whereNull('b.part_id')
            ->from('part_histories as a')
            ->select('a.*');
    }
    

    Laravel Eloquent select all rows with max created_at

    Laravel - Get the last entry of each UID type

    Laravel Eloquent group by most recent record

    使用上面的查询编辑为 has 关系,要获取每个部分的最新历史记录,您可以定义 hasOne 关系,如

    namespace App\Models;
    
    use Illuminate\Database\Eloquent\Model;
    use Illuminate\Support\Facades\DB;
    class Part extends Model
    {
        public function latest_history()
        {
            return $this->hasOne(\App\Models\PartHistory::class, 'part_id')
                ->leftJoin('part_histories as p1', function ($join) {
                    $join->on('part_histories.part_id', '=', 'p1.part_id')
                        ->whereRaw(DB::raw('part_histories.created_at < p1.created_at'));
                })->whereNull('p1.part_id')
                ->select('part_histories.*');
        }
    }
    

    然后加载具有最新历史记录的部件,您可以在上面定义的映射中加载

    $parts = Part::with('latest_history')->get();
    

    您将获得部件列表以及最新历史记录

    Array
    (
        [0] => Array
            (
                [id] => 1
                [title] => P1
                [latest_history] => Array
                    (
                        [id] => 6
                        [created_at] => 2018-06-16 08:25:10
                        [status] =>  1
                        [part_id] => 1
                    )
    
            )
    ....
    )
    

相关问题