MySQL Orderby по числу, нуля последний


280

В настоящее время я делаю очень простой OrderBy в своем заявлении.

SELECT * FROM tablename WHERE visible=1 ORDER BY position ASC, id DESC

Проблема в том, что записи NULL для 'position' обрабатываются как 0. Поэтому все записи с позицией как NULL появляются раньше, чем с 1,2,3,4. например:

NULL, NULL, NULL, 1, 2, 3, 4

Есть ли способ добиться следующего заказа:

1, 2, 3, 4, NULL, NULL, NULL.

8
Вам следует пересмотреть ответ пользователя 1052545. Это проще, не требует знания максимальных значений и может быть быстрее (при условии, что вычисление выражения может быть быстрее, чем вызов функции).
Стив Клей

Ответы:


568

MySQL имеет недокументированный синтаксис для сортировки нулей в последнюю очередь. Поместите знак минус (-) перед именем столбца и переключите ASC на DESC:

SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC, id DESC

Это, по сути, обратное position DESCразмещение значений NULL последними, но в остальном то же самое, что и position ASC.

Хорошая ссылка здесь http://troels.arvin.dk/db/rdbms#select-order_by


79
Это не документально, - col_nameэто выражение ( 0 - col_name), которое принимает предложение ORDER BY. Конечно, это работает только для числовых столбцов.
Стив Клей

7
Хороший. Работы для dateи timeколонки тоже! (MySQL 5.5). Я думаю (мне лень проверять) это работает для всех числовых столбцов (timestamp, float ...).
Мартин

6
@koral: это простое (и полезное) математическое выражение, которое переворачивает порядок, оно не будет удалено, если сам язык не изменится кардинально.
Белл

11
Как следует из комментариев, это работает для числовых столбцов, столбцов даты и времени? Но как насчет varchar? Может ли это быть применено и к varchar? Я попытался применить его к полям varchar, но порядок, по-видимому, отличается от использования ASC или DESC.
Sumit Desai

9
Не помешает ли это использованию возможного индекса для заказа по столбцу?
Тарсис

306

Я нашел это, чтобы быть хорошим решением по большей части:

SELECT * FROM table ORDER BY ISNULL(field), field ASC;

6
Без переопределения порядка работ: SELECT * FROM table ORDER BY ISNULL(field) ASC;(MySQL 5.5)
Marçal Juan

5
Это лучшее решение.
Рок Краль

4
Принятое решение не работает с TIMESTAMP в postgresql 9.3. Это решение делает ...
Калу

2
Досадно, что MySQL не будет использовать индекс по полю, когда вы добавляете isnull (поле) к предложению order by (при использовании limit).
Барри Келли

3
@kalu: в PostgreSQL значения NULL сортируются последними в порядке возрастания (и сначала в порядке убывания). И вы бы предпочли использовать стандартное предложение SQLNULLS LAST | NULLS FIRSTперевернуть его вместо обходных путей здесь.
Эрвин Брандштеттер

23

Что-то вроде

SELECT * FROM tablename where visible=1 ORDER BY COALESCE(position, 999999999) ASC, id DESC

Замените 999999999 на максимальное значение для поля.


3
Это решение хрупкое и может привести к периодическим ошибкам
Дмитрий Богданович


4

Вы можете поменять экземпляры NULL с другим значением, чтобы отсортировать их сначала (например, 0 или -1) или в последнюю очередь (большое число или буква) ...

SELECT field1, IF(field2 IS NULL, 9999, field2) as ordered_field2
  FROM tablename
 WHERE visible = 1
 ORDER BY ordered_field2 ASC, id DESC

Это не решит проблему, поскольку индекс, на который ссылается ORDER BY, не будет затронут заменой значений в инструкции SELECT и, следовательно, не исправит порядок. Также проверьте функцию COALESCE, которая функционально эквивалентна использованию вами функции IF.
определяет

Если вы правильно используете псевдоним оператора IF, строки упорядочиваются так, как вы ожидаете. Я исправил мой пример.
Лэнгдон

4

Попробуйте использовать этот запрос:

SELECT * FROM tablename
WHERE visible=1 
ORDER BY 
CASE WHEN position IS NULL THEN 1 ELSE 0 END ASC,id DESC

Нет необходимости в случае. IS NULL возвращает 1, когда выражение NULL. Смотрите ответ ревербации.
contactmatt

3

Вы можете объединить ваши NULL в ORDER BYутверждении:

select * from tablename
where <conditions>
order by
    coalesce(position, 0) ASC, 
    id DESC

Если вы хотите, чтобы значения NULL сортировались снизу, попробуйте coalesce(position, 100000). (Сделайте второе число больше, чем все остальные positionв БД.)


3
SELECT * FROM tablename WHERE visible=1 ORDER BY CASE WHEN `position` = 0 THEN 'a' END , position ASC

6
Почему ОП должен попробовать это ? Хорошие ответы всегда будут содержать объяснение того, что было сделано и почему это было сделано не только для ОП, но и для будущих посетителей SO, которые могут найти этот вопрос и прочитать ваш ответ.
RiggsFolly

2

Для DATEстолбца вы можете использовать:


NULLS последний:

ORDER BY IFNULL(`myDate`, '9999-12-31') ASC

Бланки последние:

ORDER BY IF(`myDate` = '', '9999-12-31', `myDate`) ASC

1

Для достижения следующего результата:

1, 2, 3, 4, NULL, NULL, NULL.

ИСПОЛЬЗУЙТЕ синтаксис, -(minus sign)ставьте перед именем поля и используйте обратный тип_порядка (например: если вы хотите упорядочить по порядку ASC, используйте DESC или, если вы хотите порядок DESC, используйте ASC)

SELECT * FROM tablename WHERE visible=1 ORDER BY -position DESC


1

Это работает нормально:

SELECT * FROM tablename ORDER BY position = 0, position ASC;

position
1 
2
3
0
0

-8

Почему бы вам не заказать NULLS LAST?

SELECT * 
FROM tablename
WHERE visible = 1 
ORDER BY position ASC NULLS LAST, id DESC 

NULLS LAST- какая версия MySQL была представлена?
crmpicco

2
@Panique, Вы имеете в виду (MS) SQL Server?
d -_- b

1
этот ответ не относится к MySQL
PeppyHeppy
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.