如何在 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/Eloquent 中获得完整的关系

如何在 laravel 5 中使用 Eloquent 更新数据透视表

如何在 Eloquent 模型中使用 Laravel Livewire?

如何在 Laravel 4 中手动创建一个新的空 Eloquent 集合

如何使用 eloquent 在 laravel 迁移中删除 POSTGRES 表或视图?