web-dev-qa-db-fra.com

Une jointure avec des conditions supplémentaires à l'aide de Query Builder ou Eloquent

J'essaie d'ajouter une condition en utilisant une requête JOIN avec 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')
);

Je sais que je peux utiliser expressions brutes mais alors il y aura des points d'injection SQL. J'ai essayé ce qui suit avec Query Builder mais la requête générée (et évidemment les résultats de la requête) ne correspond 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();

Voici 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 constater, la sortie de la requête n'a pas la structure (en particulier dans la portée JOIN). Est-il possible d'ajouter des conditions supplémentaires sous JOIN?

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

66
dede
$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 between peut être ajoutée à la jointure dans laravel.

Notes:

  • DB::raw() indique à Laravel de ne pas remettre les guillemets).
  • En passant une fermeture aux méthodes de jointure, vous pouvez y ajouter d'autres conditions de jointure, on() ajoutera AND condition et orOn() ajoutera OR condition.
97
Abishek

Vous pouvez reproduire ces crochets 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 devrez ensuite définir les liaisons ultérieurement à l'aide de "setBindings" comme décrit dans ce SO post: Comment lier des paramètres à une requête de base de données brute dans Laravel utilisé sur un modèle?

Ce n'est pas joli mais ça marche.

32
rickywiens

Si vous avez des paramètres, 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();

puis retournez votre requête

retourne $ résultats;

23
vroldan

l'exemple de requête SQL comme celui-ci

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

Laravel rejoindre avec 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);
    });
})
13
Majbah Habib

J'utilise laravel5.2 et nous pouvons ajouter des jointures avec différentes options que vous pouvez modifier selon vos besoins.

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();
8
Abid Ali

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

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

Un petit exemple:

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

Le deuxième paramètre est un tableau de valeurs qui seront utilisées pour remplacer les espaces réservés dans la requête de gauche à droite.

3
Jason Lewis