项目作者: EdwinPalacio5

项目描述 :
Learning PL/SQL Database ORACLE 12 c
高级语言: PLSQL
项目地址: git://github.com/EdwinPalacio5/learning-plsql.git
创建时间: 2020-05-16T04:11:22Z
项目社区:https://github.com/EdwinPalacio5/learning-plsql

开源协议:

下载


learning-PLSQL Oracle 12c

Estructura de Bloque PL/SQL

  1. DECLARE (opcional)
  2. Variables, cursores, excepciones definida por usuario
  3. BEGIN (mandatorio)
  4. Setencias SQL
  5. Sentencias PL/SQL
  6. EXCEPTION (opcional)
  7. Acciones a desarrollar cuando ocurre una excepción
  8. END; (mandatorio)

Tipos de Bloque

Anónimo

  1. [DECLARE]
  2. BEGIN
  3. --sentencias
  4. [EXCEPTION]
  5. END;

Procedimiento

  1. PROCEDURE nombre
  2. IS
  3. BEGIN
  4. --sentencias
  5. [EXCEPTION]
  6. END;

Función

  1. FUNCTION nombre
  2. RETURN tipoDato
  3. IS
  4. BEGIN
  5. --sentencias
  6. RETURN valor;
  7. [EXCEPTION]
  8. END;

Ejemplo Bloque Anonimo:

  1. -- Para habilitar la salida en SQL Developer
  2. SET SERVEROUTPUT ON;
  3. DECLARE
  4. v_fname VARCHAR(20);
  5. BEGIN
  6. SELECT first_name INTO v_fname
  7. FROM employees
  8. WHERE employee_id=100;
  9. --paquete predefinido Oracle (DBMS_OUTPUT)y su procedimiento (PUT_LINE)
  10. DBMS_OUTPUT.PUT_LINE('El primer nombre del empleado es ' || v_fname);
  11. END;

Resultado:

  1. Procedimiento PL/SQL terminado correctamente.
  2. El primer nombre del empleado es Steven

Declarando Variables PL/SQL

Sintaxis

  1. identifier [CONSTANT] datatype [NOT NULL] [:= | DEFAULT expr];

Ejemplos:

  1. DECLARE
  2. v_myname varchar(20);
  3. v_mycity varchar(20) := 'San Martin';
  4. BEGIN
  5. v_myname := 'Edwin';
  6. DBMS_OUTPUT.PUT_LINE('Mi nombre es: ' || v_myname);
  7. DBMS_OUTPUT.PUT_LINE('Vivo en: ' || v_mycity);
  8. END;

Resultado:

  1. Procedimiento PL/SQL terminado correctamente.
  2. Mi nombre es: Edwin
  3. Vivo en: San Martin

Tipos de Variables

  • PL/SQL variables
    • Escalar: Sostiene un solo valor, no tiene componentes internos (Boolean, text, integer, date, varchar, char, binary_float, bynary_double, pls_integer, binary_integer, timestamp, interval)
    • Referencia:
    • Objetos largos(LOB: Oracle no va a tratar de interpretarlo, solo lo almacena):
      • Libros: CLOB,
      • Photo: BLOB,
      • MOVIE: BFILE (Se almacena fuera de la base de datos),
      • Caracteres especiales: NCLOB
    • Compuestos:
      • Colecciones,
      • Registro
  • Variables No-PL/SQL:
    • Bind variables (enlazadas) o lenguaje principal

Convención de nombres de variables

Estructura PL/SQL Convención Ejemplo
Variable v_variable_name v_rate v_variable_name v_rate
Constante c_constant_name c_rate c_constant_name c_rate
Parámetro de subprograma p_parameter_name p_id
Bind (host) variable b_bind_name b_salary
Cursor cur_cursor_name cur_emp
Registro rec_record_name rec_emp
Tipo type_name_type ename_table_type
Excepción e_exception_name e_products_invalid
Archivo f_file_handle_name f_file

Declarando variables con el atributo %type

  1. DECLARE
  2. v_emp_lname employees.last_name%TYPE;
  3. BEGIN
  4. SELECT last_name INTO v_emp_lname
  5. FROM employees
  6. WHERE employee_id = 100;
  7. DBMS_OUTPUT.PUT_LINE('Mi apellido es: ' || v_emp_lname);
  8. END;

Resultado:

  1. Procedimiento PL/SQL terminado correctamente.
  2. Mi apellido es: King

Variables Bind o enlazadas

  1. VARIABLE b_emp_salary NUMBER;
  2. BEGIN
  3. SELECT salary INTO :b_emp_salary
  4. FROM employees
  5. WHERE employee_id=100;
  6. END;
  7. /
  8. PRINT b_emp_salary;
  9. SELECT first_name
  10. FROM employees
  11. WHERE salary = :b_emp_salary;

Resultado:

  1. Procedimiento PL/SQL terminado correctamente.
  2. B_EMP_SALARY
  3. ------------
  4. 24000
  5. FIRST_NAME
  6. --------------------
  7. Steven

AUTOPRINT con BIND Variables

  1. VARIABLE b_emp_salary NUMBER
  2. SET AUTOPRINT ON
  3. DECLARE
  4. v_empno NUMBER(6) := &empno;
  5. BEGIN
  6. SELECT salary into :b_emp_salary
  7. FROM employees
  8. WHERE employee_id = v_empno;
  9. END;

Resultado:

  1. Antiguo:DECLARE
  2. v_empno NUMBER(6) := &empno;
  3. BEGIN
  4. SELECT salary into :b_emp_salary
  5. FROM employees
  6. WHERE employee_id = v_empno;
  7. END;
  8. Nuevo:DECLARE
  9. v_empno NUMBER(6) := 140;
  10. BEGIN
  11. SELECT salary into :b_emp_salary
  12. FROM employees
  13. WHERE employee_id = v_empno;
  14. END;
  15. Procedimiento PL/SQL terminado correctamente.
  16. B_EMP_SALARY
  17. ----
  18. 2500

Escritura de Sentencias SQL Ejecutables

Antes de todo, Habilitamos la salida en SQL Developer

  1. SET SERVEROUTPUT ON;

Uso de Comentarios y Funciones de una sola fila

  1. DECLARE
  2. --declaramos variable de salario anual
  3. v_salario_anual NUMBER(9, 2);
  4. v_last_name employees.last_name%TYPE;
  5. v_hire_date employees.hire_date%TYPE;
  6. BEGIN
  7. /* asignamos valor de salario anual: se consulta el
  8. salario mensual y se multiplica por 12
  9. */
  10. SELECT salary * 12, last_name, hire_date
  11. INTO v_salario_anual, v_last_name, v_hire_date
  12. FROM employees
  13. WHERE employee_id = 100;
  14. --se imprime variable de salario anual
  15. dbms_output.put_line('Salario anual: ' || v_salario_anual);
  16. /* uso de variable de una sola fila:
  17. mostrar la cantidad de caracteres de last_name
  18. */
  19. dbms_output.put_line('Tamano de last_name: '
  20. || v_last_name
  21. || ' '
  22. || length(v_last_name));
  23. /* uso de variable de una sola fila:
  24. para determinar la cantidad de dias desde su contratación
  25. */
  26. dbms_output.put_line('cantidad de dias desde contratacion: '
  27. || months_between(sysdate, v_hire_date));
  28. END;
  29. /
  30. Resultado:
  31. Salario anual: 288000
  32. Tamano de last_name: King 4
  33. cantidad de dias desde contratacion: 203.67
  34. Procedimiento PL/SQL terminado correctamente.

Bloques anidados

  1. DECLARE
  2. v_externa VARCHAR2(20) := 'VARIABLE EXTERNA';
  3. BEGIN
  4. DECLARE
  5. v_interna VARCHAR2(20) := 'VARIABLE INTERNA';
  6. BEGIN
  7. dbms_output.put_line(v_externa);
  8. dbms_output.put_line(v_interna);
  9. END;
  10. dbms_output.put_line(v_externa);
  11. -- DBMS_OUTPUT.PUT_LINE(v_interna); variable interna no se encuentra en el alcance
  12. END;
  13. Resultados:
  14. VARIABLE EXTERNA
  15. VARIABLE INTERNA
  16. VARIABLE EXTERNA
  17. Procedimiento PL/SQL terminado correctamente.

Nombramientos por bloque

Son cualificadores o etiquetas que permiten identificar explicitamente de que ambito se encuentra la variable a la que se hace referencia

  1. BEGIN <<externo>>
  2. DECLARE
  3. v_variable VARCHAR2(20) := 'VARIABLE EXTERNA';
  4. BEGIN
  5. DECLARE
  6. v_variable VARCHAR2(20) := 'VARIABLE INTERNA';
  7. BEGIN
  8. dbms_output.put_line(v_variable);
  9. --Si agregamos el nombramiento, se hace referencia no a la variable interna sino a la externa
  10. dbms_output.put_line(externo.v_variable);
  11. END;
  12. dbms_output.put_line(v_variable);
  13. -- DBMS_OUTPUT.PUT_LINE(v_interna); variable interna no se encuentra en el alcance
  14. END;
  15. END externo;
  16. Resultados:
  17. VARIABLE INTERNA
  18. VARIABLE EXTERNA
  19. VARIABLE EXTERNA
  20. Procedimiento PL/SQL terminado correctamente.

Uso de Sentencias SQL en un bloque PL/SQL

SET SERVEROUTPUT ON;

Utilizando PL/SQL para la Manipulación de datos. Hacer cambios en las tablas de bases de datos mediante el uso de comandos DML:

  • INSERT
  • UPDATE
  • DELETE
  • MERGE

INSERT

  1. BEGIN
  2. INSERT INTO employees (employee_id, first_name, last_name, email, hire_date, job_id, salary)
  3. VALUES(employees_seq.NEXTVAL, 'Edwin', 'Palacios', 'edwin@gmail.com', CURRENT_DATE, 'AD_ASST', 4000);
  4. END;
  5. /

UPDATE

  1. Declare
  2. v_incremento_salario employees.salary%type := 800;
  3. Begin
  4. Update employees
  5. set salary = salary + v_incremento_salario
  6. Where job_id = 'ST_CLERK';
  7. End;
  8. /

Nota: Como se puede observar el SQL se trabaja de forma igual, Asimismo con eliminar, merge, commit, rollback y savepoint

Cursor SQL

Un cursor es un puntero a la zona de memoria privada asignada por el servidor Oracle. Se utiliza para manejar el conjunto de resultados de una sentencia SELECT

Hay dos tipos de cursores: implícitos y explícitos.

– Implícito: Creado y gestionado internamente por el servidor Oracle para procesar sentencias SQL.

– Explícita: Declarado explícitamente por el programador.

Atributos de Cursor

Atributo Descripción
SQL%FOUND Atributo booleano que se evalúa como TRUE si la última sentencia SQL afectó al menos una fila
SQL%NOTFOUND Atributo booleano que se evalúa como TRUE si la última sentencia SQL no afectó ni una fila
SQL%ROWCOUNT Un valor entero que representa el número de filas afectadas por la última sentencia SQL

Ejemplo de ROWCOUNT

  1. SET SERVEROUTPUT ON;
  2. Declare
  3. v_disminucion_salario employees.salary%type := 800;
  4. Begin
  5. Update employees
  6. set salary = salary - v_disminucion_salario
  7. Where job_id = 'ST_CLERK';
  8. DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' filas afectadas');
  9. End;

Estructuras de Control en bloque PLSQL

SET SERVEROUTPUT ON;

IF - THEN - ELSIF - ELSE - END IF

Sintaxis

  1. IF condition THEN
  2. statements;
  3. [ELSIF condition THEN
  4. statements;]
  5. [ELSE
  6. statements;]
  7. END IF;

Ejemplo

  1. DECLARE
  2. v_edad number := 185;
  3. BEGIN
  4. IF (v_edad < 18) THEN
  5. DBMS_OUTPUT.PUT_LINE('Menor de edad');
  6. ELSIF (v_edad < 60 AND v_edad >= 18) THEN
  7. DBMS_OUTPUT.PUT_LINE('Mayor de edad');
  8. ELSIF (v_edad < 100 AND v_edad >= 60) THEN
  9. DBMS_OUTPUT.PUT_LINE('Adulto mayor');
  10. ELSE
  11. DBMS_OUTPUT.PUT_LINE('Wow');
  12. END IF;
  13. END;
  14. /

Sentencias Case

Selecciona un resultado y lo devuelve
Sintaxis

  1. CASE selector
  2. WHEN expression1 THEN result1
  3. [WHEN expression2 THEN result2
  4. ...
  5. WHEN expressionN THEN resultN]
  6. [ELSE resultN+1]
  7. END;

Ejemplo

  1. DECLARE
  2. v_nota number(9,2) := 8;
  3. v_valoracion varchar2(20);
  4. BEGIN
  5. v_valoracion := CASE v_nota
  6. WHEN 10 THEN 'Excelente'
  7. WHEN 9 THEN 'Muy bueno'
  8. WHEN 8 THEN 'Bueno'
  9. ELSE 'Esfuerzate mas'
  10. END;
  11. DBMS_OUTPUT.PUT_LINE('Valoracion obtenida mediante sentencia CASE: ' || v_valoracion);
  12. END;
  13. /

Expresiones CASE de busqueda

La cual ofrece una mejor libertad

  1. DECLARE
  2. v_nota number(9,2) := 7.5;
  3. v_valoracion varchar2(20);
  4. BEGIN
  5. v_valoracion := CASE
  6. WHEN (v_nota >= 9 AND v_nota <= 10) THEN 'Excelente'
  7. WHEN (v_nota >= 7 AND v_nota < 9) THEN 'Muy bueno'
  8. WHEN (v_nota >= 6 AND v_nota < 7) THEN 'Bueno'
  9. ELSE 'Esfuerzate mas'
  10. END;
  11. DBMS_OUTPUT.PUT_LINE('Valoracion obtenida mediante expresiones CASE: ' || v_valoracion);
  12. END;
  13. /

Insertando SQL en case

En el siguiente ejercicio trata sobre un aumento de salario, si es el departamento de codigo 100, sus empleados aumentaran en un 10% su salario y los demás departamentos en un 5%

  1. DECLARE
  2. v_department_id departments.department_id%type := 100;
  3. BEGIN
  4. CASE v_department_id
  5. WHEN 100 THEN UPDATE employees
  6. SET salary = salary*1.1
  7. WHERE department_id = v_department_id;
  8. ELSE UPDATE employees
  9. SET salary = salary*1.05
  10. WHERE department_id = v_department_id;
  11. END CASE;
  12. DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' empleados beneficiados');
  13. END;
  14. /

Sentencias de bucle

LOOP

Sintaxis

  1. LOOP
  2. statements1;
  3. ...
  4. EXIT [WHEN condition];
  5. END LOOP;

Ejemplo

  1. DECLARE
  2. v_count number:= 0;
  3. BEGIN
  4. LOOP
  5. DBMS_OUTPUT.PUT_LINE('Valor de contador en LOOP Basico: ' || v_count);
  6. -- incremento de contador
  7. v_count := v_count + 1;
  8. EXIT WHEN v_count > 4;
  9. END LOOP;
  10. END;
  11. /
  12. Resultado:
  13. Valor de contador en LOOP Basico: 0
  14. Valor de contador en LOOP Basico: 1
  15. Valor de contador en LOOP Basico: 2
  16. Valor de contador en LOOP Basico: 3
  17. Valor de contador en LOOP Basico: 4
  18. Procedimiento PL/SQL terminado correctamente.

While

Repite mientras la condición sea true

  1. WHILE condition
  2. LOOP
  3. statements1;
  4. statements2;
  5. ...
  6. END LOOP;

ejemplo

  1. DECLARE
  2. v_count number:= 0;
  3. BEGIN
  4. WHILE (v_count <= 4)
  5. LOOP
  6. DBMS_OUTPUT.PUT_LINE('Valor de contador en WHILE: ' || v_count);
  7. -- incremento de contador
  8. v_count := v_count + 1;
  9. END LOOP;
  10. END;
  11. /
  12. Resultado:
  13. Valor de contador en WHILE: 0
  14. Valor de contador en WHILE: 1
  15. Valor de contador en WHILE: 2
  16. Valor de contador en WHILE: 3
  17. Valor de contador en WHILE: 4
  18. Procedimiento PL/SQL terminado correctamente.

FOR

El contador (counter) se declara implicitamente

  1. FOR counter IN [REVERSE] lower_bound..upper_bound
  2. LOOP
  3. statements1;
  4. statements2;
  5. ...
  6. END LOOP;
  1. BEGIN
  2. FOR i IN 0..4
  3. LOOP
  4. DBMS_OUTPUT.PUT_LINE('Valor de contador en FOR: ' || i);
  5. END LOOP;
  6. END;
  7. /
  8. Resultado:
  9. Valor de contador en FOR: 0
  10. Valor de contador en FOR: 1
  11. Valor de contador en FOR: 2
  12. Valor de contador en FOR: 3
  13. Valor de contador en FOR: 4
  14. Procedimiento PL/SQL terminado correctamente.

For REVERSE

Observar que el rango siempre se agrega de manera ascendete

  1. BEGIN
  2. FOR i IN REVERSE 0..4
  3. LOOP
  4. DBMS_OUTPUT.PUT_LINE('Valor de contador en FOR ENVERSE: ' || i);
  5. END LOOP;
  6. END;
  7. /
  8. Resultado:
  9. Valor de contador en FOR ENVERSE: 4
  10. Valor de contador en FOR ENVERSE: 3
  11. Valor de contador en FOR ENVERSE: 2
  12. Valor de contador en FOR ENVERSE: 1
  13. Valor de contador en FOR ENVERSE: 0
  14. Procedimiento PL/SQL terminado correctamente.

LOOPS anidados y etiquetas

ejemplo

  1. DECLARE
  2. v_contador_externo number := 0;
  3. v_contador_interno number := 0;
  4. BEGIN
  5. <<loop_externo>>
  6. LOOP
  7. v_contador_interno := 0;
  8. <<loop_interno>>
  9. LOOP
  10. DBMS_OUTPUT.PUT_LINE(v_contador_externo || v_contador_interno);
  11. v_contador_interno := v_contador_interno +1;
  12. EXIT loop_interno WHEN v_contador_interno > 2;
  13. END LOOP loop_interno;
  14. v_contador_externo := v_contador_externo +1;
  15. EXIT loop_externo WHEN v_contador_externo > 2;
  16. END LOOP loop_externo;
  17. END;
  18. Resultado:
  19. 00
  20. 01
  21. 02
  22. 10
  23. 11
  24. 12
  25. 20
  26. 21
  27. 22
  28. Procedimiento PL/SQL terminado correctamente.

Tipos de datos compuestos

SET SERVEROUTPUT ON;

Registros

  1. DECLARE
  2. -- Registro
  3. TYPE t_rec IS RECORD(
  4. v_sal number(8),
  5. v_minsal number(8) DEFAULT 1000,
  6. v_hire_date employees.hire_date%type,
  7. v_rec1 employees%rowtype -- %rowtype permite definir un elemento con la estructura de la tabla
  8. );
  9. v_myrec t_rec; -- Se usa el identificador v_myrec para t_rec
  10. BEGIN
  11. -- ejemplo de como se puede manipular los elementos del registro
  12. v_myrec.v_sal := v_myrec.v_minsal + 500;
  13. -- ejemplo de como obtener una fila completa
  14. SELECT * INTO v_myrec.v_rec1
  15. FROM employees
  16. WHERE employee_id = 100;
  17. DBMS_OUTPUT.PUT_LINE('V_SAL: ' || v_myrec.v_sal);
  18. DBMS_OUTPUT.PUT_LINE('Salario real através de V_REC1: '
  19. || v_myrec.v_rec1.salary
  20. || ' del empleado: '
  21. || v_myrec.v_rec1.first_name);
  22. END;
  23. /
  24. Resultado:
  25. V_SAL: 1500
  26. Salario real através de V_REC1: 24000 del empleado: Steven
  27. Procedimiento PL/SQL terminado correctamente.

Arreglos Asociados (llave, valor)

El valor bien puede ser escalar, creado bajo la deficion de una columna (%type) o mediante la definicion de una tabla o record (%rowtype)

  1. DECLARE
  2. -- declaración de arreglo asociado de tipo igual a la estructura de la columna LAST_NAME
  3. TYPE ename_table_type IS TABLE OF employees.last_name%type
  4. INDEX BY PLS_INTEGER; -- PLS_INTEGER | BINARY_INTEGER
  5. -- declaración de identificador
  6. ename_table ename_table_type;
  7. BEGIN
  8. --asignamos al arreglo el elemento con index 1
  9. ename_table(1) := 'PALACIOS';
  10. IF (ename_table.EXISTS(1)) THEN
  11. DBMS_OUTPUT.PUT_LINE(ename_table(1));
  12. END IF;
  13. END;
  14. /

Además de EXISTS, los metodos que se pueden utilizar son: EXISTS, COUNT, FIRST, LAST, PRIOR (el previo), NEXT, DELETE

VARRAY

Array variables, son de longitud fija

  1. DECLARE
  2. --Declaramos VARRAY
  3. TYPE emp_array IS VARRAY(100) OF VARCHAR2(30);
  4. --identificador
  5. emps emp_array;
  6. BEGIN
  7. -- agregamos elementos al VARRAY
  8. emps := emp_array('Scrum', 'XP');
  9. --agregar el espacio de un elemento mas
  10. emps.extend;
  11. -- agregamos elemento
  12. emps(emps.LAST) := 'Kanba';
  13. -- imprimimos elemento
  14. FOR indice IN emps.FIRST..emps.LAST
  15. LOOP
  16. DBMS_OUTPUT.PUT_LINE(emps(indice));
  17. END LOOP;
  18. END;
  19. /
  20. Resultados:
  21. Scrum
  22. XP
  23. Kanba
  24. Procedimiento PL/SQL terminado correctamente.

VARRAY en SQL

  1. Create or replace TYPE emp_array AS VARRAY(100) OF VARCHAR2(30);
  2. Describe emp_array;
  3. Resultado:
  4. Type EMP_ARRAY compilado
  5. Nombre ¿Nulo? Tipo
  6. --------- ------ ---------------------------
  7. EMP_ARRAY VARRAY(100) OF VARCHAR2(30)

Nota: teniendo este VARRAY se puede utilizar como cualquier tipo de dato en ORACLE

Consulta de VARRAY en SQL

  1. Select name
  2. From club
  3. Where 'Gen' IN (SELECT * From table(club.members));

Donde members es un campo en la tabla club de tipo VARRAY

Cursores Explicitos

SET SERVEROUTPUT ON;

Sintaxis

  1. CURSOR cursor_name IS
  2. select_estatements:

Ejemplo

  1. DECLARE
  2. -- 1. declara cursor
  3. CURSOR c_emp_cursor IS
  4. SELECT employee_id, last_name
  5. FROM employees
  6. WHERE department_id = 30;
  7. v_emp_id employees.employee_id%type;
  8. v_emp_last_name employees.last_name%type;
  9. BEGIN
  10. -- 2. abrir el cursos
  11. OPEN c_emp_cursor;
  12. LOOP
  13. -- 3. fetch, asignar valores dentro de el fetch a variables
  14. FETCH c_emp_cursor INTO v_emp_id, v_emp_last_name;
  15. DBMS_OUTPUT.PUT_LINE(v_emp_id || ' ' ||v_emp_last_name);
  16. -- 4. se itera el cursor hasta que ya no exista más tuplas usando la propiedad %NOTFOUND
  17. EXIT WHEN c_emp_cursor%NOTFOUND;
  18. END LOOP;
  19. -- 5. Close Se cierra el cursor
  20. CLOSE c_emp_cursor;
  21. END;
  22. /

Cursores y registros

En este caso se crea un variable record con la estructura del cursor

  1. DECLARE
  2. -- 1. declara cursor
  3. CURSOR c_emp_cursor IS
  4. SELECT employee_id, last_name
  5. FROM employees
  6. WHERE department_id = 30;
  7. -- declaración de variable record con la estructura del cursor
  8. v_emp_record c_emp_cursor%rowtype;
  9. BEGIN
  10. -- 2. abrir el cursos
  11. OPEN c_emp_cursor;
  12. LOOP
  13. -- 3. fetch, asignar valores dentro de el fetch a variables
  14. FETCH c_emp_cursor INTO v_emp_record;
  15. DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id
  16. || ' '
  17. ||v_emp_record.last_name);
  18. -- 4. se itera el cursor hasta que ya no exista más tuplas usando la propiedad %NOTFOUND
  19. EXIT WHEN c_emp_cursor%NOTFOUND;
  20. END LOOP;
  21. -- 5. Close Se cierra el cursor
  22. CLOSE c_emp_cursor;
  23. END;
  24. /

Cursor con bucle FOR (RECOMENDADO)

Se recomienda esta practica, dado que:

  • El cursor bucle FOR es un atajo para procesar cursores explicitos.

  • se evita hacer: OPEN, FETCH, EXIT Y CLOSE.

  • el registro es implicitamente declarado.

  1. DECLARE
  2. -- 1. declara cursor
  3. CURSOR c_emp_cursor IS
  4. SELECT employee_id, last_name
  5. FROM employees
  6. WHERE department_id = 30;
  7. BEGIN
  8. -- 2. Se itera el cursor asignando al record v_emp_record (creado implícitamente)
  9. FOR v_emp_record IN c_emp_cursor
  10. LOOP
  11. DBMS_OUTPUT.PUT_LINE(v_emp_record.employee_id
  12. || ' '
  13. ||v_emp_record.last_name);
  14. END LOOP;
  15. END;
  16. /
  1. Resultado de los tres ejemplos anteriores:
  2. 114 Raphaely
  3. 115 Khoo
  4. 116 Baida
  5. 117 Tobias
  6. 118 Himuro
  7. 119 Colmenares
  8. 119 Colmenares
  9. Procedimiento PL/SQL terminado correctamente.

Atributos de cursores

Atributo Tipo Descripción
%ISOPEN Boolean Evalua a TRUE si el cursor esta abierto
%NOTFOUND Boolean Evalua a TRUE si la más reciente recuperación no retorna una fila
%FOUND Boolean Evalua a TRUE si la más reciente recuperación retorna una fila; complemento de %NOTFOUND
%ROWCOUNT Number Evalua el número de filas que han sido recuperadas.

CURSOR FOR LOOPS utilizando Subconsultas

De esta manera se evita declarar el cursor

  1. BEGIN
  2. FOR emp_record IN ( SELECT employee_id, last_name
  3. FROM employees
  4. WHERE department_id = 30) -- observar que no se utiliza ;
  5. LOOP
  6. DBMS_OUTPUT.PUT_LINE(emp_record.employee_id
  7. || ' '
  8. ||emp_record.last_name);
  9. END LOOP;
  10. END;
  11. /
  1. Resultado:
  2. 114 Raphaely
  3. 115 Khoo
  4. 116 Baida
  5. 117 Tobias
  6. 118 Himuro
  7. 119 Colmenares
  8. Procedimiento PL/SQL terminado correctamente.

Cursor con parametros

  1. DECLARE
  2. CURSOR c_emp_cursor (deptno NUMBER) IS SELECT employee_id, last_name
  3. FROM employees
  4. WHERE department_id = deptno;
  5. BEGIN
  6. DBMS_OUTPUT.PUT_LINE('Empleados del deptno 10');
  7. FOR r_emp_record IN c_emp_cursor(10)
  8. LOOP
  9. DBMS_OUTPUT.PUT_LINE(r_emp_record.employee_id
  10. || ' '
  11. ||r_emp_record.last_name);
  12. END LOOP;
  13. DBMS_OUTPUT.PUT_LINE('Empleados del deptno 20');
  14. FOR r_emp_record IN c_emp_cursor(20)
  15. LOOP
  16. DBMS_OUTPUT.PUT_LINE(r_emp_record.employee_id
  17. || ' '
  18. ||r_emp_record.last_name);
  19. END LOOP;
  20. END;
  1. Resultado:
  2. Empleados del deptno 10
  3. 200 Whalen
  4. Empleados del deptno 20
  5. 201 Hartstein
  6. 202 Fay
  7. Procedimiento PL/SQL terminado correctamente.

Clausula For Update

Bloqueo explicito para denegar el acceso a otras sesiones durante el tiempo de transacción

  1. Select *
  2. From employees
  3. For Update [OF column_reference] [NOWAIT | WAIT n];

Clausula WHERE CURRENT OF

Utilizado para referenciar la fila actual desde un cursor explicito con el objetivo de editar o eliminar una fila a través del cursor.

Sintaxis:

  1. WHERE CURRENT OF cursor_name;

ejemplo:

  1. UPDATE employees
  2. SET salary = ...
  3. WHERE CURRENT OF c_emp_cursor;

Recomendaciones con cursores: Utilizar FOR UPDATE en las filas que se desea bloquear o borrar, esto con el objetivo de bloquear el acceso mediante otras sesiones permitiendo que la información se encuentre consistente

Excepciones

Sintaxis para atrapar excepciones

  1. EXCEPTION
  2. WHEN exception1 [OR exception2 ... ] THEN
  3. statements1;
  4. statements2;
  5. ...
  6. [WHEN exception3 [OR exception4 ... ] THEN
  7. statements1;
  8. statements2;
  9. ...]
  10. [WHEN OTHERS THEN
  11. statements1;
  12. statements2;
  13. ...]

Excepciones predefinidas de ejemplo:

  • NO_DATA_FOUND : no encuentra datos en la consulta.

  • TOO_MANY_ROWS : devuelve mas de las filas esperadas.

  • INVALID_CURSOR : Cursor invalido.

  • ZERO_DIVIDE : division entre cero.

  • DUP_VAL_ON_INDEX: Cuando se quiere duplicar una llave primaria.

Excepciones No predefinidas

Ejemplo: se desea atrapar la excepcion de querer registrar un valor null

  1. DECLARE
  2. e_insert_exception EXCEPTION; -- declaracion de exception
  3. PRAGMA EXCEPTION_INIT(e_insert_exception, -01400); -- se coloca el codigo del servidor oracle cuando no se pueden editar valores nulos
  4. BEGIN
  5. INSERT INTO departments (department_id, department_name)
  6. VALUES (280, NULL);
  7. EXCEPTION
  8. WHEN e_insert_exception THEN -- referencia de la exception en el when
  9. DBMS_OUTPUT.PUT_LINE('OPERACION DE INSERCION FALLIDA');
  10. DBMS_OUTPUT.PUT_LINE(SQLERRM);
  11. END;
  12. /
  1. Resultado:
  2. OPERACION DE INSERCION FALLIDA
  3. ORA-01400: no se puede realizar una inserción NULL en ("HR"."DEPARTMENTS"."DEPARTMENT_NAME")
  4. Procedimiento PL/SQL terminado correctamente.

Funciones para atrapar Errores

  • SQLCODE: Devuelve el valor numérico para el código de error.

  • SQLERRM: Devuelve el mensaje asociado con el número de error.

  1. ...
  2. EXCEPTION
  3. ...
  4. WHEN OTHERS THEN
  5. error_code := SQLCODE;
  6. error_message := SQLRRM;
  7. ...
  8. END;

Atrapando funciones definidas por el usuario (RAISE)

Utilizando RAISE se pueden atrapar excepciones definidas por el usuario.

  1. - Detiene la ejecución normal de un bloque PL / SQL o subprograma y transfiere el control a un controlador de excepciones.
  2. - Explícitamente plantea excepciones predefinidas o excepciones definidas por el usuario.

En el siguiente ejemplo se dispara una excepcion para indicar que el usuario debe ser mayor de edad.

  1. DECLARE
  2. v_edad NUMBER := 27;
  3. e_restriccion_edad_exception EXCEPTION;
  4. BEGIN
  5. IF v_edad > 18 THEN
  6. DBMS_OUTPUT.PUT_LINE('Bienvenid@');
  7. ELSE
  8. RAISE e_restriccion_edad_exception; -- activamos la excepcion de restriccion de edad
  9. END IF;
  10. EXCEPTION
  11. WHEN e_restriccion_edad_exception THEN
  12. DBMS_OUTPUT.PUT_LINE('Acceso denegado, debes ser mayor de edad');
  13. END;
  14. /

Procedure RAISE_APPLICATION_ERROR

Puede usar este procedimiento para emitir mensajes de error definidos por el usuario de subprogramas almacenados.
Puede reportar errores en su aplicación y evitar volver excepciones no controladas.

Se utiliza en dos lugares diferentes:

  1. sección ejecutable.
  2. sección de excepción.

Devuelve condiciones de error al usuario de una manera consistente con otros errores de Oracle Server

Sintaxis

  1. raise_application_error (error_number,
  2. message[, {TRUE | FALSE}]);

Ejemplo: utilizando en el BEGIN

  1. DECLARE
  2. v_edad NUMBER := 17;
  3. BEGIN
  4. IF v_edad > 18 THEN
  5. DBMS_OUTPUT.PUT_LINE('Bienvenid@');
  6. ELSE
  7. RAISE_APPLICATION_ERROR(-20001, 'Acceso denegado, debes ser mayor de edad'); -- excepcion de restriccion de edad
  8. END IF;
  9. END;
  10. /

Ejemplo: utilizando en el exception

  1. DECLARE
  2. v_edad NUMBER := 17;
  3. e_restriccion_edad_exception EXCEPTION;
  4. BEGIN
  5. IF v_edad > 18 THEN
  6. DBMS_OUTPUT.PUT_LINE('Bienvenid@');
  7. ELSE
  8. RAISE e_restriccion_edad_exception; -- activamos la excepcion de restriccion de edad
  9. END IF;
  10. EXCEPTION
  11. WHEN e_restriccion_edad_exception THEN
  12. RAISE_APPLICATION_ERROR(-20001, 'Acceso denegado, debes ser mayor de edad'); -- excepcion de restriccion de edad
  13. END;
  14. /

Nota: El parámetro final pasado al procedimiento es un Boolean(true/false) que indica al procedimiento que agregue este error a la pila de errores o reemplace todos los errores de la pila con este error. Pasar el valor de ‘True’ agrega el error a la pila actual, mientras que el valor predeterminado es ‘False’.

Procedimientos

Sintaxis

  1. CREATE [OR REPLACE] PROCEDURE procedure_name
  2. [(argument1 [mode1] datatype1,
  3. argument2 [mode2] datatype2,
  4. . . .)]
  5. IS|AS
  6. procedure_body;

Ejemplo

creamos procedimiento

  1. CREATE OR REPLACE PROCEDURE p_show_message
  2. (v_message varchar2) -- parametros
  3. IS
  4. v_message_date DATE := sysdate;
  5. BEGIN
  6. DBMS_OUTPUT.PUT_LINE('Message: '
  7. || v_message
  8. || ' Fecha: '
  9. || v_message_date);
  10. END;
  11. /

fin de creacion de procedimiento

invocamos procedimiento en un bloque anonimo y le pasamos por parametro

  1. BEGIN
  2. p_show_message('Este es un mensaje creado mediante un storage procedure ');
  3. END;
  1. Resultado:
  2. Procedure P_SHOW_MESSAGE compilado
  3. Message: Este es un mensaje creado mediante un storage procedure Fecha: 08/06/20
  4. Procedimiento PL/SQL terminado correctamente.

Funciones

SET SERVEROUTPUT ON;

Sintaxis:

  1. CREATE [OR REPLACE] FUNCTION function_name
  2. [(argument1 [mode1] datatype1,
  3. argument2 [mode2] datatype2,
  4. . . .)]
  5. RETURN datatype
  6. IS|AS
  7. function_body;

Ejemplo: Crearemos un funcion la cual permita calcular el ISSS de un empleado

  1. CREATE OR REPLACE FUNCTION calcular_isss
  2. (p_salary employees.salary%TYPE) --parametro
  3. RETURN employees.salary%TYPE -- return
  4. IS
  5. -- variables y/o constantes
  6. c_porcentaje_isss CONSTANT NUMBER(9,2) := 0.03;
  7. c_monto_maximo CONSTANT employees.salary%TYPE := 1000;
  8. v_monto_isss employees.salary%TYPE := 0;
  9. BEGIN
  10. IF p_salary IS NULL THEN
  11. RAISE_APPLICATION_ERROR(-20001, 'El salario no es valido, tiene valor null');
  12. ELSE
  13. IF p_salary > c_monto_maximo THEN
  14. v_monto_isss := c_monto_maximo*c_porcentaje_isss;
  15. ELSE
  16. v_monto_isss := p_salary*c_porcentaje_isss;
  17. END IF;
  18. END IF;
  19. RETURN v_monto_isss;
  20. END;
  21. /

Invocamos la funcion mediante el siguiente bloque anonimo

  1. BEGIN
  2. dbms_output.put_line('El calculo del ISSS es: $' || calcular_isss(100));
  3. END;