Как сгенерировать случайную строку из фиксированного набора символов?

Как сгенерировать случайную строку в PL/SQL из фиксированного набора символов?

Например, требуется сгенерировать буквенно-цифровую строку длиной 10, исключающую определенные символы и цифры, такие как I, O, 0 и т.д.

Не смог найти способ вызвать DBMS_RANDOM.STRING() с требуемым набором символов. Параметром можно передать только класс символов:

select DBMS_RANDOM.STRING ('x', 10) rnd
from dual;

RND
----------
PTPYOGY70T

Есть ли встроенный способ сделать это в PL/SQl?


Свободный перевод вопроса Generate Random String from fixed set of characters от участника @user931518


Ответы (2 шт):

Автор решения: 0xdb

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

Вот пример такой функции:

create or replace function RandomString(p_Characters varchar2, 
                                        p_length number) return varchar2 is
    l_res varchar2(256);
begin
    select substr(listagg(substr(p_Characters, level, 1)) within group (
            order by dbms_random.value), 1, p_length)
    into l_res
    from dual connect by level <= length(p_Characters);
    
    return l_res;
end;

И как ею пользоватся:

select randomstring('1234567abcdefg', 10) res
from dual connect by level <= 10
/
RES
----------
d17cg4e35a
b7e1f3cd46
defba7g51c
431gcd5fa7
43bgc57ad2
4fe26ad3c5
32e176ca4b
25df6c34e1
52edg6f4ba
3abf645g21

10 rows selected. 

Свободный перевод ответа от участника @Nick Krasnov

→ Ссылка
Автор решения: 0xdb

Решение без запроса в функции:

create or replace function randomize (chars varchar2, len int) return varchar2 is 
    val varchar2 (32767);
begin
    for i in 1..len loop
        val := val||substr (chars, round (dbms_random.value (1, length(chars))), 1);
    end loop;

    return val;
end;
/

Если предполагается преимущественно использовать в SQL запросе, то эффективней будет, определить функцию прямо в запросе:

with 
function randomize (chars varchar2, len int) return varchar2 is 
    val varchar2 (32767);
begin
    for i in 1..len loop
        val := val||substr (chars, round (dbms_random.value (1, length(chars))), 1);
    end loop;
    return val;
end;
select randomize (trim (column_value), 10) rnd
from xmlTable ('"123abcdef", "09zyxwvu"')
cross join (select 0 from dual connect by level<=2);

RND
----------
feede2c32b
vxyv9wwz90
cafdae2a3b
0y9zzz9wv9

Оба примера воспроизводятся на db<>fiddle.

→ Ссылка