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