ПРИСОЕДИНЕНИЕ с дополнительными условиями с использованием Query Builder или Eloquent

Я пытаюсь добавить условие, используя запрос JOIN с Laravel Query Builder.

<?php

$results = DB::select('
       SELECT DISTINCT 
          *
          FROM 
             rooms 
                LEFT JOIN bookings  
                   ON rooms.id = bookings.room_type_id
                  AND (  bookings.arrival between ? and ?
                      OR bookings.departure between ? and ? )
          WHERE
                bookings.room_type_id IS NULL
          LIMIT 20',
    array('2012-05-01', '2012-05-10', '2012-05-01', '2012-05-10')
);

Я знаю, что могу использовать сырые выражения, но тогда будут точки внедрения SQL. Я пробовал следующее с Query Builder, но сгенерированный запрос (и, очевидно, результаты запроса) не то, что я планировал:

$results = DB::table('rooms')
    ->distinct()
    ->leftJoin('bookings', function ($join) {
        $join->on('rooms.id', '=', 'bookings.room_type_id');
    })
    ->whereBetween('arrival', array('2012-05-01', '2012-05-10'))
    ->whereBetween('departure', array('2012-05-01', '2012-05-10'))
    ->where('bookings.room_type_id', '=', null)
    ->get();

Это сгенерированный запрос Laravel:

select distinct * from `room_type_info`
    left join `bookings` 
on `room_type_info`.`id` = `bookings`.`room_type_id` 
where `arrival` between ? and ? 
    and `departure` between ? and ? 
    and `bookings`.`room_type_id` is null

Как видите, выходные данные запроса не имеют структуры (особенно в области JOIN). Можно ли добавить дополнительные условия под ПРИСОЕДИНЕНИЕ?

Как я могу создать тот же запрос с помощью Laravel Query Builder (если возможно). Лучше использовать Eloquent или лучше использовать DB :: select?


person dede    schedule 31.05.2013    source источник


Ответы (7)


$results = DB::table('rooms')
                     ->distinct()
                     ->leftJoin('bookings', function($join)
                         {
                             $join->on('rooms.id', '=', 'bookings.room_type_id');
                             $join->on('arrival','>=',DB::raw("'2012-05-01'"));
                             $join->on('arrival','<=',DB::raw("'2012-05-10'"));
                             $join->on('departure','>=',DB::raw("'2012-05-01'"));
                             $join->on('departure','<=',DB::raw("'2012-05-10'"));
                         })
                     ->where('bookings.room_type_id', '=', NULL)
                     ->get();

Не совсем уверен, можно ли добавить предложение between к соединению в laravel.

Примечания:

  • DB::raw() указывает Laravel не возвращать кавычки.
  • Передав замыкание методам соединения, вы можете добавить к нему дополнительные условия соединения, on() добавит AND условие, а orOn() добавит OR условие.
person Abishek    schedule 31.05.2013
comment
Спасибо за ответ. К сожалению, сгенерированный запрос немного отличается, так как условие соединения теперь имеет and arrival >= ? and arrival <= ? and departure >= ? and departure <= ? вместо AND ( r.arrival between ? and ? OR r.departure between ? and ? ) (обратите внимание на предложение OR). Это добавляет к результату дополнительные строки, которых там не должно быть. Я предполагаю, что с помощью QB невозможно сгенерировать все типы условий при объединении. - person dede; 31.05.2013
comment
На самом деле я заметил, что? не добавляется в предложения ON. Эти значения в ON не параметризованы и не защищены от SQL-инъекции. Я отправил вопрос, пытаясь найти решение. - person prograhammer; 19.07.2013
comment
это не отвечало на исходный вопрос, который содержал предложение или, которое было проигнорировано в этом ответе. - person ionescho; 20.05.2015
comment
Идеальное решение. Просто не забудьте использовать DB :: raw при использовании значения, иначе Laravel (по крайней мере, в 5.6.29) добавит обратные кавычки и нарушит цель. - person Adrian Hernandez-Lopez; 26.09.2018

Вы можете скопировать эти скобки в левом соединении:

LEFT JOIN bookings  
               ON rooms.id = bookings.room_type_id
              AND (  bookings.arrival between ? and ?
                  OR bookings.departure between ? and ? )

is

->leftJoin('bookings', function($join){
    $join->on('rooms.id', '=', 'bookings.room_type_id');
    $join->on(DB::raw('(  bookings.arrival between ? and ? OR bookings.departure between ? and ? )'), DB::raw(''), DB::raw(''));
})

Затем вам нужно будет установить привязки позже, используя "setBindings", как описано в этом сообщении SO: Как привязать параметры к необработанному запросу БД в Laravel, который используется в модели?

Это некрасиво, но работает.

person rickywiens    schedule 03.10.2014

Если у вас есть параметры, вы можете это сделать.

    $results = DB::table('rooms')
    ->distinct()
    ->leftJoin('bookings', function($join) use ($param1, $param2)
    {
        $join->on('rooms.id', '=', 'bookings.room_type_id');
        $join->on('arrival','=',DB::raw("'".$param1."'"));
        $join->on('arrival','=',DB::raw("'".$param2."'"));

    })
    ->where('bookings.room_type_id', '=', NULL)
    ->get();

а затем верните свой запрос

return $ results;

person vroldan    schedule 17.06.2014
comment
в случае условий для соединения вы можете использовать $ join- ›where () внутри левого соединения вместо DB :: raw - person TTT; 05.07.2021

Пример запроса sql, подобный этому

LEFT JOIN bookings  
    ON rooms.id = bookings.room_type_id
    AND (bookings.arrival = ?
        OR bookings.departure = ?)

Присоединение к Laravel с несколькими условиями

->leftJoin('bookings', function($join) use ($param1, $param2) {
    $join->on('rooms.id', '=', 'bookings.room_type_id');
    $join->on(function($query) use ($param1, $param2) {
        $query->on('bookings.arrival', '=', $param1);
        $query->orOn('departure', '=',$param2);
    });
})
person Majbah Habib    schedule 01.08.2016

Я использую laravel5.2, и мы можем добавлять соединения с различными параметрами, которые вы можете изменить в соответствии с вашими требованиями.

Option 1:    
    DB::table('users')
            ->join('contacts', function ($join) {
                $join->on('users.id', '=', 'contacts.user_id')->orOn(...);//you add more joins here
            })// and you add more joins here
        ->get();

Option 2:
    $users = DB::table('users')
        ->join('contacts', 'users.id', '=', 'contacts.user_id')
        ->join('orders', 'users.id', '=', 'orders.user_id')// you may add more joins
        ->select('users.*', 'contacts.phone', 'orders.price')
        ->get();

option 3:
    $users = DB::table('users')
        ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
        ->leftJoin('...', '...', '...', '...')// you may add more joins
        ->get();
person Abid Ali    schedule 03.08.2016

Есть разница между необработанными запросами и стандартными выборками (между методами DB::raw и DB::select).

Вы можете делать то, что хотите, используя DB::select и просто вставляя ? заполнитель, так же, как вы делаете с подготовленными операторами (это фактически то, что он делает).

Небольшой пример:

$results = DB::select('SELECT * FROM user WHERE username=?', ['jason']);

Второй параметр - это массив значений, который будет использоваться для замены заполнителей в запросе слева направо.

person Jason Lewis    schedule 31.05.2013
comment
Означает ли это, что параметры автоматически экранируются (за исключением SQL-инъекции)? - person dede; 31.05.2013
comment
Да, это просто оболочка для подготовленных операторов PDO. - person Jason Lewis; 31.05.2013
comment
Есть ли способ использовать эту технику в предложении ON в левом соединении? См. Мой вопрос здесь. Я попытался внутри закрытия leftJoin сделать $join->on('winners.year','=',DB::select('?',array('2013'));, но не сработало. - person prograhammer; 19.07.2013
comment
это не совсем то, насколько красноречиво предназначено для работы. вы могли бы просто сделать DB :: raw () и сделать это самостоятельно - person mydoglixu; 09.06.2015

Мои пять центов за схему LEFT JOIN ON (.. или ..) и (.. или ..) и ..

    ->join('checks','checks.id','check_id')
    ->leftJoin('schema_risks', function (JoinClause $join) use($order_type_id, $check_group_id,  $filial_id){
        $join->on(function($join){
            $join->on('schema_risks.check_method_id','=', 'check_id')
                ->orWhereNull('schema_risks.check_method_id')
                ;
        })
        ->on(function($join) use ($order_type_id) {
            $join->where('schema_risks.order_type_id', $order_type_id)
                ->orWhereNull('schema_risks.order_type_id')
                ;
        })
        ->on(function($join) use ($check_group_id) {
            $join->where('schema_risks.check_group_id', $check_group_id)
                ->orWhereNull('schema_risks.check_group_id')
                ;
        })
        ->on(function($join) use($filial_id){
            $join->whereNull('schema_risks.filial_id');
            if ($filial_id){
                $join->orWhere('schema_risks.filial_id', $filial_id);
            }
        })            
        ->on(function($join){
            $join->whereNull('schema_risks.check_risk_level_id')
                ->orWhere('schema_risks.check_risk_level_id', '>' , CheckRiskLevel::CRL_NORMALLLY );
        })
        ;
    })
person Solo.dmitry    schedule 01.03.2021