Как отсортировать значения NULL последними с помощью Eloquent в Laravel

У меня много отношений между моими сотрудниками и таблицей групп. Я создал сводную таблицу, и все работает с ней правильно. Однако у меня есть столбец sortOrder в таблице моих сотрудников, который я использую для определения порядка их отображения. Сотрудник со значением 1 в столбце sortOrder должен быть первым, значение 2 должно быть вторым и т. Д. (Или назад, если сортировка по убыванию) Столбец sortOrder - это целочисленный столбец, который допускает нулевые значения.

Я настроил свою групповую модель для сортировки сотрудников по столбцу сортировки, но столкнулся с проблемой. Нулевые значения всегда отображаются первыми. Я пробовал использовать ISNULL и аналогичные методы SQL вместо обычных «asc» или «desc», но получаю только сообщение об ошибке.

Вот код в моей модели группы:

class Group extends Eloquent {

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

И вот что я использую в контроллере для доступа к моей модели:

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

Какая уловка в Laravel для сортировки значений NULL последними?


person eagle0042    schedule 14.07.2013    source источник


Ответы (8)


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');
}
person junkystu    schedule 19.04.2015
comment
Это рабочее решение также для нечисловых значений, таких как даты. - person Maciej Sikora; 20.02.2017
comment
ИМХО, это наименее хакерское решение. - person richplane; 04.07.2018
comment
Я пробовал, но получил ошибку mysql. но исправлено добавлением `в обе стороны порядка, подобного этому 'ISNULL(`sortOrder`), `sortOrder` ASC' - person Babak Asadzadeh; 16.05.2020

Просто добавьте в поле знак минус и измените порядок на DESC.

$q->orderBy(\DB::raw('-`sortOrder`'), 'desc');
person miller    schedule 29.07.2015
comment
Для laravel 5.1: $ q- ›orderBy (\ DB :: raw ('- sortOrder'), 'desc'); - person Blum; 05.10.2015
comment
Для Laravel 5.4: $ q- ›orderByRaw (-start_date, 'DESC') - person BassMHL; 27.04.2017
comment
А для Laravel 5.6: $query->orderByRaw('-start_date DESC') (обратите внимание на одну строку вместо второго параметра). - person Sebastiaan Luca; 26.08.2018
comment
предыдущий комментарий неверен, должно быть $query->orderByRaw('-`start_date` DESC') - person Hlorofos; 15.03.2021

В 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');
person shukshin.ivan    schedule 20.09.2016

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 значение, используется реальное значение.

person Andreyco    schedule 14.07.2013
comment
Спасибо! Это прекрасно работает! Я не знал, что в Eloquent можно использовать цепные методы Fluent. - person eagle0042; 15.07.2013
comment
Не могли бы вы сказать, насколько важны скобки при выборе? У меня с ними странная проблема. У меня два компьютера для разработки, и один из них не имеет проблем с скобками, другой выдает исключение FatalErrorException. Я вынул их, теперь он работает на обоих компьютерах, и результат моего запроса, похоже, не изменился. - person eagle0042; 16.07.2013
comment
Скобки, переданные select() методам, представляют собой не что иное, как новый синтаксис для массива. Вы столкнулись с проблемой, потому что эта функция новая, она поставляется с PHP 5.4. На одном из ваших компьютеров установлена ​​версия 5.4, а на другом - нет. См. php.net/manual/en/language.types.array.php или php.net/manual/en/migration54.new-features.php - person Andreyco; 16.07.2013
comment
Это похоже на плохую практику. - person Christopher; 14.08.2015

Вместо того, чтобы полагаться на произвольно большое число, вы также можете:

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

У него есть дополнительное преимущество, заключающееся в поддержке SQLite.

person Juliusz Gonera    schedule 13.02.2014

Недавно я столкнулся с этой проблемой, используя Laravel 5.6, где ответ junkystu был идеальным для меня. Однако наша среда тестирования использует sqlite, поэтому тесты постоянно возвращали ошибку 500.

Это то, что мы придумали, и он должен быть немного более независимым от драйвера БД.

По возрастанию

$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');
person Fillie    schedule 08.08.2018

Обходной путь для PostgreSQL

Для числовых типов:

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

Для текстовых типов:

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

Уловка состоит в том, чтобы заменить NULL значения в столбце сортировки на ноль (или пустую строку), чтобы его можно было отсортировать как обычное целое (или текстовое) значение.

person AlexM    schedule 18.03.2016

->orderBy('sortOrder', 'is', 'null')->orderBy('sortOrder', 'asc')

Кажется, работает.

person Bruce van der Kooij    schedule 18.04.2015
comment
Фактически, это создает запрос, содержащий order by sortOrder DESC, sortOrder ASC, который не добавляет последние значения NULL. - person junkystu; 19.04.2015
comment
@junkystu: Как вы это проверили? Мне еще не удалось заставить работать журнал SQL. Кстати, я использую Eloquent 5.0. - person Bruce van der Kooij; 19.04.2015
comment
используйте панель отладки, это очень удобно и даже позволяет вам видеть запросы, которые выполняются через ajax среди другие полезные вещи - person junkystu; 19.05.2015