我正在尝试使用 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 注入点。我已经使用 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 范围内)。是否可以在 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 条件。
如果你有一些参数,你可以这样做。
$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();
然后返回您的查询
返回$结果;
您可以在左连接中复制这些括号:
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(''));
})
然后,您必须稍后使用“setBindings”设置绑定,如此 SO 帖子中所述:How to bind parameters to a raw DB query in Laravel that's used on a model?
它不漂亮,但它有效。
像这样的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']);
第二个参数是一个值数组,用于从左到右替换查询中的占位符。
$join->on('winners.year','=',DB::select('?',array('2013'));
但没有奏效。
对于条件参数,我们可以使用 where
,
$results = DB::table('rooms')
->distinct()
->leftJoin('bookings', function($join) use ($param)
{
$join->on('rooms.id', '=', 'bookings.room_type_id')
->where('arrival','=', $param);
})
->where('bookings.room_type_id', '=', NULL)
->get();
我的 5 美分方案 LEFT JOIN ON (.. or ..) and (.. or ..) and ..
->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 );
})
;
})
and arrival >= ? and arrival <= ? and departure >= ? and departure <= ?
而不是AND ( r.arrival between ? and ? OR r.departure between ? and ? )
(请注意OR
子句)。这会将额外的行添加到不应该存在的结果中。我想不可能使用 QB 在 join 中生成所有类型的条件。