Существует ли сортировка для сортировки следующих строк в следующем порядке 1,2,3,6,10,10A, 10B, 11?

12

У меня есть база данных со столбцом VARCHAR, который содержит целые числа различной длины. Я хочу отсортировать их так, чтобы 10 приходилось после 9, а не 1, а 70A приходилось после 70. Я смог сделать это с помощью операторов PATINDEX () , CTE и CASE в предложении WHERE.

Тем не менее, мне было интересно, если бы было сопоставление, где это было бы ненужным.

Джастин Даринг
источник
Вот новая ссылка для этого предложения теперь, когда Microsoft мигрировала из Connect в UserVoice, но не пересылала URI: поддержка «естественной сортировки» / DIGITSASNUMBERS в качестве параметра сортировки
Соломон Руцкий,
2
Microsoft заявила, что будет реализовывать это как встроенную функцию в SQL Server, если получит достаточно голосов. Так что иди сюда и нажмите на кнопку голосования .
Питер Айлетт

Ответы:

8

Нет. Сортировка - это сортировка по алфавиту, в зависимости от кодовой страницы, акцента, регистра, ширины, кана. Числа символов (0-9) не имеют ни одного из этих свойств.

Так 9всегда после того, как 10Bв любом роде.

Вы должны разделить это, как вы заметили, или отсортировать так:

ORDER BY
    RIGHT('                              ' + MyColumn, 30)

Длина справа определяет, сколько пробелов у вас есть.

Вы могли бы, конечно:

  • иметь 2 столбца, чтобы сделать это ненужным (и гораздо быстрее), и иметь вычисляемый столбец, чтобы объединить их
  • настаивать на ведущих нулях
  • Правильно обоснуйте в char (сохраненная версия моего RIGHT выше)

Последние 2 предложения похожи на мои права выше и немного отличаются. Быстрая сортировка (не требуется обработка colukmn), но требуется больше места для хранения

ГБН
источник
Я не понимаю, как это работает. Это перерывы на 2, 2а, 3 и т. Д ...
Младен Прайдич
@Mladen Prajdic: ты прав, упс. Забыл про
висячие
Относительно " Так 9всегда 10Bв любом виде. ": Так обстоят дела только в SQL Server, потому что базовый параметр сортировки для обработки "DigitsAsNumbers" не был представлен как параметр сортировки. Еще ;-). Это стало доступно для приложений на базе Windows, начиная с Windows 7, особенно в проводнике. И однажды он может быть открыт для SQL Server, если достаточно людей поддержит эту идею. Я попытался добиться успеха, представив следующее предложение Connect: Поддержка "естественной сортировки" / DIGITSASNUMBERS в качестве параметра сортировки .
Соломон Руцкий
8

Я бы установил вычисляемый столбец, а затем отсортировал на основе этого. Что-то вроде

CAST( 
     CASE WHEN IS_NUMERIC(left(OtherColumn, 2) = 1) then 
         left(OtherColumn,2) 
     else 
         left(otherColumn, 1)  
AS INT)

Затем используйте этот столбец для сортировки, поскольку теперь вы можете индексировать столбец.

mrdenny
источник
Это действительно полезно знать о подобных проблемах. Однако в этом случае я не могу изменить схему.
Джастин Даринг
Вы можете добавить в схему? За исключением вычисляемого столбца, вы всегда можете создать представление - хотя это не будет действительно оптимизируемым, как вычисляемый столбец.
Аарон Бертран
Если вы выполняете индексированное представление и имеете редакцию Enterprise, ваш запрос будет автоматически использовать индексированное представление, если оно может выяснить, что вы пытаетесь сделать. В стандартной версии вам нужно использовать WITH (NOEXPAND), чтобы активировать индексированное представление. В этот момент вы должны иметь в своем заявлении описание дела, но оно должно работать, я думаю.
Мрденный
Вам не нужно создавать вычисляемый столбец. Вы можете использовать это выражение непосредственно в предложении ORDER BY
a_horse_with_no_name
Если вы хотите гарантировать индекс или сканирование таблицы, вы можете. Если вы хотите иметь возможность индексировать значение, тогда необходим вычисляемый столбец или индексированное представление.
Мрденный
5

Если вам нужен болезненный способ доказать, что говорит @gbn (по сути, вы не можете сказать, что сопоставление упорядочивает подстроки по-разному), вы можете создать быструю таблицу #temp, которая имеет коэффициент для ожидаемого порядка, и посмотреть, упорядочение по любому сопоставлению возвращает тот же порядок:

CREATE TABLE #foo(id INT, n NVARCHAR(10));

CREATE TABLE #bar(collation SYSNAME);

SET NOCOUNT ON;

INSERT #foo SELECT 1,'1'
UNION SELECT 2,'2'
UNION SELECT 3,'3'
UNION SELECT 4,'6'
UNION SELECT 5,'10'
UNION SELECT 6,'10A'
UNION SELECT 7,'10B'
UNION SELECT 8,'11';

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'
    WITH x AS 
    (
        SELECT n, rn = ROW_NUMBER() OVER 
        (ORDER BY n COLLATE ' + name + ') FROM #foo
    ) 
    INSERT #bar 
    SELECT TOP (1) ''' + name + ''' FROM x
    WHERE NOT EXISTS
    (
        SELECT COUNT(*) FROM #foo AS f
        WHERE f.id = x.rn
        AND f.n <> x.n
    );' FROM sys.fn_helpcollations();

EXEC sp_executesql @sql;

SELECT collation FROM #bar;

GO
DROP TABLE #foo, #bar;

Это выполняется для меня примерно за 10 секунд и дает 0 строк - это означает, что никакие параметры сортировки, доступные для SQL Server (по крайней мере 2008 R2, еще не пробовали Denali), будут отсортированы так, как вы ожидаете. Вам нужен другой способ определения сортировки.

Аарон Бертран
источник
2

Хотите разумный, эффективный способ сортировки чисел в строках как фактические числа? Рассмотрите возможность голосования за мое предложение Microsoft Connect: поддержка «естественной сортировки» / DIGITSASNUMBERS в качестве параметра сортировки


Хотя этот вопрос относится к SQL Server, а этот ответ - нет, я решил, что мне все же следует публиковать эту информацию, просто чтобы повысить ее осведомленность и не противостоять каким-либо другим ответам.

При этом за пределами SQL Server в некоторых средах возможна сортировка такого типа. Это то, что по крайней мере указано в документации Unicode. В UNICODE LOCALE DATA MARKUP LANGUAGE (LDML) ЧАСТЬ 5: стандарт / отчет COLLATION имеется диаграмма для параметров сортировки, которая описывает различные варианты настройки поведения сортировки. Одним из вариантов является -kn-trueили [numericOrdering on]:

Если установлено значение on , любая последовательность десятичных цифр (General_Category = Nd в [ UAX44 ]) сортируется на первичном уровне с ее числовым значением. Например, «А-21» <«А-123». Все вычисленные первичные веса находятся в начале группы переупорядочения цифр . Таким образом, с таблицей UCA, "a $" <"a0" <"a2" <"a12" <"a⓪" <"aa".

Однако этот документ является «техническим стандартом», а не частью базовой спецификации Unicode. Примечание в верхней части документа гласит:

Технический стандарт Unicode (UTS) является независимой спецификацией. Соответствие стандарту Unicode не подразумевает соответствия любому UTS.

Следовательно, это конкретное поведение недоступно в SQL Server или даже в .NET (по крайней мере, изначально), хотя оба они соответствуют базовой спецификации Unicode.

Проект ICU (International Components for Unicode) представляет собой набор библиотек C / C ++ и Java, которые реализуют эту функциональность, и даже есть онлайн-демонстрация. А в разделе «связанные проекты» есть ссылка на проект .NET, который, по-видимому, является оберткой COM-объекта для библиотеки ICU, что позволило бы раскрыть эту функциональность для управляемого кода. Но не ясно, если этот .NET проект все еще активен.

Но чтобы увидеть это поведение в действии, перейдите к демонстрации сортировки ICU .

Вставьте следующее в область ввода текста с левой стороны:

1
2
10B
6
11
10A
3
10

Установите все параметры на «по умолчанию». Отметьте опцию «Ввод номеров строк» ​​справа от sortкнопки и убедитесь, что опция «Прочность разрядов» не отмечена.

Нажмите на sortкнопку, и вы должны получить следующее:

[1] 1
[8] 10
[6] 10A
[3] 10B
[5] 11
[2] 2
[7] 3
[4] 6

Это то, что следует ожидать при выполнении типичной сортировки строк, и то, что вы видите в SQL Server.

Теперь в ряду переключателей чуть выше sortкнопки второй ряд помечен как «числовой». Выберите переключатель «вкл».

Нажмите sortкнопку еще раз, и вы должны получить следующее:

[1] 1
[2] 2
[7] 3
[4] 6
[8] 10
[6] 10A
[3] 10B
[5] 11

Опрос, если это работает, когда числовая часть находится в середине строки? Хорошо, вставьте следующее в область ввода текста с левой стороны (заменив предыдущий список):

Script - 1.sql
Script - 2.sql
Script - 10B.sql
Script - 6.sql
Script - 11.sql
Script - 10A.sql
Script - 3.sql
Script - 10.sql

Убедитесь, что для числовой настройки все еще установлено значение «вкл». Нажмите sortкнопку еще раз, и вы должны получить следующее:

[1] Script - 1.sql
[2] Script - 2.sql
[7] Script - 3.sql
[4] Script - 6.sql
[8] Script - 10.sql
[6] Script - 10A.sql
[3] Script - 10B.sql
[5] Script - 11.sql

Хотите увидеть это в другом месте? Создайте на жестком диске папку, например, C: \ temp \ sorting \ , и создайте пустые файлы с теми же именами «Script -...». Сделайте DIRв окне команды, и вы увидите стандартную сортировку. Но при просмотре списка файлов в проводнике Windows вы увидите список, отсортированный с использованием параметра «числовой» :-).

Соломон Руцкий
источник
К вашему сведению, Postgres 10 получает поддержку для сортировки ICU. Смотрите это сообщение в блоге Питера Айзентраута.
Василий Бурк
@BasilBourque Спасибо, что упомянули об PG10. В конце этого блога говорится, что «ICU предлагает множество функциональных возможностей в этой области, которые мы пока не раскрываем через PostgreSQL. Существуют варианты сортировки без учета регистра, сортировки без учета акцента и полной настройки параметров сортировки. для тех, кто в будущих выпусках PostgreSQL. " Таким образом, в своей первой / текущей реализации он не меняет никакой информации в моем ответе. Если в будущем предложении будет разрешена числовая сортировка, я упомяну об этом в своем ответе, но в качестве сноски, поскольку этот вопрос относится к SQL Server.
Соломон Руцкий,