Laravel Query BuilderでJOINクエリを使用して条件を追加しようとしています。
<?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')
);
Raw Expressions を使用できることはわかっていますが、SQLインジェクションポイントがあります。クエリビルダーで次のことを試しましたが、生成されたクエリ(そして明らかにクエリ結果)は意図したものではありません。
$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スコープの下)。 JOINの下に条件を追加することはできますか?
Laravelのクエリビルダーを使用して同じクエリを作成するにはどうすればよいですか(可能であれば)Eloquentを使用する方が良いですか、DB :: selectのままにする必要がありますか?
$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
条件を追加します。左結合でこれらの括弧を複製できます。
LEFT JOIN bookings
ON rooms.id = bookings.room_type_id
AND ( bookings.arrival between ? and ?
OR bookings.departure between ? and ? )
は
->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(''));
})
その後、このSOポストで説明されているように、「setBindings」を使用して後でバインディングを設定する必要があります。 Laravelモデルで使用されていますか?
きれいではありませんが、機能します。
いくつかのパラメータがある場合、これを行うことができます。
$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();
その後、クエリを返します
$ resultsを返します。
このような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);
});
})
私は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();
生のクエリと標準の選択(DB::raw
メソッドとDB::select
メソッドの間)には違いがあります。
DB::select
を使用し、準備されたステートメントで行うのと同じように?
プレースホルダーにドロップするだけで、必要な処理を実行できます(実際に実行されます)。
小さな例:
$results = DB::select('SELECT * FROM user WHERE username=?', ['jason']);
2番目のパラメーターは、クエリ内のプレースホルダーを左から右に置き換えるために使用される値の配列です。