Чи є порівняння для сортування наступних рядків у такому порядку 1,2,3,6,10,10A, 10B, 11?


12

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

Однак мені було цікаво, чи існує порівняння, де це було б непотрібно.


Ось нове посилання на цю пропозицію тепер, коли Microsoft перейшла з підключення до UserVoice, але не пересилала URI: Підтримка "природного сортування" / DIGITSASNUMBERS як варіант
зібрання

2
Microsoft заявили, що вони будуть реалізовувати це як вбудовану функцію в SQL Server, якщо вони отримають достатньо голосів. Тому перейдіть сюди і натисніть на кнопку голосування .
Пітер Ейлетт

Відповіді:


8

Ні. Збірка - це алфавітне сортування, залежно від кодової сторінки, акценту, регістру, ширини, каналу. Символи чисел (0-9) не мають жодної властивості.

Так 9завжди після того, як 10Bв будь-якому роді.

Ви повинні розділити його, як ви зазначили, або сортувати так:

ORDER BY
    RIGHT('                              ' + MyColumn, 30)

Довжина праворуч визначає кількість пробілів.

Ви, звичайно, можете:

  • мають 2 стовпчики, щоб зробити це непотрібним (і набагато швидше), і є обчислений стовпець для їх поєднання
  • наполягати на провідних нулях
  • право виправдати в графі (збережена версія мого ВПРАВО вище)

Останні 2 пропозиції схожі на моє ВПРАВО вище і трохи відрізняються. Швидше сортувати (не потрібно обробляти colukmn), але більше місця для зберігання не потрібно


я не бачу, як це працює. Перерва на 2, 2а, 3 і т.
Д

@Mladen Prajdic: ти прав, на жаль. Забув про
останні

Щодо " Так 9завжди є 10Bв будь-якому роді ". Це лише такий шлях у SQL Server, оскільки базовий варіант сортування для обробки "DigitsAsNumbers" не був виставлений як параметр Collation. І все-таки ;-). Це стало доступним для програм на базі Windows, починаючи з Windows 7, особливо в File Explorer. І він може одного дня опинитися на SQL Server, якщо достатньо людей підтримає цю ідею. Я спробував прокатати кулю, подавши наступну пропозицію підключення: Підтримка "природного сортування" / DIGITSASNUMBERS як параметр Collation .
Соломон Руцький

8

Я встановив би обчислюваний стовпчик, а потім сортувати виходячи з цього. Щось на зразок

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

Потім використовуйте цей стовпець для сортування за тим, як ви можете індексувати стовпець.


Це дійсно корисно знати про подібні проблеми. Однак у цьому випадку я не можу змінити схему.
Justin Dearing

Чи можете ви додати до схеми? Якщо заборонити обчислений стовпець, ви завжди зможете створити подання - хоча це насправді не можна оптимізувати, як може бути обчислений стовпець.
Аарон Бертран

Якщо ви маєте індексований вигляд і маєте Enterprise Edition, ваш запит автоматично використовуватиме індексований вигляд, якщо він зможе з’ясувати, що ви намагаєтеся зробити. Якщо стандартне видання, вам потрібно буде використовувати кнопку AND (NOEXPAND), щоб запустити індексований вигляд, який буде використовуватися. У цей момент вам потрібно буде мати у своєму розпорядженні заяву про справу, але я думаю, це має спрацювати.
mrdenny

Вам не потрібно створювати обчислену колонку. Ви можете використовувати цей вираз безпосередньо в пункті ЗАМОВЛЕННЯ ПО
a_horse_with_no_name

Якщо ви хочете гарантувати сканування індексу або таблиці, ви впевнені, що можете. Якщо ви хочете мати можливість індексувати значення, тоді потрібен обчислений стовпець або індексований вигляд.
mrdenny

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. У МОВІ МАРКУПОВИХ МАРКУПОВИХ МАРКУПІВ (LDML) ЧАСТИНА 5: Стандарт / звіт про колекцію є діаграма Налаштування зібрання, яка описує різні варіанти налаштування поведінки сортування. Одним із варіантів є -kn-trueабо [numericOrdering on]:

Якщо встановлено , щоб на , будь-яка послідовність десяткових цифр (General_Category = Nd в [ UAX44 ]) сортується на початковому рівні з його числовим значенням. Наприклад, "A-21" <"A-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 Explorer ви побачите список, відсортований за допомогою параметра "числовий" :-).


FYI, Postgres 10 отримує підтримку для порівнянь ICU. Дивіться цю публікацію в блозі Пітера Ейзентраута.
Василь Бурк

@BasilBourque Дякую, що згадуєте про PG10. У цьому записі в кінці стверджується, що "ICU пропонує багато функціональних можливостей у цій галузі, які ми ще не відкриваємо через PostgreSQL. Існують варіанти сортування, залежно від регістру, сортування, нечутливого до акцентів, та повністю налаштування зіставлення. Подивіться. для тих, хто буде в майбутніх випусках PostgreSQL. " Тож у своїй першій / поточній реалізації вона не змінює жодної інформації в моїй відповіді. Якщо майбутня пропозиція дозволяє числове сортування, я зазначу це у своїй відповіді, але як виноску, оскільки це питання стосується SQL Server.
Соломон Руцький
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.