Естественная (человеческая буквенно-цифровая) сортировка в Microsoft SQL 2005 - PullRequest
43 голосов
/ 29 августа 2008

У нас есть большая база данных, в которой есть пагинация на стороне БД. Это быстро, возвращая страницу из 50 строк из миллионов записей за небольшую долю секунды.

Пользователи могут определять свою собственную сортировку, в основном выбирая, по какому столбцу сортировать. Столбцы являются динамическими - некоторые имеют числовые значения, некоторые даты и некоторый текст.

В то время как большинство сортирует, как ожидается, текст сортируется тупо. Ну, я говорю глупо, это имеет смысл для компьютеров, но расстраивает пользователей.

Например, сортировка по идентификатору строковой записи дает что-то вроде:

rec1
rec10
rec14
rec2
rec20
rec3
rec4

... и т. Д.

Я хочу, чтобы это учитывало число, поэтому:

rec1
rec2
rec3
rec4
rec10
rec14
rec20

Я не могу контролировать ввод (иначе я бы просто отформатировал первые тысячи), и я не могу полагаться на один формат - некоторые вещи такие, как "{alpha code} - {dept code} - {rec id }».

Я знаю несколько способов сделать это в C #, но не могу вытащить все записи, чтобы отсортировать их, так как это может привести к замедлению.

Кто-нибудь знает способ быстрого применения естественной сортировки на сервере Sql?


Мы используем:

ROW_NUMBER() over (order by {field name} asc)

А потом мы этим разбираемся.

Мы можем добавлять триггеры, хотя мы не будем. Все их входные данные параметризованы и тому подобное, но я не могу изменить формат - если они введут «rec2» и «rec10», они ожидают, что они будут возвращены просто так и в естественном порядке.


У нас есть действительный пользовательский ввод в разных форматах для разных клиентов.

Можно пойти rec1, rec2, rec3, ... rec100, rec101

В то время как другой может пойти: grp1rec1, grp1rec2, ... grp20rec300, grp20rec301

Когда я говорю, что мы не можем контролировать ввод, я имею в виду, что мы не можем заставить пользователей изменять эти стандарты - они имеют значение, например grp1rec1, и я не могу переформатировать его как grp01rec001, так как это изменило бы что-то используемое для поиска и связи с внешними системами.

Эти форматы сильно различаются, но часто представляют собой смесь букв и цифр.

Сортировать их в C # легко - просто разбейте их на { "grp", 20, "rec", 301 } и затем по очереди сравните значения последовательности.

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

Сервер SQL сортирует по значению, а не по сравнению - в C # я могу разделить значения для сравнения, но в SQL мне нужна логика, которая (очень быстро) получает одно значение, которое последовательно сортирует.

@ moebius - ваш ответ может сработать, но все равно кажется уродливым компромиссом добавить ключ сортировки для всех этих текстовых значений.

Ответы [ 13 ]

0 голосов
/ 15 апреля 2009

Я только что прочитал статью где-то о такой теме. Ключевой момент: вам нужно только целочисленное значение для сортировки данных, в то время как строка 'rec' принадлежит пользовательскому интерфейсу. Вы можете разделить информацию на два поля, скажем, alpha и num, отсортировать по alpha и num (отдельно), а затем показать строку, составленную из alpha + num. Вы можете использовать вычисляемый столбец для составления строки или представления. Надеюсь, это поможет

0 голосов
/ 15 апреля 2009

Вы можете использовать следующий код для решения проблемы:

Select *, 
    substring(Cote,1,len(Cote) - Len(RIGHT(Cote, LEN(Cote) - PATINDEX('%[0-9]%', Cote)+1)))alpha,
    CAST(RIGHT(Cote, LEN(Cote) - PATINDEX('%[0-9]%', Cote)+1) AS INT)intv 
FROM Documents 
   left outer join Sites ON Sites.IDSite = Documents.IDSite 
Order BY alpha, intv

С уважением, rabihkahaleh@hotmail.com

0 голосов
/ 30 августа 2008

Я до сих пор не понимаю (возможно, из-за моего плохого английского).

Вы можете попробовать:

ROW_NUMBER() OVER (ORDER BY dbo.human_sort(field_name) ASC)

Но это не сработает для миллионов записей.

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

Более того:

  • встроенные функции T-SQL действительно медленно и Microsoft предлагает использовать Вместо этого .NET функционирует.
  • человеческая ценность является постоянной величиной, поэтому нет смысла вычислять ее каждый раз когда запрос выполняется.
...