web-dev-qa-db-ja.com

LaravelでEloquentを使用して最後にNULL値をソートする方法

従業員とグループのテーブルの間には、多対多の関係があります。ピボットテーブルを作成しましたが、すべて正しく動作しています。しかし、従業員テーブルにsortOrder列があり、それを使用して、それらが表示される順序を決定しています。 sortOrder列の値が1の従業員が最初になり、2の値が2番目になるというようになります。 (または降順でソートされている場合は逆)sortOrder列は、null値を許可する整数列です。

従業員を並べ替え列で並べ替えるようにグループモデルを設定しましたが、問題が発生しました。 null値は常に最初に表示されます。通常の "asc"または "desc"の代わりにISNULLおよび同様のSQLメソッドを使用しようとしましたが、エラーしか表示されません。

これが私のグループモデルのコードです。

class Group extends Eloquent {

public function employees()
    {
        return $this->belongsToMany("Employee")->orderBy('sortOrder', 'asc');
    }
}

そして、これがモデルにアクセスするためにコントローラーで使用するものです:

$board = Group::find(6)->employees;

NULL値を最後にソートするためのLaravelのトリックは何ですか?

24
eagle0042
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値でない場合は、実際の値が使用されます。

6
Andreyco

LaravelはISNULLメソッドを考慮していませんが、IFステートメントよりも効率的であり、結果は同じままなので、生のクエリとして渡して使用することができます。次のように、1000000人の従業員(受け入れられた回答)を超える場合:

public function employees()
{
    return $this->hasMany('Employee')
                ->orderBy(DB::raw('ISNULL(sortOrder), sortOrder'), 'ASC');
}

Update:orderByRaw() メソッドを使用することもできます:

public function employees()
{
    return $this->hasMany('Employee')
                ->orderByRaw('ISNULL(sortOrder), sortOrder ASC');
}
40
junkystu

マイナス記号をフィールドに追加し、順序をDESCに変更するだけです。

$q->orderBy(\DB::raw('-`sortOrder`'), 'desc');
26
miller

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');
7
shukshin.ivan

任意の大きな数に依存する代わりに、次のことも実行できます。

public function employees()
{
    return $this
        ->hasMany('Employee')
        ->select(['*', DB::raw('sortOrder IS NULL AS sortOrderNull')])
        ->orderBy('sortOrderNull')
        ->orderBy('sortOrder');
}

SQLiteによってサポートされるという追加の利点があります。

4
Juliusz Gonera

私は最近、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');
3
Fillie

PostgreSQLの回避策

数値型の場合:

DB::table('t')
    ->select(['id', 'val'])
    ->orderBy(DB::raw("coalesce(val, 0)"), 'desc')

テキストタイプの場合:

orderBy(DB::raw("coalesce(val, '')"), 'desc')

トリックは、通常の整数(またはテキスト)値としてソートできるように、ソート列のNULL値をゼロ(または空の文字列)に置き換えることです。

0
AlexM