Как я могу отсортировать в Oracle столбцы Varchar2 или NVarchar2 в моем собственном порядке. Или доступны какие-либо существующие опции, в которых сначала ставятся буквы, затем цифры, а затем все специальные символы.
Наш первый подход заключался в использовании функции, которая вручную отображает символы в числа.
select id, sorted_column
from some_table
order FN_SPECIAL_SORT_KEY(sorted_column,'asc')
Специальная функция сортировки отображает каждый символ в двузначное число, а возвращаемое значение используется для сортировки. Кажется, это просто очень дорогая конкатенация, и она кажется неправильной.
for i in 1..length(sorted_text)
loop
v_result:=v_result || case substr(sorted_text,i,1)
WHEN ' ' THEN 82 WHEN '!' THEN 81 WHEN '"' THEN 80 WHEN '#' THEN 79 WHEN '$'
..............
WHEN 'u' THEN 15 WHEN 'U' THEN 15 WHEN 'v' THEN 14 WHEN 'V' THEN 14 WHEN 'w' THEN 13 WHEN 'W' THEN 13 WHEN 'x'
....
else 90 end;
end loop;
Мне трудно придумать альтернативный подход. Я хочу знать, какие проблемы существуют с этим подходом. Возможно, у нас нет альтернативы.
Приложение 1:
Добавление примера отсортированных данных. Как правило, все буквенные символы не чувствительны к регистру, затем цифры 0-9, затем специальные символы в любом порядке.
Вот пример отсортированного списка по возрастанию. Имейте в виду, что специальные символы взаимозаменяемы, все они должны быть после букв и цифр. В двоичной сортировке некоторые специальные символы перед буквами (то есть ')
Мой желаемый заказ,
AB1 $
aCC #
ac '
BZ
Двоичный порядок Oracle
AB1 $
BZ
ac '
acc #
Некоторые варианты:
Сохраните отсортированную версию ваших данных в таблице с помощью триггера и используйте ее.
Используйте Oracle Locale Builder для создания пользовательского порядка сортировки. (Предостережение: я никогда не использовал это, поэтому я не знаю, какие ошибки могут существовать там.) Затем вы можете использовать функцию NLSSORT с этим пользовательским порядком сортировки.
источник
Другой подход - добавить индекс на основе функции
FN_SPECIAL_SORT_KEY(sorted_column,'asc')
. Избегает необходимости в дополнительном столбце + триггер, и вам не нужно будет изменять ваши запросы.источник
На основании вашего описания кажется, что TRANSLATE может сделать всю работу за вас. Как предполагает Джеффри Кемп, для этого может быть создан индекс на основе функций.
Настроить:
Демонстрация:
Вывод:
Проверьте порядок всех символов:
источник
Если вы хотите проиндексировать данные, чтобы избежать сортировки в запросе
order by
, вы можете сделать это следующим образом:-- редактировать
Как прокомментировал @Leigh, альтернативный, более точный подход состоит в том, чтобы иметь единственную функцию, объединяющую (модифицированные) регулярные выражения:
regexp_replace(lower(foo), '[^a-z]', '~')||regexp_replace(foo, '[^a-zA-Z0-9]', '~')||foo
включение
||foo
конца в любом случае делает упорядоченность детерминированной (повторяемой), что может быть хорошей вещью, даже если вопрос специально не задает его.источник
regexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9]', '~') || foo
. Проблема в том, что это отличается от вашего первоначального решения. Таким образом, исправленная версия нуждается в исправлении, а не в оригинале. Порядок сортировки можно исправить, изменив второе регулярное выражение, которое дает порядок наregexp_replace(lower(foo), '[^a-z]', '~') || regexp_replace(foo, '[^0-9a-zA-Z]', '~') || foo
.