Миграция необработанного SQL в Eloquent - PullRequest
0 голосов
/ 13 июня 2018

Я пытаюсь перенести некоторый 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 Ответ

0 голосов
/ 13 июня 2018

Вы можете переписать ваш запрос как левое соединение, чтобы получить те же результаты

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 выбрать все строки с максимальным созданным_ат

Laravel - Получить последнюю запись каждого типа UID

Laravel Eloquent группы по самой последней записи

Редактировать, используя указанный выше запрос как отношение 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
                )

        )
....
)
...