Une jointure avec condition supplémentaire en utilisant Query Builder ou Eloquent

j'essaie d'ajouter une condition sur join query en utilisant le constructeur de requêtes de Laravel.

C'est la requête que j'essaie de réécrire avec QB:

 $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')
     );

I know i can use Raw extensions ( http://four.laravel.com/docs/queries#raw-expressions ), mais il y aura alors des points D'injection SQL. J'ai essayé ce qui suit (avec le constructeur de requête), mais la requête générée (et évidemment, les résultats de requête) ne sont pas ce que je voulais:

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

C'est la requête générée par 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

comme vous pouvez le voir, la requête générée n'a pas la structure (surtout sous JOIN scope. Est-il possible d'ajouter une condition supplémentaire sous join in QB?).

Comment puis-je construire la même requête en utilisant le constructeur de requêtes de Laravel (si possible)? Est-il préférable D'utiliser Eloquent, ou de rester avec DB::select?

48
demandé sur dede 2013-05-31 06:43:41

6 réponses

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

pas tout à fait sûr si la clause entre peut être ajoutée à la jointure dans laravel.

Notes:

  • DB::raw() dit à Laravel de ne pas remettre de devis.
  • en passant une fermeture à des méthodes de jointure vous pouvez y ajouter plus de conditions de jointure, on() ajoutera et conditionnera et orOn() ajoutera ou conditionnera.
71
répondu Abishek 2013-05-31 03:18:16

vous pouvez répliquer ces parenthèses dans la jointure de gauche:

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

est

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

vous aurez alors à définir les fixations plus tard en utilisant "setBindings" comme décrit dans ce So post: comment lier des paramètres à une requête DB brute dans Laravel qui est utilisé sur un modèle?

ce n'est pas joli mais ça marche.

28
répondu rickywiens 2017-11-18 05:09:56

si vous avez des params, vous pouvez le faire.

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

et ensuite retourner votre requête

retourner $results;

18
répondu vroldan 2014-06-17 15:35:25

La requête sql exemple comme ceci

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

Laravel joindre à plusieurs conditions

->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);
    });
})
8
répondu Majbah Habib 2018-07-11 04:31:42

j'utilise laravel5.2 et nous pouvons ajouter des jointures avec différentes options, vous pouvez modifier selon votre exigence.

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();
5
répondu Abid Ali 2016-08-03 07:41:25

il y a une différence entre les requêtes brutes et les sélections standard (entre les méthodes DB::raw et DB::select ).

vous pouvez faire ce que vous voulez en utilisant un DB::select et tout simplement tomber dans le ? placeholder un peu comme vous le faites avec des déclarations préparées (c'est en fait ce qu'il fait).

un petit exemple:

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

le second paramètre est un tableau de valeurs qui sera utilisé pour remplacer placeholders dans la requête de gauche à droite.

3
répondu Jason Lewis 2013-05-31 08:45:26