Laravel 同一列上的多个 orderBy
Laravel multiple orderBy on same column
首先,我将包括一些我尝试过的事情,因为我认为这对我正在尝试做的事情来说是不言自明的。
$event->load(['dates' => function($q) {
$q->where( DB::raw('DATE(start_time)'), '>=', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'asc')
->where( DB::raw('DATE(start_time)'), '<', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'desc');
}]);
或
$event->load(['dates' => function($q) {
$q->where( DB::raw('DATE(start_time)'), '>=', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'asc')
->orWhere(function($query) {
$query->where( DB::raw('DATE(start_time)'), '<', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'desc');
});
}]);
我想做什么
我有一个 EVENTS table 与 DATES 有 hasMany
关系。我正在尝试加载相关日期 first 在 ascending 顺序为即将到来的日期然后在 descending 为已经过去的日期排序。
无论我尝试什么,orderBy
总是排序 所有 结果而不是 where
查询。如何解决这个问题?
非常感谢 - 正确答案当然会被投票选为答案。
同一查询不能有两个不同的订单。但是,您可以拥有两个子查询,每个子查询都有自己的顺序,union
按照您希望的方式组合在一起。
好的,实际上找到了两个适合我问题的解决方案。感谢 @Bernie 给了我一个正确方向的推动 - 我不能在同一个查询中有两个不同的订单并寻找类似 union / merge 的东西.
有多个查询
第一行是 Eager Loading 即将到来的日期 $event
。
第二,你得到 过去的日期,第三,你将它们合并在一起。
唯一的坏处 - 您必须执行多个(两个)查询,这不是最佳选择。
$event->load(['dates' => function($q) {
$q->where( DB::raw('DATE(start_time)'), '>=', Carbon::now()->format('Y-m-d') )
->orderBy('start_time');
}]);
$past = $event->dates()
->where( DB::raw('DATE(start_time)'), '<', Carbon::now()->format('Y-m-d') )
->orderBy('start_time', 'desc')
->get();
$event->dates = $event->dates->merge($past);
收集方法
首先,您 Eager Load 属于该事件的所有日期。
你 filter
所有 过去的日期 和 reverse
他们 - 所有这些都是通过使用 收集方法 .
然后你 count
过去的日期,splice
它们来自原始 Collection 并合并新的反向 Collection 返回。
$event->load(['dates' => function($q) {
$q->orderBy('start_time');
}]);
$filtered = $event->dates->filter(function ($item) {
return $item->raw_date < Carbon::now()->format('Y-m-d');
})->reverse();
$event->dates->splice(0, $filtered->count());
$event->dates = $event->dates->merge($filtered);
结论
第一种方法使用两个 查询,这不是最优的 - 第二种方法使用相当多的 收集方法 。
如果有人能指出哪一个更有效率,那将非常有帮助!
首先,我将包括一些我尝试过的事情,因为我认为这对我正在尝试做的事情来说是不言自明的。
$event->load(['dates' => function($q) {
$q->where( DB::raw('DATE(start_time)'), '>=', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'asc')
->where( DB::raw('DATE(start_time)'), '<', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'desc');
}]);
或
$event->load(['dates' => function($q) {
$q->where( DB::raw('DATE(start_time)'), '>=', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'asc')
->orWhere(function($query) {
$query->where( DB::raw('DATE(start_time)'), '<', Carbon::now()->format('Y-m-d'))
->orderBy('start_time', 'desc');
});
}]);
我想做什么
我有一个 EVENTS table 与 DATES 有 hasMany
关系。我正在尝试加载相关日期 first 在 ascending 顺序为即将到来的日期然后在 descending 为已经过去的日期排序。
无论我尝试什么,orderBy
总是排序 所有 结果而不是 where
查询。如何解决这个问题?
非常感谢 - 正确答案当然会被投票选为答案。
同一查询不能有两个不同的订单。但是,您可以拥有两个子查询,每个子查询都有自己的顺序,union
按照您希望的方式组合在一起。
好的,实际上找到了两个适合我问题的解决方案。感谢 @Bernie 给了我一个正确方向的推动 - 我不能在同一个查询中有两个不同的订单并寻找类似 union / merge 的东西.
有多个查询
第一行是 Eager Loading 即将到来的日期 $event
。
第二,你得到 过去的日期,第三,你将它们合并在一起。
唯一的坏处 - 您必须执行多个(两个)查询,这不是最佳选择。
$event->load(['dates' => function($q) {
$q->where( DB::raw('DATE(start_time)'), '>=', Carbon::now()->format('Y-m-d') )
->orderBy('start_time');
}]);
$past = $event->dates()
->where( DB::raw('DATE(start_time)'), '<', Carbon::now()->format('Y-m-d') )
->orderBy('start_time', 'desc')
->get();
$event->dates = $event->dates->merge($past);
收集方法
首先,您 Eager Load 属于该事件的所有日期。
你 filter
所有 过去的日期 和 reverse
他们 - 所有这些都是通过使用 收集方法 .
然后你 count
过去的日期,splice
它们来自原始 Collection 并合并新的反向 Collection 返回。
$event->load(['dates' => function($q) {
$q->orderBy('start_time');
}]);
$filtered = $event->dates->filter(function ($item) {
return $item->raw_date < Carbon::now()->format('Y-m-d');
})->reverse();
$event->dates->splice(0, $filtered->count());
$event->dates = $event->dates->merge($filtered);
结论
第一种方法使用两个 查询,这不是最优的 - 第二种方法使用相当多的 收集方法 。
如果有人能指出哪一个更有效率,那将非常有帮助!