Как я могу преобразовать этот sql запрос в красноречивую команду laravel? - PullRequest
2 голосов
/ 18 февраля 2020

в sql запросить этот коммандос сделать именно то, что я хотел:

SELECT 
    v.id,
    ( 
        SELECT sv.status_id 
        FROM status_viagem sv 
        WHERE sv.viagem_id = v.id 
        ORDER BY sv.created_at DESC LIMIT 1 ) AS status_id
FROM viagens v

Вот результаты sql:

enter image description here

Но я понятия не имею, как я могу сделать это, используя Laravel eloquent

В принципе, запись в viagem может иметь много состояний, но мне нужно получить каждый viagem и их последний статус запись из таблицы status_viagem (сводная таблица)

по пути viagem / viagens означает путешествие.

Отображение моего класса:

class Viagem extends Model
{
  ...
  public function status()
  {
        return $this->belongsToMany('App\Status')->withTimestamps();
  }
  ...
}


class Status extends Model
{

    public function viagens()
    {
        return $this->belongsToMany('App\Viagem')->withTimestamps();
    }
}

В обоих классах принадлежащие мне люди получают много ко многим:

many-to-many

Может ли кто-нибудь мне помочь? спасибо

---------- Временное решение -------

Спасибо за помощь, ребята. На самом деле я не могу найти хорошее решение, используя только красноречивый.

Шаг 1/3 - Чтобы обойти эту ситуацию, я сначала выполняю вышеописанное sql, чтобы захватить только проходы под желаемым status_id (последняя запись status_viagem):

$viagens_ids = DB::select(
            "SELECT viagem_id FROM (
                SELECT 
                    v.id AS viagem_id,
                    ( 
                        SELECT sv.status_id 
                        FROM status_viagem sv 
                        WHERE sv.viagem_id = v.id 
                        ORDER BY sv.id DESC LIMIT 1 ) AS status_id
                FROM viagens v
            ) AS tt

            WHERE tt.status_id = {$status->id}"
        );

Шаг 2 / 3 - затем я использовал array_map для организации своих идентификаторов viagens

$a = array_map(
                function($obj) { return $obj->viagem_id; }, 
                $viagens_ids
            );

Шаг 3/3 - И наконец, я использовал elequent whereIn для получения моих viagens:

 Viagem::with( 'status')->whereIn('id', $a)->get();

Фактически я Я решил эту проблему по-старому, но я не доволен этим, потому что я sh узнаю, как это сделать, используя eloquent. что плохо для меня.

Ответы [ 3 ]

1 голос
/ 19 февраля 2020

Существует множество способов сделать запрос в laravel. Я создал тестовый проект для вас, чтобы попробовать. Суть:

1. Eloquent ORM

Eloquent ORM - это маги Laravel c, которые имеют некоторые ограничения в стремительной загрузке - с которыми я просто сталкиваюсь, обдумывая ваш вопрос в течение нескольких часов. Он не будет хорошо работать с first(), last() и некоторыми другими функциями в ограниченном нетерпеливом закрытии загрузки.

В вашем случае наше почти там можно исправить:

   App\Models\Viagem::with(['status' => function($query){
          return $query->orderBy('pivot_created_at', 'desc');
         }])
        ->get()

Он вернет все поле для Viagem и Status, включая его сводную таблицу (status_viagem).

Однако, если вы хотите получить только viagem.id и status_viagem.status_id, вы можете map() это так:

   App\Models\Viagem::with(['status' => function($query){
           return $query->orderBy('pivot_created_at', 'desc');
         }])
        ->get()
        ->map(function($data){
           $o = new stdClass();
           $o->id = $data->id;
           $o->status_id = $data->status->first()->id;
           return $o;
        });

Обратите внимание, что приведенное выше утверждение требует, чтобы sql запрос выполнялся дважды. Стремительная загрузка в основном работает, сначала запрашивая все Viagem, затем запрашивая Status и отображая их в памяти на основе внешних ключей. Вы можете заметить, что замена get на toSql даст вам только первый запрос. Пожалуйста, включите Журнал запросов , чтобы увидеть второй запрос.

2. Query Builder

Начиная с ответа Ryan Adhitama Putra , вы можете сделать что-то вроде:

   App\Models\Viagem::join('status_viagem', 'viagens.id', '=', 'status_viagem.viagem_id')
       ->orderBy('status_viagem.created_at', 'desc')
       ->groupBy(['status_viagem.status_id', 'viagens.id'])
       ->select(['viagens.id', 'status_viagem.status_id'])
       ->get();

Этот подход к построителю запросов гарантированно будет запущен только один раз, его можно заменить get() с toSql() для просмотра результирующего запроса.

3. Необработанные запросы

Метание DB::raw() может когда-нибудь помочь, но я действительно не хотел об этом упоминать.

0 голосов
/ 18 февраля 2020

Попробуйте это.

$status_id = Viagem::join('status','viagem.id','status_viagem.viagem_id')
             ->select('viagem.id','status_viagem.status_id')
             ->get();
0 голосов
/ 18 февраля 2020

Я не уверен, что представляют собой viagens и viagem, но я думаю, что одно из отношений должно принадлежать toTany (), а другое hasMany ().

тогда после правильной установки отношений вы можете использовать Eloquent как это:

$status_id = Viagem::with('status')->orderBy('created_at', 'desc')->first()->pluck('status_id');

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...