Почему NULL сортируются первыми?

20

Почему при наличии значения NULL в столбце и упорядочении по возрастанию значения NULL сортируются первыми?

select 1 as test
union all
select 2
union all
select NULL
union all
select 3
union all
select 4
order by test

результаты в

NULL
1
2
3
4

Я продолжаю думать, что NULL означает «неопределенный» или возможный «неизвестный». Если это правда, не будут ли они сортировать в последнюю очередь, так как значение может быть больше, чем все другие значения? (Или это где-то вариант сортировки?)

Я использую SQL Server 2008R2, но подозреваю, что это верно для всех SQL-серверов и, вероятно, для всех СУБД.

Ричард
источник
1
Oracle перечисляет это в последнюю очередь. Это обидело меня однажды, полагая, что это должно вести себя как SQL Server.
Андрей Ринея
2
«Если это правда, они не будут сортироваться последними, так как значение может быть больше, чем все другие значения». Значение может быть меньше, чем все другие значения. Для меня интуитивно понятно, что значение фальси, такое как ноль, должно быть в нижней части. И практично, так как на практике вы часто хотите использовать descпорядок, чтобы показать самые большие или самые последние вещи, и в этом случае я был бы рад, чтобы нулевые вещи были последними.
mahemoff
База данных делает то, что вы говорите, чтобы сделать. Если вы знаете, что ваши данные содержат пустые значения, и у вас есть какая-то бизнес-причина для сортировки данных определенным образом, вам нужно указать это либо в запросе, либо в коде / представлении, которое обрабатывает / отображает данные. Никогда не оставляйте сортировку до поведения базы данных по умолчанию.
ничего лишнего

Ответы:

19

BOL : значение NULL указывает, что значение неизвестно. Значение NULL отличается от пустого или нулевого значения. Нет двух нулевых значений равных. Сравнения между двумя нулевыми значениями, или между NULL и любым другим значением, возвращают неизвестное, потому что значение каждого NULL неизвестно.

NULL означает неизвестный. Никакая другая интерпретация не действительна.

Если это правда, не будут ли они сортировать в последнюю очередь, так как значение может быть больше, чем все другие значения?

Там не может быть . Там нет потенциальной ценности. Неизвестный неизвестный неизвестный.

Что касается того, почему оно появляется первым, а не последним, то это не учитывается опубликованными стандартами SQL и, к сожалению, остается на усмотрение поставщика СУБД:

Википедия : Стандарт SQL явно не определяет порядок сортировки по умолчанию для пустых значений. Вместо этого в соответствующих системах значения Null могут быть отсортированы до или после всех значений данных с помощью предложений NULLS FIRST или NULLS LAST из списка ORDER BY, соответственно. Однако не все поставщики СУБД реализуют эту функцию. Поставщики, которые не реализуют эту функцию, могут указать различные способы сортировки пустых значений в СУБД.

Марк Стори-Смит
источник
Итак, это решение суда. Это имеет большой смысл. Благодарность!
Ричард
6

Вы правы, что NULLможет означать «Неопределенный» или «Uknownn» или «Пока неизвестно» или «Не применяется». Но нет никаких оснований ставить Нули первым или последним. Если мы не знаем фактические значения, то они могут быть маленькими или большими.

Я думаю, что стандарт для определения желаемого поведения Nulls во время сортировки:

ORDER BY 
    test NULLS LAST                      --- or NULLS FIRST for the opposite

К сожалению, SQL-сервер еще не принял этот синтаксис. Если я не ошибаюсь, у PostgreSQL и Oracle это есть.

Одно из решений:

ORDER BY 
     CASE WHEN test IS NOT NULL 
            THEN 0 
          ELSE 1 
     END 
   , test

Другое решение, которое нуждается в корректировке в зависимости от типа данных - но не будет хорошо сформовано, так как не может использовать индекс для (test):

ORDER BY 
    COALESCE(test, 2147483647)               --- if it's a 4-byte signed integer
ypercubeᵀᴹ
источник
Таким образом, сервер SQL ORDER BY COALESCE (test, 2147483647) не может использовать индекс.
Ардалан Шахголи
3

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

Чтобы получить поведение, которое вы хотите - Насколько я знаю, нет никакой возможности сортировки, чтобы поставить нулевые значения последними, поэтому вы должны связать их с помощью вычисляемого столбца, чтобы заставить их последними. Однако в SQL Server вы не можете упорядочить по вычисляемому столбцу ( CASE WHEN ...), когда ваши данные содержат оператор set ( UNION ALL). Так:

CREATE TABLE #sorttest(test int)
INSERT INTO #sorttest values(1)
INSERT INTO #sorttest values(5)
INSERT INTO #sorttest values(4)
INSERT INTO #sorttest values(NULL)
INSERT INTO #sorttest values(3)
INSERT INTO #sorttest values(2)
SELECT test
FROM #sorttest
ORDER BY CASE WHEN test IS NULL THEN 1 ELSE 0 END, test

DROP TABLE #sorttest

Будет работать для сортировки нулей в прошлом. Если вам нужно использовать UNION(или EXCEPTили INTERSECTS) для создания набора данных, поместите данные во временную таблицу, как указано выше.

Саймон Ригартс
источник
... или использовать выход UNIONed в качестве производной таблицы.
Андрей М
0

Если вы имеете дело с номерами, вы также можете использовать

ORDER BY -test DESC

NULLявляются минимально возможными значениями, поэтому DESCставит их в конце. Между тем ненулевые значения имеют инвертированный знак, так что на DESCсамом деле это ASCреальные значения. Это должно быть быстрее, CASEи я полагаю, что оптимизатор запросов может также использовать индексы для testстолбцов.

Лука
источник
3
Нет, он не сможет использовать индекс для сортировки. Если у вас нет индекса для вычисляемого выражения (- test).
ypercubeᵀᴹ
1
Умный, хотя и ограниченный только числовыми данными (в любом случае подходит для примера OP). Я не уверен, что это действительно будет быстрее, чем использование CASE, но я уверен, что он не будет использовать индекс (если только это не то, что говорит @ ypercube - - но тогда выражение CASE может быть проиндексировано точно таким же образом).
Андрей М