2009-02-16 8 views
3

Наше приложение имеет поле CustomerNumber. У нас есть сотни разных людей, использующих систему (каждый из них имеет свой собственный логин и собственный список CustomerNumber). У отдельного пользователя может быть не более 100 000 клиентов. Многие из них имеют менее 100.Как сортировать и отображать смешанные списки букв и цифр, как ожидают пользователи?

Некоторые люди только помещают фактические цифры в поля своих номеров клиентов, в то время как другие используют смесь вещей. Система позволяет использовать 20 символов, которые могут быть A-Z, 0-9 или тире, и сохраняет их в VARCHAR2 (20). Перед тем, как быть сохраненным, все строчные буквы делаются в верхнем регистре.

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

SELECT CustomerNumber,CustomerName 
FROM Customer 
WHERE User = ? 
ORDER BY CustomerNumber; 

Это наивное решение, как и люди, которые только когда-либо использовать цифры не хотят видеть простой буквенный вид (где «10» идет перед «9»).

Я не хочу спрашивать у пользователя каких-либо лишних вопросов об их данных.

Я использую Oracle, но я думаю, было бы интересно увидеть некоторые решения для других баз данных. Укажите, в какой базе данных работает ваш ответ.

Как вы думаете, лучший способ реализовать это?

ответ

2

В Oracle 10g:

SELECT cust_name 
FROM t_customer c 
ORDER BY 
    REGEXP_REPLACE(cust_name, '[0-9]', ''), TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+')) 

Это будет сортировать первым вхождение числа, а не о его позиции, я. е .:

  1. customer1 < customer2 < customer10
    • cust1omer ? customer1
    • cust8omer1 ? cust8omer2

, где ? означает, что порядок не определен.

Этого достаточно для большинства случаев.

Заставить порядок сортировки по делу 2, вы можете добавить REGEXP_INSTR(cust_name, '[0-9]', n) в ORDER BY список n раз, заставляя заказ на первое появление n -го (2nd, 3rd и т.д.) группы цифр.

Заставить порядок сортировки по делу 3, вы можете добавить TO_NUMBER(REGEXP_SUBSTR(cust_name, '[0-9]+', n)) в ORDER BY список n раз, принуждая порядок из n -го. группа цифр.

На практике, я написал достаточно.

Вы можете создать индекс, основанный на функциях, для этих выражений, но вам нужно будет закрепить его с подсказкой, и односторонний SORT ORDER BY будет выполнен в любом случае, так как CBO не доверяет функциональным индексам чтобы разрешить на них ORDER BY.

4

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

Другая возможность - выполнить сортировку после выбора по возвращенным результатам.

Jeff Atwood has put together a blog Публикация о том, как некоторые люди подсчитывают дружеские заказы на сортировку людей.

+0

См. Также http://stackoverflow.com/questions/34518/natural-sorting-algorithm и другие вещи, помеченные как «естественные» для обсуждения и реализации ... – dmckee

1

Вы могли бы иметь числовой столбец [CustomerNumberInt], который используется только, когда CustomerNumber чисто числовой (NULL в противном случае [1]), а затем

ORDER BY CustomerNumberInt, CustomerNumber 

[1] в зависимости от того, как SQL версия обрабатывает NULLs в ORDER BY вы можете настроить его к нулю (или бесконечности!)

1

у меня аналогичная ужасной ситуации и разработали соответственно ужасную функцию, чтобы справиться с ней (SQLServer)

в моей ситуации у меня есть таблица «единиц» (это система отслеживания работы для студентов, поэтому подразделение в этом контексте представляет собой курс, который они выполняют). У единиц есть код, который по большей части является чисто числовым, но по разным причинам он был сделан varchar, и они решили префикс несколько до 5 символов. Таким образом, они ожидают, что 53,123,237,356 сортировать нормально, но и T53, T123, T237, T356

UnitCode является NVARCHAR (30)

Вот тело функции:

declare @sortkey nvarchar(30) 

select @sortkey = 
    case 
     when @unitcode like '[^0-9][0-9]%' then left(@unitcode,1) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-1) 
     when @unitcode like '[^0-9][^0-9][0-9]%' then left(@unitcode,2) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-2) 
     when @unitcode like '[^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,3) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-3) 
     when @unitcode like '[^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,4) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-4) 
     when @unitcode like '[^0-9][^0-9][^0-9][^0-9][^0-9][0-9]%' then left(@unitcode,5) + left('000000000000000000000000000000',30-(len(@unitcode))) + right(@unitcode,len(@unitcode)-5) 
     when @unitcode like '%[^0-9]%' then @unitcode 
     else left('000000000000000000000000000000',30-len(@unitcode)) + @unitcode 
    end 

return @sortkey 

Я хотел стрелять я сам в лицо после написания этого, однако он работает и, кажется, не убивает сервер, когда он работает.

0

Я использовал это в SQL SERVER и отлично работал: здесь решение должно заполнить числовые значения символом спереди, чтобы все имели одинаковую длину строки.

Ниже приведен пример использования этого подхода:

select MyCol 
from MyTable 
order by 
    case IsNumeric(MyCol) 
     when 1 then Replicate('0', 100 - Len(MyCol)) + MyCol 
     else MyCol 
    end 

100 должна быть заменена на фактическую длину этого столбца.

 Смежные вопросы

  • Нет связанных вопросов^_^