16/04/ Sesión 11 Funciones y procedimientos Ing. Ricardo Inquilla
16/04/ Crear e invocar funciones propias con PL/SQL Crear e invocar procedimientos con PL/SQL
16/04/ Creación de funciones y procedimientos. Subprogramas locales. Programas almacenados y el diccionario de datos.
16/04/ Existen dos tipos principales de bloques PL/SQL, anónimos y nominados. Ejm: Funciones, procedimientos, paquetes y disparadores. Los bloques anónimos, que empiezan con DECLARE o BEGIN, se compilan cada vez que se ejecutan, no se almacenan en la base de datos y no pueden llamarse directamente desde otros bloques PL/SQL.
16/04/ Los procedimientos y funciones PL/SQL se comportan de forma muy parecida a los procedimientos y funciones de otros lenguajes de tercera generación, compartiendo muchas de sus propiedades. Los procedimientos y funciones también se conocen con el nombre de subprogramas.
16/04/ En primer lugar creamos el procedimiento con la instrucción CREATE OR REPLACE PROCEDURE En la llamada al procedimiento le pasamos un parámetro, en el caso del ejemplo es un mensaje. Un subprograma es un bloque PL/SQL con una sección declarativa, una sección ejecutable y una sección de tratamiento de errores, donde únicamente la sección ejecutable es obligatoria.
16/04/ Sintaxis : CREATE [OR REPLACE] PROCEDURE nombre_procedimiento [(argumento [IN|OUT |INOUT ] tipo.... [(argumento [IN|OUT |INOUT ] tipo) ] {IS |AS} Cuerpo_procedimiento;
16/04/ nombre_procedimiento : Es el nombre del procedimiento que se quiere crear. argumento : Es el nombre de un parámetro del procedimiento. tipo : Es el tipo del parámetro. cuerpo_procedimiento : Es un bloque PL/SQL que constituye el código del procedimiento.
16/04/ INOUT IN OUT Pasa un valor al subprograma Retorna un valor a quien invoca el subprograma Pasa un valor al subprograma y retorna el valor actualizado Puede ser una constante o variable Debe ser una variable
16/04/ CREATE OR REPLACE PROCEDURE imprime as as BEGIN dbms_output.put_line (‘Pocedimiento 2008’); END;/ Creación BEGIN imprime (); END; / Llamada al subprograma
16/04/ CREATE OR REPLACE PROCEDURE imprime ( mensaje in varchar2) as asBEGIN dbms_output.put_line (mensaje); dbms_output.put_line (mensaje);END;/ Creación BEGIN imprime (' Este es mi primer procedimiento '); END; / Llamada al subprograma
16/04/ CREATE TABLE tb_credito (credito_id varchar2(30), balance numeric(4,1)) Crear un procedimiento que incremente la columna balance, del codigo recibido como parametro, el monto a incrementar será recibido con otro parámetro
16/04/ create or replace procedure credito (codigo in varchar, monto in number) as begin update tb_credito set balance = balance + monto where credito_id = codigo; end; BEGIN credito (‘1‘,450); END; / Llamada al subprograma
16/04/ CREATE TABLE tb_credito (credito_id VARCHAR2(30), balance numeric(4,1))
16/04/ create or replace procedure Act_lista(credito varchar, monto numeric) as begin update tb_credito set balance = balance + monto where credito_Id = credito; end; declare cursor cs1 is select * from tb_credito; begin Act_lista ('001', '49'); for fila in cs1 loop dbms_output.put_line(fila.credito_id || '-' || fila.balance); end loop; end;
16/04/ create or replace procedure p_02 (id in varchar, b in numeric ) as begin update tb_credito set balance=balance + b where credito_id=id ; for x in (select credito_id,balance from tb_credito)loop dbms_output.put_line (x.credito_id || '-' || x.balance); end loop; end; / begin p_02('002',100); end; /
16/04/ Crear un procedimiento que utilizando 1 secuencia para el código inserte 1 registro en la tabla tb_credito y utilizando excepciones muestre un mensaje de error cuando duplique la llave primaria y otro mensaje para cualquier otro error.
16/04/ CREATE OR REPLACE PROCEDURE sp_inserta_depa (v_name in dept.dname%TYPE, v_local in dept.loc%TYPE) (v_name in dept.dname%TYPE, v_local in dept.loc%TYPE) IS IS v_nuevodeptno dept.deptno%TYPE; v_nuevodeptno dept.deptno%TYPE; BEGIN BEGIN SELECT seq_departament.NEXTVAL INTO v_nuevodeptno FROM DUAL; SELECT seq_departament.NEXTVAL INTO v_nuevodeptno FROM DUAL; INSERT INTO dept VALUES (v_nuevodeptno, v_name, v_local); INSERT INTO dept VALUES (v_nuevodeptno, v_name, v_local); COMMIT; COMMIT;EXCEPTION WHEN DUP_VAL_ON_INDEX THEN WHEN DUP_VAL_ON_INDEX THEN ROLLBACK; ROLLBACK; DBMS_OUTPUT.PUT_LINE('Ya existe un departamento con el código generado.'); DBMS_OUTPUT.PUT_LINE('Ya existe un departamento con el código generado.'); WHEN OTHERS THEN WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error Inesperado.' || SQLERRM); DBMS_OUTPUT.PUT_LINE('Error Inesperado.' || SQLERRM); END; END; Creando Procedimietno BEGIN sp_inserta_depa(‘Luis’,’Costa Norte’); END; Ejecutar Procedimietno CREATE SEQUENCE seq_emp INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE; CREATE SEQUENCE seq_emp INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE;
16/04/ CREATE OR REPLACE PROCEDURE sp_inserta_depa (v_name in dept.dname%TYPE, v_local in dept.loc%TYPE) (v_name in dept.dname%TYPE, v_local in dept.loc%TYPE) IS IS v_nuevodeptno dept.deptno%TYPE; v_nuevodeptno dept.deptno%TYPE; BEGIN BEGIN SELECT seq_departament.NEXTVAL INTO v_nuevodeptno FROM DUAL; SELECT seq_departament.NEXTVAL INTO v_nuevodeptno FROM DUAL; INSERT INTO dept VALUES (v_nuevodeptno, v_name, v_local); INSERT INTO dept VALUES (v_nuevodeptno, v_name, v_local); COMMIT; COMMIT;EXCEPTION WHEN DUP_VAL_ON_INDEX THEN WHEN DUP_VAL_ON_INDEX THEN ROLLBACK; ROLLBACK; DBMS_OUTPUT.PUT_LINE('Ya existe un departamento con el código generado.'); DBMS_OUTPUT.PUT_LINE('Ya existe un departamento con el código generado.'); WHEN OTHERS THEN WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error Inesperado.' || SQLERRM); DBMS_OUTPUT.PUT_LINE('Error Inesperado.' || SQLERRM); END; END; Creando Procedimietno BEGIN sp_inserta_depa(‘Luis’,’Costa Norte’); END; Ejecutar Procedimietno CREATE SEQUENCE seq_emp INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE; CREATE SEQUENCE seq_emp INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE;
16/04/ CREATE OR REPLACE PROCEDURE sp_inserta_dept_2 (p_name dept.dname%TYPE, p_local dept.loc%TYPE, p_nuevodeptno OUT dept.deptno%TYPE) IS BEGIN SELECT seq_dept.NEXTVAL INTO p_nuevodeptno FROM DUAL; INSERT INTO dept VALUES (p_nuevodeptno, p_name, p_local); COMMIT; EXCEPTION WHEN DUP_VAL_ON_INDEX THEN DBMS_OUTPUT.PUT_LINE('Ya existe un departamento con el código generado.'); p_nuevodeptno :=-1; WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error Inesperado.' || SQLERRM); p_nuevodeptno :=-1; END; / CREATE SEQUENCE seq_dept INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE; CREATE SEQUENCE seq_dept INCREMENT BY 1 START WITH 1 NOMAXVALUE NOCYCLE;
16/04/ DECLARE v_nombreDEPT.dname%TYPE:='RRHH'; v_localDEPT.loc%TYPE:='LINCE'; v_nuevocodigoDEPT.deptno%TYPE; BEGIN sp_inserta_dept_2('FINANZAS','LIMA',v_nuevocodigo); dbms_output.put_line('Nuevo Departamento: ' || v_nuevocodigo); sp_inserta_dept_2(v_nombre,v_local,v_nuevocodigo); dbms_output.put_line('Nuevo Departamento: ' || v_nuevocodigo); END; /
16/04/ Crear un procedimiento que muestre los tres primeros empleado(nombres) que tienen un salario superior a 2000.
16/04/ DECLARE PROCEDURE ENCONTRAR IS CURSOR C1 IS SELECT EMPNO,ENAME FROM EMP WHERE SAL>2000; REGISTRO C1%ROWTYPE; BEGIN OPEN C1; FETCH C1 INTO REGISTRO; IF C1 %ROWCOUNT=3 THEN DBMS_OUTPUT.PUT_LINE(REGISTRO.EMPNO || ' '||REGISTRO.ENAME); ELSE DBMS_OUTPUT.PUT_LINE('NO SE ENCONTRO'); END IF; CLOSE C1; END ENCONTRAR; / BEGIN ENCONTRAR; END;
16/04/ create or replace procedure sp_empleados2000 is begin DECLARE CURSOR todos2000 IS SELECT * FROM emp where sal>2000; mi_emp emp%ROWTYPE; BEGIN OPEN todos2000; LOOP FETCH todos2000 INTO mi_emp; /* Procesar sólamente los empleados de salario superior a 2000*/ EXIT WHEN todos2000%NOTFOUND or todos2000%ROWCOUNT > 3; DBMS_OUTPUT.PUT_LINE(mi_emp.empno ||' '|| mi_emp.ename ||' '|| mi_emp.sal ); END LOOP; CLOSE todos2000; END; end;
16/04/ Crear un procedimiento que liste todos los empleados que tienen un nombre de 5 letras.
16/04/ DECLARE PROCEDURE EJERCICIO_7_4 IS CURSOR C1 IS SELECT ENAME,JOB,SAL,DEPTNO FROM EMP WHERE LENGTH(ENAME)=&long; REGISTRO C1%ROWTYPE; BEGIN OPEN C1; LOOP FETCH C1 INTO REGISTRO; EXIT WHEN C1%NOTFOUND; DBMS_OUTPUT.PUT_LINE (REGISTRO.ENAME ||' '||REGISTRO.JOB ||' '||REGISTRO.SAL||' '||REGISTRO.DEPTNO); END LOOP; CLOSE C1; END EJERCICIO_7_4; BEGIN EJERCICIO_7_4; END; /
16/04/ Sintaxis : CREATE [OR REPLACE] FUNCTION nombre_función [(argumento [IN|OUT |INOUT ] tipo.... [(argumento [IN|OUT |INOUT ] tipo) ] RETURN tipo_retorno {IS |AS} Cuerpo_función;
16/04/ nombre_función : Es el nombre de la función que se quiere crear. argumento : Es el nombre de un parámetro de la función. tipo : Es el tipo del parámetro. tipo_retorno : Es el tipo del valor que devuelve la función. cuerpo_función : Es un bloque PL/SQL que constituye el código de la función.
16/04/ Utilizar la Tabla tb_credito Crear función que retorna monto(balance) CREATE or replace FUNCTION obtener_monto () RETURN NUMBER (monto_no IN NUMBER) RETURN NUMBERIS acc_bal NUMBER(11,2); BEGIN BEGIN SELECT balance INTO tb_credito WHERE credito_id = monto_no; SELECT balance INTO acc_bal FROM tb_credito WHERE credito_id = monto_no;RETURN(acc_bal);END; Ejecutar Función declare valor number(4); begin valor:=obtener_monto(2); dbms_output.put_line(valor); end; /
16/04/ CREATE OR REPLACE FUNCTION sf_can_empleado (p_dept dept.deptno%TYPE) RETURN NUMBER IS v_numero number(6); BEGIN SELECT count(1) INTO v_numero FROM emp WHERE deptno = p_dept; deptno = p_dept; RETURN v_numero; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error Inesperado.' ||SQLERRM); END; DECLARE Valor NUMBER(6); BEGIN Valor := sf_can_empleado(20); dbms_output.put_line(valor);END; Cantidad de empleados que pertenecen al departamento enviado como parámetro
16/04/ Dentro del cuerpo de una función, la instrucción RETURN, se utiliza para devolver el control, junto con un valor, al entorno que realizó la llamada. Sintaxis : RETURN expresión;
16/04/ Eliminación de procedimientos : DROP PROCEDURE nombre_procedimiento; Eliminación de funciones : DROP FUNCTION nombre_función;
16/04/ Subprogramas Locales
16/04/ Los subprogramas locales no crean un objeto en la base de datos, solo tienen vigencia durante la ejecución del programa o subprograma que los crea e invoca. Los subprogramas locales deben ser declarados al final de la sección declarativa.
16/04/ DECLARE CURSOR c_Emps IS SELECT ename, job FROM emp; v_salida_formateada VARCHAR2(50); -- Función que devolverá el nombre y job --concatenados y separados por espacio FUNCTION Formateador ( p_ename IN VARCHAR2, p_job IN VARCHAR2) RETURN p_ename||' '||p_job; END Formateador; -- Inicio del bloque principal BEGIN FOR v_emp_record IN c_Emps LOOP v_salida_formateada := Formateador(v_emp_record.ename,v_emp_record.en ame.job); DBMS_OUTPUT.PUT_LINE(v_salida_formateada); END LOOP; END;
16/04/ Programas almacenados y el diccionario de datos
16/04/ La vista del diccionario de datos que contiene el código de un procedimiento o de una función es la vista ALL_SOURCE.
16/04/ select * from user_objects where object_type = ‘PROCEDURE' Mostrar errores de procedimiento y funciones Errors show
16/04/ Mucha Gracias por tu atención.
16/04/ Crea un procedimiento que utilizando dos parámetro inserte 1 registro en la tabla crédito y muestre el ultimo monto insertado.
16/04/
16/04/ select * from user_objectswhere object_type = ‘PROCEDURE'