Сортировать символы в varchar2 по алфавиту - PullRequest
3 голосов
/ 14 мая 2010

Я ищу функцию, которая сортировала бы символы в varchar2 по алфавиту.

Есть ли что-то встроенное в оракул, которое я могу использовать, или мне нужно создать кастом в PL / SQL?

Ответы [ 5 ]

1 голос
/ 09 февраля 2016

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

select listagg(letter) 
    within group (order by UPPER(letter), ASCII(letter) DESC) 
from
(
select regexp_substr('gfedcbaGFEDCBA', '.', level) as letter from dual
connect by regexp_substr('gfedcbaGFEDCBA', '.', level) is not null
);

Подзапрос разбивает строку на записи (по одному символу), используя regexp_substr , и внешний запрос объединяет записи в одну строку, используя listagg , после их сортировки.

Здесь вы должны быть осторожны, поскольку сортировка по алфавиту зависит от конфигурации вашей базы данных, как указывал Cine.

В приведенном выше примере буквы сортируются по возрастанию «по алфавиту» и по убыванию по коду ascii, что в моем случае приводит к «aAbBcCdDeEfFgG». Результат в вашем случае может быть другим.

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

select listagg(letter) 
    within group (order by nlssort(letter, 'nls_sort=german') 
from
(
select regexp_substr('gfedcbaGFEDCBA', '.', level) as letter from dual
connect by regexp_substr('gfedcbaGFEDCBA', '.', level) is not null
);

Приведенный выше запрос также даст вам «aAbBcCdDeEfFgG», но если вы измените «немецкий» на «испанский», вы получите вместо «AaBbCcDdEeFfGg».

1 голос
/ 18 мая 2010

Итак, в конце концов я пошел по маршруту PL / SQL, потому что после некоторого времени поиска я понял, что нет встроенной функции, которую я мог бы использовать.

Вот то, что я придумал. Он основан на будущем ассоциативного массива, в котором Oracle хранит ключи в отсортированном порядке.

create or replace function sort_chars(p_string in varchar2) return varchar deterministic
as
     rv varchar2(4000);
     ch  varchar2(1);
     type vcArray is table of varchar(4000) index by varchar2(1);
     sorted vcArray;

     key varchar2(1);

begin
     for i in 1 .. length(p_string)
     loop
        ch := substr(p_string, i, 1);

        if (sorted.exists(ch))
        then 
            sorted(ch) := sorted(ch) || ch;
        else
            sorted(ch) := ch;
        end if;
     end loop;


    rv := '';
    key  := sorted.FIRST;
    WHILE key IS NOT NULL LOOP
        rv := rv || sorted(key);
        key := sorted.NEXT(key);
    END LOOP;

     return rv;
end;

Простой тест производительности:

set timing on;

create table test_sort_fn as 
select t1.object_name || rownum as test from user_objects t1, user_objects t2;

select count(distinct test) from  test_sort_fn;

select count (*)  from (select sort_chars(test)  from test_sort_fn);


Table created.
Elapsed: 00:00:01.32

COUNT(DISTINCTTEST)
-------------------
             384400
1 row selected.
Elapsed: 00:00:00.57

  COUNT(*)
----------
    384400
1 row selected.
Elapsed: 00:00:00.06
1 голос
/ 17 мая 2010

Вы должны помнить, что нет единого мнения о том, что означает «в алфавитном порядке». Все зависит от того, в какой стране он находится, кто смотрит на ваши данные и в каком контексте.

Например, в DK существует большое количество различных сортировок a, aa, b, c, æ, ø, å

  • по алфавиту: a, aa, b, c, æ, ø, å
  • для некоторого словаря: a, aa, å, b, c, æ, ø
  • для других словарей: a, b, c, æ, ø, aa, å
  • по стандарту Microsoft: a, b, c, æ, ø, aa, å

проверить http://www.siao2.com/2006/04/27/584439.aspx для получения дополнительной информации. Который также, оказывается, большой блог для проблем как они.

1 голос
/ 14 мая 2010

Из ответа на http://forums.oracle.com/forums/thread.jspa?messageID=1791550 это может сработать, но нет 10g для проверки на ...

SELECT MIN(permutations)
FROM (SELECT REPLACE (SYS_CONNECT_BY_PATH (n, ','), ',') permutations
    FROM (SELECT LEVEL l, SUBSTR ('&col', LEVEL, 1) n
        FROM DUAL
        CONNECT BY LEVEL <= LENGTH ('&col')) yourtable
    CONNECT BY NOCYCLE l != PRIOR l)
WHERE LENGTH (permutations) = LENGTH ('&col')

В примере col определено в SQL * Plus, но если вы сделаете это функцией, вы можете передать ее или переработать, чтобы получить непосредственно столбец таблицы.

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

0 голосов
/ 17 мая 2010

Если вы не возражаете против того, чтобы символы возвращались по 1 в строке:

select substr(str, r, 1) X from (
select 'CAB' str,
       rownum r
from dual connect by level <= 4000
) where r <= length(str) order by X;

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