将原始SQL迁移到雄辩 [英] Migrating Raw SQL to Eloquent

查看:74
本文介绍了将原始SQL迁移到雄辩的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一些Raw SQL迁移到模型上的Eloquent(或查询生成器)范围.我的零件历史记录表如下所示:

I am trying to migrate some Raw SQL to an Eloquent (or Query Builder) scope on my model. My Parts history table looks like this:

+----+---------+--------+------------+
| 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可以具有状态相同的多个条目.

Notice the same part_id can have multiple entries where the status is the same.

此刻,我使用以下选项选择最新状态:

At the moment I use the following to select the latest status:

$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( ... )

到目前为止,我正在尝试在零件模型上建立作用域,

I am trying to make a scope on the parts model out of this, so far I have this:

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),我无法弄清其余部分

which is part way there (but still using some raw SQL), I just can't figure out the rest

推荐答案

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

You could rewrite your query as left join to get the same results

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

我想您可以在您的范围内轻松地在查询之上进行转换,例如

and I guess you can transform easily above query in your scope something like

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选择具有max的所有行created_at

Laravel-获取以下项的最后一个条目每个UID类型

按最新记录记录的Laravel口才组

使用上述查询作为has关系进行编辑,要获取每个零件的最新历史记录,您可以定义一个hasOne关系,例如

Edit using above query as has relation,To get the latest history for each part you can define a hasOne relation like

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.*');
    }
}

然后要加载具有其最新历史记录的零件,您可能希望将已定义的映射加载为

And then to load parts with their latest history you could eager load above defined mapping as

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

您将拥有一份零件清单以及最新的历史记录,

You will have a list of parts along with latest history as

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
                )

        )
....
)

这篇关于将原始SQL迁移到雄辩的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆