Oracle

Paquetes en PL/SQL

Por : Jhons_1101
2018-12-07
Tags :
Los paquetes son una recopilación de funciones y procedimientos que son agrupados por módulos (Es una buena practica), estos módulos generalmente agrupan una funcionalidad. como por ejemplo módulo de clientes o estudiantes y dentro de este paquete PL/SQL, estarán por ejemplo las funciones get_obtenerCliente(), get_facturasPorCliente(), pr_modificaCliente(), etc.. donde (get_) sería una función para obtener datos y (pr_) sería un procedimiento el cual modifica transaccionalmente nuestra base de datos.

El paquete puede incluir un conjunto de procedimientos para formar una API. El paquete se compila y se almacena en la base de datos, donde sus contenidos pueden ser compartidos por muchas aplicaciones.
compartir en facebook compartir en Google compartir en Twitter compartir en Blogger compartir como código embebido compartir la url
Paquetes por lo general tienen dos partes, una especificación (SPEC) y un cuerpo; a veces el cuerpo no es necesario. La especificación es la interfaz para el paquete. Declara los tipos, variables, constantes, excepciones, cursores y subprogramas que pueden ser referenciados desde el exterior del paquete. El cuerpo define las consultas de los cursores y el código de los subprogramas.

Para crear las especificaciones del paquete, utilice la instrucción SQL CREATE PACKAGE. Una declaración CREATE PACKAGE BODY define el cuerpo del paquete.

La especificación contiene declaraciones públicas, que son visibles a los procedimientos almacenados. Debe declarar subprogramas al final de la especificación después de todos los demás elementos (excepto pragmas que nombran a una función específica; tales pragmas deben seguir las especificaciones de la función).

La cláusula AUTHID ordena a Oracle a ejecutar con derechos (permiso) de usuario solicitante (CURRENT_USER), o con los derechos de propietario (definidor). Si no se especifica la cláusula, Oracle utilizará por defecto DEFINER AUTHID.


Tenga en cuenta que para permitir la ejecución de código con derechos Invoker, la cláusula AUTHID debe ser utilizado antes de que el actual o con las palabras clave en la cabecera de rutina.


CREATE OR REPLACE PROCEDURE cu_test AUTHID CURRENT_USER IS 
BEGIN
  FOR rec IN (SELECT table_name FROM user_tables)
  LOOP
    dbms_output.put_line(rec.table_name);
  END LOOP;
END cu_test;
/




Que contiene un paquete PL/SQL


  • Get y Set son métodos para las variables de paquete.
  • Un Cursor. Realiza la consulta en varias ubicaciones, es más rápido que volver a escribir la misma consulta cada vez. También es más fácil de mantener y modificar si es necesario.
  • Las excepciones. Se puede manejar excepciones dentro de los subprogramas.
  • Procedimientos y funciones que se llaman entre sí. Usted no necesita preocuparse por orden de compilación de procedimientos y funciones empaquetadas.
  • Declaraciones de los procedimientos y funciones sobrecargadas. Se pueden crear múltiples variaciones de un procedimiento o función, utilizando los mismos nombres pero diferentes conjuntos de parámetros.
  • Las variables que desee permanecer disponible entre las llamadas de procedimiento en la misma sesión. Se pueden tratar variables en un paquete como variables globales.


  • Ventajas de paquetes PL/SQL


    Los paquetes tienen una larga historia en la ingeniería de software, que ofrece características importantes para el código fiable, fácil de mantener, reutilizable, a menudo en los esfuerzos de desarrollo de equipos para sistemas grandes.

    Modularidad


    Paquetes permiten encapsular tipos relacionados lógicamente, elementos y subprogramas en un módulo PL/SQL con nombre definido. Cada paquete se hace fácil de entender, y las interfaces entre los paquetes son simples, claras y bien definidas. Esto ayuda el desarrollo de aplicaciones.

    Diseño de aplicaciones más fácil


    Al diseñar una aplicación, todo lo que necesita es la información de interfaz. Puede codificar y compilar una especificación sin su cuerpo. No es necesario que defina los cuerpos de paquete por completo hasta que esté listo para completar la solicitud.

    Ocultación de información


    Con los paquetes, puede especificar si necesita que los tipos, los elementos y los subprogramas sean públicos (visibles y accesibles) o privada (oculto e inaccesible). Por ejemplo, si un paquete contiene cuatro subprogramas, tres podrían ser públicos y uno de ellos privado.
    El paquete oculta la ejecución del subprograma privado para que sólo el paquete (no la aplicación) se ve afectado. Esto simplifica el mantenimiento y la mejora del código. Además, al ocultar los detalles de implementación de los usuarios, a proteger la integridad del paquete.

    Añadido Funcionalidad


    Variables y cursores públicas envasados ​​persisten durante la duración de una sesión. Ellos pueden ser compartidos por todos los subprogramas que se ejecutan en el entorno. Ellos le permiten mantener datos a través de transacciones sin almacenarlo en la base de datos.

    Mejor presentación


    Cuando se llama a un subprograma (procedimiento o función) ​​por primera vez, todo el paquete se carga en memoria. las llamadas posteriores a subprogramas relacionados en el paquete no requieren ser cargadas de nuevo en disco.

    Los paquetes se detienen en cascada. Por ejemplo, si cambia el cuerpo de una función oprocedimiento de un paquete y este es afectado por nuevos parámetros o cambios en las variables de salida, los paquetes o subprogramas que llaman/consumen este paquete quedarán descompilador y será necesario volver a compilar.

    
    ------------------------------------------------------------------------------------
    -- Declaración de un paquete sin un cuerpo (body)
    ------------------------------------------------------------------------------------
    CREATE PACKAGE trans_data AS  -- bodiless package
       TYPE TimeRec IS RECORD (
          minutes SMALLINT,
          hours   SMALLINT);
       TYPE TransRec IS RECORD (
          category VARCHAR2(10),
          account  INT,
          amount   REAL,
          time_of  TimeRec);
       minimum_balance    CONSTANT REAL := 10.00;
       number_processed   INT;
       insufficient_funds EXCEPTION;
    END trans_data;
    
    


    Cómo usar el contenido del paquete
    Para hacer referencia a los tipos, artículos, subprogramas y características de llamada declaradas dentro de una especificación de paquete, se debe de usar la notación de puntos (.).

    <nombre_de_paquete>.type_name
    <nombre_de_paquete>.item_name
    <nombre_de_paquete>.subprogram_name
    <nombre_de_paquete>.call_spec_name
    /* Donde <nombre_de_paquete>, es el nombre del programa y lo siguiente al punto (.) es la referencia a el tipo, artículo, subprograma. */


    El cuerpo del paquete


    El cuerpo del paquete contiene la implementación de todos los punteros y subprograma declarados en la especificación de paquete. los subprogramas definidos en un cuerpo del paquete son accesibles fuera del paquete sólo si sus especificaciones también aparecen en la especificación de paquete.
    Si una especificación subprograma no está incluido en el paquete de especificaciones, el subprograma sólo puede ser llamado por otros subprogramas en el mismo paquete. Un cuerpo del paquete debe de estar en el mismo esquema que la especificación de paquete.

    El cuerpo del paquete también puede contener declaraciones privados, que definen los tipos y elementos necesarios para el funcionamiento interno del paquete. El alcance de estas declaraciones es local en el cuerpo del paquete. Por lo tanto, los tipos y los artículos declarados son inaccesibles excepto desde dentro del cuerpo del paquete.
    Después de la parte declarativa de un cuerpo del paquete es la parte de inicialización opcional, que normalmente tiene declaraciones que inicializan algunas de las variables declaradas con anterioridad en el paquete.
    La parte de inicialización de un paquete juega un papel menor, ya que, a diferencia de los subprogramas, un paquete no se puede llamar o pasar parámetros. Como resultado, la parte de inicialización de un paquete se ejecuta sólo una vez, la primera vez que hace referencia el paquete.

    Recuerde, si una especificación de paquete sólo declara tipos, constantes, variables, excepciones y especificaciones de llamados, el cuerpo del paquete es innecesaria. Sin embargo, el cuerpo todavía se puede utilizar para inicializar artículos declarados en la especificación de paquete.


    Casos prácticos de uso de un paquete PL/SQL



    
    ------------------------------------------------------------------------------------
    -- 
    ------------------------------------------------------------------------------------
    CREATE TABLE emp_audit(date_of_action DATE, user_id VARCHAR2(20), 
                           package_name VARCHAR2(30));
    
    CREATE OR REPLACE PACKAGE emp_admin AS
    -- Declare externally visible types, cursor, exception
       TYPE EmpRecTyp IS RECORD (emp_id NUMBER, sal NUMBER);
       CURSOR desc_salary RETURN EmpRecTyp;
       invalid_salary EXCEPTION;
    -- Declare externally callable subprograms
       FUNCTION hire_employee (last_name VARCHAR2, first_name VARCHAR2, 
         email VARCHAR2, phone_number VARCHAR2, job_id VARCHAR2, salary NUMBER,
         commission_pct NUMBER, manager_id NUMBER, department_id NUMBER) 
         RETURN NUMBER;
       PROCEDURE fire_employee (emp_id NUMBER); -- overloaded subprogram
       PROCEDURE fire_employee (emp_email VARCHAR2); -- overloaded subprogram
       PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER);
       FUNCTION nth_highest_salary (n NUMBER) RETURN EmpRecTyp;
    END emp_admin;
    /
    CREATE OR REPLACE PACKAGE BODY emp_admin AS
       number_hired NUMBER;  -- visible only in this package
    -- Fully define cursor specified in package
       CURSOR desc_salary RETURN EmpRecTyp IS
          SELECT employee_id, salary FROM employees ORDER BY salary DESC;
    -- Fully define subprograms specified in package
       FUNCTION hire_employee (last_name VARCHAR2, first_name VARCHAR2, 
         email VARCHAR2, phone_number VARCHAR2, job_id VARCHAR2, salary NUMBER,
         commission_pct NUMBER, manager_id NUMBER, department_id NUMBER) 
         RETURN NUMBER IS
         new_emp_id NUMBER;
       BEGIN
          SELECT employees_seq.NEXTVAL INTO new_emp_id FROM dual;
          INSERT INTO employees VALUES (new_emp_id, last_name, first_name, email,
            phone_number, SYSDATE, job_id, salary, commission_pct, manager_id,
            department_id);
          number_hired := number_hired + 1;
          DBMS_OUTPUT.PUT_LINE('The number of employees hired is ' 
                               || TO_CHAR(number_hired) );   
          RETURN new_emp_id;
       END hire_employee;
       PROCEDURE fire_employee (emp_id NUMBER) IS
       BEGIN
          DELETE FROM employees WHERE employee_id = emp_id;
       END fire_employee;
       PROCEDURE fire_employee (emp_email VARCHAR2) IS
       BEGIN
          DELETE FROM employees WHERE email = emp_email;
       END fire_employee;
      -- Define local function, available only inside package
       FUNCTION sal_ok (jobid VARCHAR2, sal NUMBER) RETURN BOOLEAN IS
          min_sal NUMBER;
          max_sal NUMBER;
       BEGIN
          SELECT MIN(salary), MAX(salary) INTO min_sal, max_sal FROM employees
             WHERE job_id = jobid;
          RETURN (sal >= min_sal) AND (sal <= max_sal);
       END sal_ok;
       PROCEDURE raise_salary (emp_id NUMBER, amount NUMBER) IS
          sal NUMBER(8,2);
          jobid VARCHAR2(10);
       BEGIN
          SELECT job_id, salary INTO jobid, sal FROM employees
                 WHERE employee_id = emp_id;
          IF sal_ok(jobid, sal + amount) THEN
             UPDATE employees SET salary = salary + amount WHERE employee_id = emp_id;
          ELSE
             RAISE invalid_salary;
          END IF;
       EXCEPTION  -- exception-handling part starts here
         WHEN invalid_salary THEN
           DBMS_OUTPUT.PUT_LINE('The salary is out of the specified range.');
       END raise_salary;
       FUNCTION nth_highest_salary (n NUMBER) RETURN EmpRecTyp IS
          emp_rec EmpRecTyp;
       BEGIN
          OPEN desc_salary;
          FOR i IN 1..n LOOP
             FETCH desc_salary INTO emp_rec;
          END LOOP;
          CLOSE desc_salary;
          RETURN emp_rec;
       END nth_highest_salary;
    BEGIN  -- initialization part starts here
       INSERT INTO emp_audit VALUES (SYSDATE, USER, 'EMP_ADMIN');
       number_hired := 0;
    END emp_admin;
    /
    -- calling the package procedures
    DECLARE
      new_emp_id NUMBER(6);
    BEGIN
      new_emp_id := emp_admin.hire_employee('Belden', 'Enrique', 'EBELDEN',
                       '555.111.2222', 'ST_CLERK', 2500, .1, 101, 110);
      DBMS_OUTPUT.PUT_LINE('The new employee id is ' || TO_CHAR(new_emp_id) );
      EMP_ADMIN.raise_salary(new_emp_id, 100);
      DBMS_OUTPUT.PUT_LINE('The 10th highest salary is '|| 
        TO_CHAR(emp_admin.nth_highest_salary(10).sal) || ', belonging to employee: ' 
        || TO_CHAR(emp_admin.nth_highest_salary(10).emp_id) );
      emp_admin.fire_employee(new_emp_id);
    -- you could also delete the newly added employee as follows:
    --  emp_admin.fire_employee('EBELDEN');
    END;
    
    





    Si este contenido te fue útil, no olvides compartirlo en redes sociales, Considéralo. Puede ser la manera de agradecer!


    Agrega tu comentario...

    Puedes utilizar etiquetas <pre></pre>, <p></p>, <div></div>, + (Nombre usuario, para responderle a alguien)

    BxV7J1S





    Este post no tiene comentarios, sé el primero en hacerlo
    Esta entrada no cuenta con imágenes adjuntas

    Unete al grupo de whatsApp +57 316 392 6456

    Sigue el grupo en facebook

    Siguenos.....