martes, 29 de noviembre de 2016

Generando Valores Aleatorios con DBMS_RANDOM

Objetivos:
• Conocer el paquete DBMS_RANDOM.
• Describir sus Funciones y Procedimientos.
• Presentar ejemplos prácticos y funcionales.

NOTA: Usamos como ejemplo la Base de Datos: ORCL, la cual viene por defecto en cualquier versión de ORACLE.
____________________________________________________________________________________
Paquete DBMS_RANDOM
Dependiendo del requerimiento se pueden presentar escenarios en los cuales sea necesario generar valores aleatorios, ya sea para crear una gran cantidad de datos para propósitos de prueba de desempeño, o cuando simplemente necesitamos asignar un número X a un proceso.

Cualquiera que sea la necesidad, Oracle provee el Paquete DBMS_RANDOM que permite generar valores  numéricos, tipo carácter y cadenas alfanuméricas de forma aleatoria. Tenga presente que es posible especificar el tamaño y el rango a ser usado en la generación de los valores aleatorios.

Nota: En este paquete podemos ver como la sobrecarga de procedimientos y funciones es posible dentro de Bloques de PL/SQL tales como: Bloques anónimos, Subprogramas y Paquetes. Es decir, puede utilizar el mismo nombre para varios subprogramas diferentes, siempre y cuando sus parámetros difieran en número, orden o tipos de dato.

Lista de Procedimientos/Funciones Disponibles:
Subprogram
Description
Procedimiento INITIALIZE
Inicializa el paquete con un valor de semilla (SEED value).
Función NORMAL
Retorna números aleatorios en una distribución normal.
Procedimiento RANDOM
Genera números aleatorios.
Procedimientos SEED
Restablece la semilla. Dicho procedimiento contiene una versión que recibe un parámetro BINARY_INTEGER(numérico) y una sobrecarga que recibe un tipo VARCHAR2(carácter).
Función STRING
Genera una cadena aleatoria.
Procedimiento TERMINATE
Finaliza el paquete.
Funciones VALUE
Esta función(sin parámetros) genera una numero aleatorio mayor o igual a 0 pero menor que 1. Su sobrecarga(con dos parámetros) genera un número aleatorio mayor o igual que el limite inferior(parámetro low) y menor que el limite superior(parámetro high). Ambas versiones tienen una precisión de 38 dígitos a la derecha del decimal.
Procedimiento INITIALIZE
Este procedimiento inicializa el generador. En síntesis este procedimiento es obsoleto ya que su función es simplemente llamar a los Procedimientos de SEED.
---
Función NORMAL
Esta función retorna números aleatorios en una distribución normal estándar.
---
Procedimiento RANDOM
Este procedimiento genera números aleatorios. Al igual que INITIALIZE, es considerado obsoleto y, aunque viene incluido en el paquete, no se recomienda su uso.
---
Procedimientos SEED
Estos procedimientos restablecen la semilla usada para generar números/cadenas aleatorias.
---
Función STRING
Esta función genera una cadena aleatoria. La misma recibe dos parámetros descritos a continuación:
Parámetro
Descripción
opt
Es usado para especificar el aspecto de la cadena de retorno:
  •  'u', 'U' – Retorna una cadena de caracteres alfabéticos en mayúsculas.
  •  'l', 'L' - Retorna una cadena de caracteres alfabéticos en minúsculas.
  •  'a', 'A' - Retorna una cadena de caracteres alfabéticos mixta (mayúsculas y minúsculas).
  •  'x', 'X' - Retorna una cadena de caracteres alfanuméricos en mayúsculas.
  •  'p', 'P' - Retorna una cadena de cualquier carácter imprimible.
Si no se especifica uno de los valores anteriores, se retorna una cadena de caracteres alfabéticos en mayúsculas.
len
Longitud de la cadena retornada.
Procedimiento TERMINATE
Se supone que una vez se haya terminado con el paquete, se debería llamar al procedimiento TERMINATE, pero realmente este no realiza función alguna y, aunque viene incluido en el paquete, es obsoleto y no debe utilizarse.
---
Funciones VALUE
Como ya especificamos, la función básica(sin parámetros) genera un número aleatorio, mayor o igual a 0 y menor que 1. La sobrecarga recibe dos parámetros (low y high) y retorna un numero mayor o igual que el primero (low) y menor que el segundo (high).
____________________________________________________________________________________
Ejemplos:
SELECT
        DBMS_RANDOM.NORMAL,
        DBMS_RANDOM.RANDOM,
        DBMS_RANDOM.string('U', 8),
        DBMS_RANDOM.string('L'8),
        DBMS_RANDOM.string('K'8),
        DBMS_RANDOM.VALUE,
        DBMS_RANDOM.VALUE(20,60)
FROM dual;
/*En este ejemplo invocamos las funciones */
---OUTPUT:
CREATE TABLE hr.calificaciones
(
    cod_estudiante      NUMBER(6),          --Código Estudiante
    cod_semestre        NUMBER(1)           --Código Semestre
                            CONSTRAINT ck_sem CHECK(cod_semestre IN (1,2)),
    espanol             NUMBER(3),      --no es recomendable usar la ñ para nombre de objectos de Base de Datos
    matematicas         NUMBER(3),
    sociales            NUMBER(3),
    naturales           NUMBER(3),

    CONSTRAINT pk_calif PRIMARY KEY (cod_estudiante, cod_semestre),
    CONSTRAINT ck_calif CHECK  --Constraint para limitar el rango de las calificaciones.
                           (
                                (espanol BETWEEN 1 AND 100)
                                AND
                                (matematicas BETWEEN 1 AND 100)
                                AND
                                (sociales BETWEEN 1 AND 100)
                                AND
                                (naturales BETWEEN 1 AND 100)
                           )
);
/*Creamos la tabla calificaciones para mostrar un ejemplo mas práctico del paquete DBMS_RANDOM.*/
---
DECLARE
    v_rec_calif     hr.calificaciones%ROWTYPE;
BEGIN
    FOR i IN 1..10 LOOP    --LOOP para los estudiantes...
        FOR j IN 1..LOOP   --LOOP para los semestres...
            v_rec_calif.cod_estudiante := i;
            v_rec_calif.cod_semestre := j;
            v_rec_calif.espanol := TRUNC(DBMS_RANDOM.VALUE(1,101));
            v_rec_calif.matematicas := TRUNC(DBMS_RANDOM.VALUE(1,101));
            v_rec_calif.sociales := TRUNC(DBMS_RANDOM.VALUE(1,101));
            v_rec_calif.naturales := TRUNC(DBMS_RANDOM.VALUE(1,101));
--
            INSERT INTO hr.calificaciones
            VALUES v_rec_calif;
        END LOOP;
--
        COMMIT;
    END LOOP;
END;
/*En este bloque anónimo nos valemos de la función VALUE del paquete RANDOM para insertar algunos registros en la tabla calificaciones, la lógica del SCRIPT es el siguiente: creamos una variable tipo Recordv_rec_calif con los campos de la tabla: calificaciones; usamos un FOR LOOP para generar los códigos de estudiantes (10) y otro LOOP FOR para generar 2 semestres por cada estudiante; y por último asignamos los valores generados por la función VALUE a los campos de la variable v_rec_calif  para su posterior inserción.*/
---
SELECT 
      cod_estudiante    AS estudiante,
      cod_semestre      AS semestre,
      espanol,
      matematicas,
      sociales,
      naturales,
      (espanol+matematicas+sociales+naturales)/AS promedio
FROM hr.calificaciones;
/*Consultamos la tabla para ver los registros insertados por el SCRIPT anterior.*/
---OUTPUT:
____________________________________________________________________________________
Fuentes: https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_random.htm#ARPLS040