Почему SQL сортирует нашу строку, по-видимому, нелогично? - PullRequest
1 голос
/ 07 мая 2019

Работая с SQL сегодня, мы обнаружили, что SQL не сортирует наши строки в столбце, как мы ожидаем.

Это наш список наборов данных: (URL-адреса сокращены, чтобы предотвратить злоупотребления)

http://10.10.14
http://192.168.
https://m.hanno
https://online.
https://online-
https://owi-000
https://owi2.su
https://owi2-00
https://owi2-71
https://owi-700
https://owi-702
https://owi-703
https://owi-704
https://owi-707
https://owi-708
https://owi-710
https://owi-711
https://owi-712
https://owi-713
https://owi-714
https://owi-715
https://owi-716
https://owi-717
https://owigo.n
https://owigosm
https://owigow.

URL-адреса owi2 находятся непосредственно за owi-000.Однако это должно быть позади owi-717 или перед owi-000, но определенно не между.

...
https://owi-000
https://owi2.su
https://owi2-00
https://owi2-71
https://owi-700
...

Вот как мы ожидаем результатов.Минус предшествует 2 в ASCII и многих других кодировках символов.Поэтому все URL с owi2 должны следовать после owi -.

...
https://owi-717
https://owi2.su
https://owi2-00
https://owi2-71
https://owigo.n
...

Мы скопировали все URL в MS Excel и, к нашему удивлению, получили те же результаты.Поэтому мы проверили строки, чтобы убедиться, что не непечатаемый символ не вызывает проблему.И на самом деле, мы не нашли непечатных символов с помощью Notepad ++.

Наш вопрос: почему SQL сортирует наши URL-адреса так, как это делает?

Ответы [ 2 ]

4 голосов
/ 07 мая 2019

TLDR : Убедитесь, что у вас есть VARCHAR, а не NVARCHAR. Строки NVARCHAR будут игнорировать дефис. Если вы не можете вносить изменения в тип данных, попробуйте использовать параметры сортировки Latin1_General_CI_AS

Как уже упоминалось ранее, например здесь , SO здесь и здесь , существует разница в том, как дефис используется при сортировке буквенно-цифровых символов.

Типичные параметры сортировки игнорируют дефис при сортировке. Цитата из статьи MSDN:

Правила сортировки SQL для сортировки данных не в Юникоде несовместимы с любой программой сортировки, предоставляемой Microsoft Windows операционная система; однако сортировка данных в Юникоде совместима с определенной версией правил сортировки Windows. Поскольку правила сравнения для не-Unicode и Unicode данных отличаются, когда вы используете сортировку SQL, вы можете увидеть разные результаты для сравнение одних и тех же символов в зависимости от базовых данных тип. Например, если вы используете сортировку SQL «SQL_Latin1_General_CP1_CI_AS», строка не-Unicode 'a-c' меньше чем строка 'ab', потому что дефис ("-") сортируется как отдельный символ, который предшествует "б". Однако, если вы конвертируете эти строки Unicode и вы делаете то же самое сравнение, строка Unicode N'a-c 'считается больше, чем N'ab', потому что Unicode Правила сортировки используют «сортировку слов», которая игнорирует дефис.

1 голос
/ 07 мая 2019

В качестве альтернативы, если вам нужно использовать nvarchar, тогда вы можете использовать другое сопоставление.Однако вы можете изменить параметры сортировки столбца в таблице, что может привести к нежелательным последствиям, так как в этом случае любое сравнение, которое вы делаете, должно быть явно сопоставлено, если они не совпадают;что повлияет на SARGability.Учитывая, что вы хотите это только для заказа, вы можете просто использовать ключевое слово COLLATE.Например:

SELECT ROW_NUMBER() OVER (ORDER BY URL COLLATE SQL_Latin1_General_CP1_CI_AS),
       ROW_NUMBER() OVER (ORDER BY CONVERT(nvarchar(20),URL) COLLATE SQL_Latin1_General_CP1_CI_AS),
       ROW_NUMBER() OVER (ORDER BY URL COLLATE Latin1_General_CI_AS),
       ROW_NUMBER() OVER (ORDER BY CONVERT(nvarchar(20),URL) COLLATE Latin1_General_CI_AS),
       ROW_NUMBER() OVER (ORDER BY URL COLLATE Latin1_General_100_BIN2),
       ROW_NUMBER() OVER (ORDER BY CONVERT(nvarchar(20),URL) COLLATE Latin1_General_100_BIN2),
       URL
FROM (VALUES('http://10.10.14'),
            ('http://192.168.'),
            ('https://m.hanno'),
            ('https://online.'),
            ('https://online-'),
            ('https://owi-000'),
            ('https://owi2.su'),
            ('https://owi2-00'),
            ('https://owi2-71'),
            ('https://owi-700'),
            ('https://owi-702'),
            ('https://owi-703'),
            ('https://owi-704'),
            ('https://owi-707'),
            ('https://owi-708'),
            ('https://owi-710'),
            ('https://owi-711'),
            ('https://owi-712'),
            ('https://owi-713'),
            ('https://owi-714'),
            ('https://owi-715'),
            ('https://owi-716'),
            ('https://owi-717'),
            ('https://owigo.n'),
            ('https://owigosm'),
            ('https://owigow.'))V(URL)
ORDER BY URL COLLATE Latin1_General_CI_AS;

db <> fiddle

Здесь вы можете видеть, что порядок сортировки SQL_Latin1_General_CP1_CI_AS имеет другой порядок для varchar - nvarchar,С другой стороны, Latin1_General_CI_AS согласован для обоих (копирование порядка, который nvarchar с сопоставлением SQL_Latin1_General_CP1_CI_AS имел).Latin1_General_100_BIN2 также согласуется, но следует тому же порядку для varchar.

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