DeepEdit!

Программирование баз данных на Oracle, техническая документация, литература, статьи и публикации

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Генерирование строк

В предыдущих разделах рассмотрены основы генерирования случайных значений, соответствующие функции и их инициализация, но все приведенные примеры относились к генерированию чисел. В этом разделе мы рассмотрим генерирование случайных символьных строк с помощью функции STRING пакета DBMS_RANDOM. Функция STRING принимает два параметра, opt и len.
Создание 40-символьной строки из букв в смешанном регистре с помощью нашей новой функции выглядит так:
Первый из них, opt, определяет тип генерируемой строки. Его возможные значения перечислены в табл. 7.1.
Таблица 7.1. Возможные значения параметра opt
Значение opt
Действие
u
Генерировать только буквы в верхнем регистре (например,
DFTHNDSW)
l
Генерировать только буквы в нижнем регистре (например,
pikdcdsd)
a
Генерировать только буквы в обоих регистрах (например, DeCW- Cass)
x
Генерировать буквы и цифры в верхнем регистре (например,
A1W56RTY)
P
Генерировать любые печатные символы (например, $\$2sw&*)

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

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

Давайте вспомним о цели, поставленной в начале этой главы: мы хотели создать тестовые данные, содержащие имена клиентов и значения остатков на их счетах, используя надежный способ рандомизации, с тем, чтобы полученные значения номеров и сумм были действительно случайными. Мы обсудили способ создания сумм остатков, а что насчет имен?
Можно было бы использовать нашу функцию get_random_string, но сейчас она возвращает только строки заданной длины. В действительности имена имеют переменную длину. Чтобы сгенерировать достаточно разнообразный набор имен, усовершенствуем нашу функцию: будем задавать минимальную и максимальную длину, а фактическая длина будет случайной в рамках этого диапазона. Вот вторая версия функции генерации случайных строк:

Вызывая функцию DBMS_RANDOM. STRING, передаем ей в качестве параметра длины строки случайное число из указанного параметрами диапазона. Проверим, как это работает:

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

4
91772
2043
FZIGIONR80U
5
91772
2043
FZIGIONR80U
6
91772
2043
FZIGIONR80U
7
91772
2043
FZIGIONR80U
СО
91772
2043
FZIGIONR80U
9
86258
8032
65YJYV9NMMBGMRP5CMP7
10
86258
8032
65YJYV9NMMBGMRP5CMP7

Как видите, результат весьма далек от ожидаемого. Слишком много совпадающих значений сумм и имен. Это совсем не похоже на по-настоящему случайный набор данных. В чем же ошибка?
Проблема заключается в начальном значении последовательности. Обратите внимание, что в 6 строке фрагмента кода функции seed передается значение, составленное из часов, минут и секунд. Но этот код выполняется менее чем за секунду, из-за чего каждый раз устанавливается одно и то же начальное значение, поэтому и сгенерированные случайные значения оказываются одинаковыми. В приведенном примере в итерациях с 1 по 8 использовались одинаковые начальные значения, вследствие чего и все «случайные» значения оказались одинаковыми. Начальное значение последовательности изменилось в девятой итерации, и это привело к изменению «случайного» значения.
Решить эту проблему можно простым удалением из программы строки с вызовом функции seed. Вот измененный код с закомментированной строкой:

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


Отнеситесь внимательно к полученному уроку. Использование одинаковых начальных значений последовательности случайных чисел приводит к предсказуемости результата работы генератора. Не задавая начального значения, мы получим действительно случайные числа. В примере выше программа выполнялась слишком быстро, опережая изменения начального значения. Но что делать, если требуется получать случайные значения, мы хотим использовать некоторое начальное значение, но ничего не знаем о скорости выполнения программы?
Решение заключается в добавлении к начальному значению дополнительного (и гарантированно изменяющегося) элемента. В приведенном фрагменте этим элементом может быть переменная цикла i, которая обязательно изменяет свое значение внутри цикла. Тогда код можно переписать следующим образом:

Обратите внимание на строку 6, где теперь к начальному значению добавляется компонент i. Это гарантирует, что значение каждый раз будет новым, даже при очень быстром выполнении программы. Такой подход можно использовать в любых программах, использующих случайные значения.
Никогда не устанавливайте начальное значение последовательности равным тому, каким оно было до вызова функции генерации случайного значения. Если вы в качестве начального значения используете некую переменную, значение которой потенциально может остаться неизменным (такую как текущее время), добавьте к ней другую переменную, которая гарантированно изменяется (например, счетчик цикла).
 









jAntivirus