如何在 Laravel 中使用 Eloquent 对 NULL 值进行最后排序
Posted
技术标签:
【中文标题】如何在 Laravel 中使用 Eloquent 对 NULL 值进行最后排序【英文标题】:How to sort NULL values last using Eloquent in Laravel 【发布时间】:2013-07-12 17:12:55 【问题描述】:我的员工和组表之间存在多对多关系。我已经创建了数据透视表,并且一切正常。但是,我的员工表上有一个 sortOrder 列,用于确定它们的显示顺序。 sortOrder 列中值为 1 的员工应该排在第一位,值为 2 的员工应该排在第二位,以此类推。 (如果按降序排序,则向后) sortOrder 列是一个允许空值的整数列。
我已设置我的组模型以按排序列对员工进行排序,但我遇到了问题。始终首先显示空值。我尝试使用 ISNULL 和类似的 SQL 方法来代替使用的常规“asc”或“desc”,但我只得到一个错误。
这是我的 Group 模型中的代码:
class Group extends Eloquent
public function employees()
return $this->belongsToMany("Employee")->orderBy('sortOrder', 'asc');
这是我在控制器中用来访问我的模型的内容:
$board = Group::find(6)->employees;
Laravel 中最后排序 NULL 值的技巧是什么?
【问题讨论】:
【参考方案1】:Laravel 没有考虑 ISNULL
方法,但是,您可以将它作为原始查询传递并仍然使用它,因为它比 IF
语句更有效,并且如果您曾经使用过,结果将保持不变超过 1000000 名员工(接受的答案),如下所示:
public function employees()
return $this->hasMany('Employee')
->orderBy(DB::raw('ISNULL(sortOrder), sortOrder'), 'ASC');
更新: 也可以使用orderByRaw() 方法:
public function employees()
return $this->hasMany('Employee')
->orderByRaw('ISNULL(sortOrder), sortOrder ASC');
【讨论】:
这也是适用于非数值(如日期)的有效解决方案。 恕我直言,这是最简单的解决方案。 我试过但得到 mysql 错误。但是通过在顺序的两边添加`来修复'ISNULL(`sortOrder`), `sortOrder` ASC'
【参考方案2】:
只需在字段中添加一个减号并将顺序更改为 DESC。
$q->orderBy(\DB::raw('-`sortOrder`'), 'desc');
【讨论】:
对于 laravel 5.1:$q->orderBy(\DB::raw('-sortOrder'), 'desc'); 对于 Laravel 5.4:$q->orderByRaw("-start_date",'DESC') 对于 Laravel 5.6:$query->orderByRaw('-start_date DESC')
(注意单个字符串而不是第二个参数)。
之前的评论有误,应该是$query->orderByRaw('-`start_date` DESC')
【参考方案3】:
在 Laravel 5.2 或更高版本中,只需调用 orderByRaw
。您甚至可以通过聚合值而不是列进行排序。在以下示例中,如果没有子模型,max_st
可以是 null
。
Model::where('act', '2')
->leftJoin('submodels', 'model.id', '=', 'submodels.model_id')
->select('models.*', DB::raw('MAX(submodels.st) as max_st')),
->orderByRaw('max_st DESC NULLS LAST');
【讨论】:
【参考方案4】:public function employees()
return $this
->hasMany('Employee')
->select(['*', DB::raw('IF(`sortOrder` IS NOT NULL, `sortOrder`, 1000000) `sortOrder`')])
->orderBy('sortOrder', 'asc');
说明: IF 语句在这里解决了这个问题。如果找到 NULL 值,则将一些大数字分配给 sortOrder。如果发现不是 NULL 值,则使用实际值。
【讨论】:
谢谢!这完美!我不知道在 Eloquent 中可以使用 Fluent 链方法。 你能告诉我选择中括号的重要性吗?我对他们有一个奇怪的问题。我有两台开发计算机,其中一台没有括号问题,另一台抛出 FatalErrorException。我把它们拿出来了,现在两台电脑都可以用了,我的查询结果好像没变。 传递给select()
方法的括号只不过是数组的新语法。您会遇到问题,因为此功能是 php 5.4 附带的新功能。您的一台计算机运行 5.4,另一台不运行。见php.net/manual/en/language.types.array.php 或php.net/manual/en/migration54.new-features.php
这看起来是个坏习惯。【参考方案5】:
您还可以这样做:
public function employees()
return $this
->hasMany('Employee')
->select(['*', DB::raw('sortOrder IS NULL AS sortOrderNull')])
->orderBy('sortOrderNull')
->orderBy('sortOrder');
SQLite 支持它还有一个额外的好处。
【讨论】:
【参考方案6】:我最近使用 Laravel 5.6 遇到了这个问题,其中 junkystu 的答案对我来说是完美的。但是我们的测试框架使用 sqlite,所以测试总是返回 500 错误。
这是我们想出的,它应该与 DB 驱动程序稍微无关。
升序
$query->orderBy(DB::raw('column_to_sort IS NULL, column_to_sort'), 'asc');
降序
$query->orderBy(DB::raw('column_to_sort IS NOT NULL, column_to_sort'), 'desc');
【讨论】:
【参考方案7】:PostgreSQL 的解决方法
对于数字类型:
DB::table('t')
->select(['id', 'val'])
->orderBy(DB::raw("coalesce(val, 0)"), 'desc')
对于文本类型:
orderBy(DB::raw("coalesce(val, '')"), 'desc')
诀窍是将排序列中的NULL
值替换为零(或空字符串),以便可以将其排序为普通整数(或文本)值。
【讨论】:
【参考方案8】:->orderBy('sortOrder', 'is', 'null')->orderBy('sortOrder', 'asc')
似乎有效。
【讨论】:
实际上,这会创建一个包含order by sortOrder DESC, sortOrder ASC
的查询,该查询不会最后添加 NULL 值。
@junkystu:你是如何验证的?我还没有设法让 SQL 日志记录工作。我正在使用 Eloquent 5.0 顺便说一句。
使用debug bar,它非常好,甚至可以让您查看通过 ajax 运行的查询以及其他有用的东西以上是关于如何在 Laravel 中使用 Eloquent 对 NULL 值进行最后排序的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Eloquent 在 Laravel 中开始查询?
如何在 laravel 5 中使用 Eloquent 更新数据透视表
如何在 Eloquent 模型中使用 Laravel Livewire?