Diferència entre revisions de la pàgina «M2 - Bases de dades / Exercicis UF3: Llenguatges SQL / Solucions PL-SQL T8»

De wikiserver
Dreceres ràpides: navegació, cerca
 
(Hi ha 13 revisions intermèdies del mateix usuari que no es mostren)
Línia 1: Línia 1:
==T8- Cursors explícits ==
+
==Solución 8-1: Manejo de Excepciones Predefinidas==
  
*'''Exercici 1'''
+
En esta práctica, escribirá un bloque PL/SQL que aplique una excepción predefinida para procesar un único registro a la vez. El bloque PL/SQL seleccionará el nombre del empleado con un valor de salario determinado.
  
Previ: buida la taula TOP_DOGS.
+
1) Ejecute el comando en el archivo lab_05_01.sql para volver a crear la tabla messages.
  
::SQL> DELETE
+
2) En la sección de declaraciones, declare dos variables: v_ename del tipo employees.last_name y v_emp_sal del tipo employees.salary.
:: 2   FROM TOP_DOGS;
+
Inicialice la última en 6000.
 
+
<pre>
Crea un bloc pl/sql que determini els n empleats amb sous més alts (suposeu que no hi ha dos empleats o més amb el mateix sou):
 
 
 
a. obtenir un numero "n" entrat per teclat per l'usuari amb un paràmetre de substitució.
 
 
 
b. en un bucle, obtenir els cognoms  i sous d'aquests "n" empleats de la taula EMP
 
 
 
c. guarda aquestes dades en la taula TOP_DOGS.
 
 
 
d. Suposa que no hi ha dos empleats amb al mateix sou.
 
 
 
e. comprova varis casos: n=0 i n més gran que el número màxim d'empleats.
 
 
 
 
 
::SET SERVEROUTPUT ON;
 
 
 
::SET VERIFY OFF;
 
 
 
::ACCEPT p_num PROMPT  'Introdueixi el número de empleats amb sou més alt:  '
 
 
 
::DECLARE
 
 
 
:::v_num NUMBER(3) :=&p_num;
 
 
 
:::v_ename emp.ename%TYPE;
 
 
 
:::v_sal emp.sal%TYPE;   
 
 
 
:::--declarem un cursor que guardarà totes les dades de la taula empleats
 
:::CURSOR emp_cursor IS
 
::::SELECT ename, sal
 
::::FROM emp
 
::::WHERE sal IS NOT NULL
 
::::ORDER BY sal DESC;
 
 
 
::BEGIN
 
 
 
:::OPEN emp_cursor; --obrim el cursor, aquest es posiciona apuntant el primer registre del cursor
 
 
 
:::FETCH emp_cursor INTO v_ename, v_sal; --carreguem el valor de la primera fila en les variables v_ename i v_sal, el cursor se situa en el següent registre
 
 
 
:::WHILE emp.cursor%ROWCOUNT <= v_num AND emp_curosr%FOUND LOOP -- mentre recuperem menys registres dels demanats i quedin registres
 
   
 
::::INSERT INTO top_dogs VALUES (v_ename,v_sal); --inserim una nova fila amb el valors carregats
 
       
 
::::FETCH emp_cursor INTO v_ename, v_sal; --fem que el cursor carregui de nou i passi al següent registre
 
   
 
:::END LOOP;
 
   
 
:::CLOSE emp_cursor;--tanquem el cursor, alliberem memòria
 
 
 
:::COMMIT;
 
 
 
::END;
 
 
 
::/
 
 
 
::SQL> SELECT *
 
:: 2  FROM TOP_DOGS;
 
 
 
 
 
*'''Exercici 2'''
 
 
 
Considera el cas de que varis empleats tinguin el mateix salari. Al igual que l'exercici anterior crea un bloc pl/sql que determini els n empleats amb sous més alts, però en aquest cas si se cal mostrar totes les persones que tinguin un mateix sou.
 
 
 
a. Si l'usuari introdueix n=2 han d'aparèixer tres registres (king, ford i scott, aquest últims tenen el mateix sou.
 
 
 
b. Si l'usuari introdueix n=3 han d'aparèixer 4 registres (king, ford i scott i jones).
 
 
 
c. Buida totes les files de la taula TOP_DOGS abans de prova l'exercici.
 
 
 
 
 
SET SERVEROUTPUT ON;
 
SET VERIFY OFF;
 
ACCEPT num_emp PROMPT  'Introdueixi el número de empleats amb sou més alt:  '
 
 
DECLARE
 
DECLARE
  v_numemp number(3) :=&num_emp;  
+
  v_ename employees.last_name%TYPE;
  v_sal emp.sal%TYPE :=-1;
+
  v_emp_sal employees.salary%TYPE := 6000;
 +
</pre>
 +
3) En la sección ejecutable, recupere los apellidos de los empleados cuyos salarios son iguales al valor de v_emp_sal. Si el salario introducido devuelve sólo una fila, inserte en la tabla messages el nombre y el importe del salario del empleado.
  
  CURSOR c_emp IS SELECT * FROM emp ORDER BY NVL(sal,0) DESC;
+
'''Nota:''' no utilice cursores explícitos.
+
<pre>
 
BEGIN
 
BEGIN
  DELETE FROM top_dogs; --buidem la taula top_dogs
+
  SELECT last_name INTO v_ename
  FOR v_emp IN c_emp LOOP
+
  FROM employees
        DBMS_OUTPUT.PUT_LINE(v_numemp);  
+
  WHERE salary = v_emp_sal;
        EXIT WHEN  (c_emp%ROWCOUNT > v_numemp AND v_sal<>v_emp.sal) OR (v_numemp=0);
+
  INSERT INTO messages (results)
        INSERT INTO top_dogs VALUES (v_emp.ename,v_emp.sal);  
+
  VALUES (v_ename || ' - ' || v_emp_sal);
          IF (v_sal=v_emp.sal) THEN v_numemp:=v_numemp+1;
+
</pre>
            ELSE  v_sal:=v_emp.sal;
+
4) Si el salario introducido no devuelve ninguna fila, maneje la excepción con un manejador de excepciones adecuado e inserte en la tabla messages el mensaje “No employee with a salary of ''<salary>''”.
          END IF;
+
<pre>
    END LOOP;
+
EXCEPTION
END;
+
  WHEN no_data_found THEN
 +
    INSERT INTO messages (results)
 +
    VALUES ('No employee with a salary of '|| TO_CHAR(v_emp_sal));
 +
</pre>
 +
5) Si el salario introducido devuelve varias filas, maneje la excepción con un manejador de excepciones adecuado e inserte en la tabla messages el mensaje “More than one employee with a salary of ''<salary>''”.
 +
<pre>
 +
WHEN too_many_rows THEN
 +
  INSERT INTO messages (results)
 +
  VALUES ('More than one employee with a salary of '|| TO_CHAR(v_emp_sal));
 +
</pre>
 +
6) Maneje cualquier otra excepción con un manejador de excepciones adecuado e inserte en la tabla messages el mensaje “Some other error occurred”.
 +
<pre>
 +
WHEN others THEN
 +
  INSERT INTO messages (results)
 +
  VALUES ('Some other error occurred.');
 +
END;
 +
</pre>
 +
7) Muestre las filas de la tabla messages para comprobar si el bloque PL/SQL se ha ejecutado correctamente.
 +
<pre>
 
/
 
/
 +
SELECT * FROM messages;
 +
</pre>
 +
La salida es la siguiente:
 +
[[Imatge:M2UF3_MEP_1.png |400px|center| Manejo de Excepciones Predefinidas]]
  
--------------------------------------------------------------------------------------------------
+
8) Cambie el valor inicializado de v_emp_sal a 2000 y vuelva a ejecutar. La salida es la siguiente:
 
+
[[Imatge:M2UF3_MEP_2.png |400px|center| Manejo de Excepciones Predefinidas]]
--Versión 2 de este ejericio
 
 
 
ACCEPT p_num PROMPT 'introduce el máximo numero de sueldos distintos: '
 
  
 +
<source lang="java">
 
DECLARE
 
DECLARE
 
+
  v_ename employees.last_name%TYPE;
  v_num  NUMBER(3):= &p_num;
+
  v_emp_sal employees.salary%TYPE := 6000;
 
 
  v_ename emp.ename%TYPE;
 
 
 
  v_salari_actual  emp.sal%TYPE;
 
 
 
  v_ultimo_salario  emp.sal%TYPE:= 1;
 
 
 
  CURSOR  emp_cursor IS  SELECT ename, sal FROM emp WHERE sal IS NOT NULL ORDER BY sal DESC;
 
 
 
 
BEGIN
 
BEGIN
 +
  SELECT last_name INTO v_ename
 +
  FROM employees
 +
  WHERE salary = v_emp_sal;
 +
  INSERT INTO messages (results)
 +
  VALUES (v_ename || ' - ' || v_emp_sal);
 +
EXCEPTION
 +
  WHEN no_data_found THEN
 +
    INSERT INTO messages (results)
 +
    VALUES ('No employee with a salary of '|| TO_CHAR(v_emp_sal));
 +
  WHEN too_many_rows THEN
 +
    INSERT INTO messages (results)
 +
    VALUES ('More than one employee with a salary of '|| TO_CHAR(v_emp_sal));
 +
  WHEN others THEN
 +
    INSERT INTO messages (results)
 +
    VALUES ('Some other error occurred.');
 +
END;
 +
/
 +
SELECT * FROM messages;
 +
</source>
  
  open emp_cursor;
+
==Solución 8-2: Manejo de Excepciones de Oracle Server Estándar==
  
  FETCH emp_cursor INTO v_ename, v_salari_actual;
+
En esta práctica, escribirá un bloque PL/SQL que declare una excepción para el error de Oracle Server ORA-02292 (integrity constraint violated – child record found). El bloque comprobará la excepción y mostrará el mensaje de error.
  
  WHILE (emp_cursor%ROWCOUNT <= v_num OR v_salari_actual=v_ultimo_salario) AND emp_cursor%FOUND LOOP
+
1) En la sección de declaraciones, declare una excepción e_childrecord_exists.
 
+
Asocie la excepción declarada al error de Oracle Server estándar –02292.
              INSERT INTO top_dogs(name, salary)
+
<pre>
 
+
SET SERVEROUTPUT ON
              VALUES (v_ename,v_salari_actual);
 
 
 
              v_ultimo_salario:=v_salari_actual;
 
 
 
              FETCH emp_cursor INTO v_ename, v_salari_actual;
 
 
 
  END LOOP;
 
 
 
  close emp_cursor;
 
 
 
COMMIT;
 
 
 
END;
 
 
 
 
 
SET SERVEROUTPUT ON;
 
SET VERIFY OFF;
 
ACCEPT num_emp PROMPT  'Introdueixi el número de empleats amb sou més alt:  '
 
 
DECLARE
 
DECLARE
  v_numemp number(3) :=&num_emp;  
+
  e_childrecord_exists EXCEPTION;
 
+
  PRAGMA EXCEPTION_INIT(e_childrecord_exists, -02292);
  --declarem un cursor que guardarà totes les dades de la taula empleats
+
</pre>
  CURSOR c_emp IS SELECT * FROM emp ORDER BY sal DESC;
+
2) En la sección ejecutable, muestre “Deleting department 40....” Incluya una sentencia DELETE para suprimir el departamento con department_id 40.
 
+
<pre>
  --declarem una variable registre capaç de guardar totes les dades de una fila del cursor anterior
 
 
 
  v_emp c_emp%ROWTYPE;
 
 
 
BEGIN
 
BEGIN
  OPEN c_emp; --obrim el cursor, aquest es posiciona apuntant el primer registre del cursor
+
  DBMS_OUTPUT.PUT_LINE(' Deleting department 40........');
  FETCH c_emp INTO v_emp; --carreguem el valor de la primera fila en la variablle c_emp, el cursor se situa
+
  delete from departments where department_id=40;
 
+
</pre>
                          --en el seguent registre
+
3) Incluya una sección de excepciones para manejar la excepción e_childrecord_exists y muestre el mensaje adecuado.
   
+
<pre>
    FOR i IN 1..v_numemp LOOP --usem un bucle per repetir la càrrega tantes vegades com v_numemp
+
EXCEPTION
        IF c_emp%NOTFOUND THEN EXIT; --condició de sortida del for, si c_emp està buida, el fetch no
+
  WHEN e_childrecord_exists THEN
 
+
  DBMS_OUTPUT.PUT_LINE(' Cannot delete this department. There are employees in this department (child records exist.) ');
                                    --retorna cap valor
 
        END IF;
 
 
 
        INSERT INTO top_dogs VALUES (v_emp.ename,v_emp.sal); --inserim una nova fila amb el valors carregats
 
        FETCH c_emp INTO v_emp; --fem que el cursor carregui de nou i passi al següent registre
 
    END LOOP;
 
   
 
    CLOSE c_emp;--tanquem el cursor, alliberem memòria
 
 
 
 
END;
 
END;
 +
</pre>
 +
La salida de ejemplo es la siguiente:
 +
[[Imatge:M2UF3_MEP_3.png |600px|center| Manejo de Excepciones Estándar]]
  
 
+
<source lang="java">
*'''Exercici 2'''
+
SET SERVEROUTPUT ON
 
 
Considere el caso de que varios empleados tengan el mismo salario. Al igual que el ejercicio anterior cree un bloque plsql que determine los n empleados con sueldos mas altos pero en este caso si se muestra una persona con el mismo sueldo se tendran que mostrar todos los que tengan este sueldo.
 
 
 
a) Si el usuario introduce n=2 deben aparecer tres registros (king, ford i scott, estos últimos tienen el mismo sueldo.
 
 
 
b) Si el usuario introduce n=3 deben aparecer 4 registros (king, ford i scott i jones)
 
 
 
c) vacía todas la filas de la tabla TOP_DOGS antes de probar  el ejercicio.
 
 
 
 
 
SET SERVEROUTPUT ON;
 
SET VERIFY OFF;
 
ACCEPT num_emp PROMPT  'Introdueixi el número de empleats amb sou més alt:  '
 
DECLARE
 
  v_numemp number(3) :=&num_emp;   
 
  v_sal emp.sal%TYPE :=-1;
 
 
 
  CURSOR c_emp IS SELECT * FROM emp ORDER BY NVL(sal,0) DESC;
 
 
BEGIN
 
  DELETE FROM top_dogs; --buidem la taula top_dogs
 
  FOR v_emp IN c_emp LOOP
 
        DBMS_OUTPUT.PUT_LINE(v_numemp);   
 
        EXIT WHEN  (c_emp%ROWCOUNT > v_numemp AND v_sal<>v_emp.sal) OR (v_numemp=0);
 
        INSERT INTO top_dogs VALUES (v_emp.ename,v_emp.sal);   
 
          IF (v_sal=v_emp.sal) THEN v_numemp:=v_numemp+1;
 
            ELSE  v_sal:=v_emp.sal;
 
          END IF;
 
    END LOOP;
 
END;
 
/
 
 
 
--------------------------------------------------------------------------------------------------
 
 
 
--Versión 2 de este ejericio
 
 
 
ACCEPT p_num PROMPT 'introduce el máximo numero de sueldos distintos: '
 
 
 
 
DECLARE
 
DECLARE
 
+
  e_childrecord_exists EXCEPTION;
  v_num  NUMBER(3):= &p_num;
+
  PRAGMA EXCEPTION_INIT(e_childrecord_exists, -02292);
 
 
  v_ename  emp.ename%TYPE;
 
 
 
  v_salari_actual  emp.sal%TYPE;
 
 
 
  v_ultimo_salario  emp.sal%TYPE:= 1;
 
 
 
  CURSOR  emp_cursor IS  SELECT ename, sal FROM emp WHERE sal IS NOT NULL ORDER BY sal DESC;
 
 
 
 
BEGIN
 
BEGIN
 
+
  DBMS_OUTPUT.PUT_LINE(' Deleting department 40........');
  open emp_cursor;
+
  delete from departments where department_id=40;
 
+
EXCEPTION
  FETCH emp_cursor INTO v_ename, v_salari_actual;
+
  WHEN e_childrecord_exists THEN
 
+
  DBMS_OUTPUT.PUT_LINE(' Cannot delete this department. There are employees in this department (child records exist.) ');
  WHILE (emp_cursor%ROWCOUNT <= v_num OR v_salari_actual=v_ultimo_salario) AND emp_cursor%FOUND LOOP
 
 
 
              INSERT INTO top_dogs(name, salary)
 
 
 
              VALUES (v_ename,v_salari_actual);
 
 
 
              v_ultimo_salario:=v_salari_actual;
 
 
 
              FETCH emp_cursor INTO v_ename, v_salari_actual;
 
 
 
  END LOOP;
 
 
 
  close emp_cursor;
 
 
 
COMMIT;
 
 
 
 
END;
 
END;
 +
</source>

Revisió de 16:13, 19 març 2018

Solución 8-1: Manejo de Excepciones Predefinidas

En esta práctica, escribirá un bloque PL/SQL que aplique una excepción predefinida para procesar un único registro a la vez. El bloque PL/SQL seleccionará el nombre del empleado con un valor de salario determinado.

1) Ejecute el comando en el archivo lab_05_01.sql para volver a crear la tabla messages.

2) En la sección de declaraciones, declare dos variables: v_ename del tipo employees.last_name y v_emp_sal del tipo employees.salary. Inicialice la última en 6000.

DECLARE
  v_ename employees.last_name%TYPE;
  v_emp_sal employees.salary%TYPE := 6000;

3) En la sección ejecutable, recupere los apellidos de los empleados cuyos salarios son iguales al valor de v_emp_sal. Si el salario introducido devuelve sólo una fila, inserte en la tabla messages el nombre y el importe del salario del empleado.

Nota: no utilice cursores explícitos.

BEGIN
  SELECT last_name INTO v_ename
  FROM employees
  WHERE salary = v_emp_sal;
  INSERT INTO messages (results)
  VALUES (v_ename || ' - ' || v_emp_sal);

4) Si el salario introducido no devuelve ninguna fila, maneje la excepción con un manejador de excepciones adecuado e inserte en la tabla messages el mensaje “No employee with a salary of <salary>”.

EXCEPTION
  WHEN no_data_found THEN
    INSERT INTO messages (results)
    VALUES ('No employee with a salary of '|| TO_CHAR(v_emp_sal));

5) Si el salario introducido devuelve varias filas, maneje la excepción con un manejador de excepciones adecuado e inserte en la tabla messages el mensaje “More than one employee with a salary of <salary>”.

WHEN too_many_rows THEN
  INSERT INTO messages (results)
  VALUES ('More than one employee with a salary of '|| TO_CHAR(v_emp_sal));

6) Maneje cualquier otra excepción con un manejador de excepciones adecuado e inserte en la tabla messages el mensaje “Some other error occurred”.

WHEN others THEN
  INSERT INTO messages (results)
  VALUES ('Some other error occurred.');
END;

7) Muestre las filas de la tabla messages para comprobar si el bloque PL/SQL se ha ejecutado correctamente.

/
SELECT * FROM messages;

La salida es la siguiente:

Manejo de Excepciones Predefinidas

8) Cambie el valor inicializado de v_emp_sal a 2000 y vuelva a ejecutar. La salida es la siguiente:

Manejo de Excepciones Predefinidas
DECLARE
  v_ename employees.last_name%TYPE;
  v_emp_sal employees.salary%TYPE := 6000;
BEGIN
  SELECT last_name INTO v_ename
  FROM employees
  WHERE salary = v_emp_sal;
  INSERT INTO messages (results)
  VALUES (v_ename || ' - ' || v_emp_sal);
EXCEPTION
  WHEN no_data_found THEN
    INSERT INTO messages (results)
    VALUES ('No employee with a salary of '|| TO_CHAR(v_emp_sal));
  WHEN too_many_rows THEN
    INSERT INTO messages (results)
    VALUES ('More than one employee with a salary of '|| TO_CHAR(v_emp_sal));
  WHEN others THEN
    INSERT INTO messages (results)
    VALUES ('Some other error occurred.');
END;
/
SELECT * FROM messages;

Solución 8-2: Manejo de Excepciones de Oracle Server Estándar

En esta práctica, escribirá un bloque PL/SQL que declare una excepción para el error de Oracle Server ORA-02292 (integrity constraint violated – child record found). El bloque comprobará la excepción y mostrará el mensaje de error.

1) En la sección de declaraciones, declare una excepción e_childrecord_exists. Asocie la excepción declarada al error de Oracle Server estándar –02292.

SET SERVEROUTPUT ON
DECLARE
  e_childrecord_exists EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_childrecord_exists, -02292);

2) En la sección ejecutable, muestre “Deleting department 40....” Incluya una sentencia DELETE para suprimir el departamento con department_id 40.

BEGIN
  DBMS_OUTPUT.PUT_LINE(' Deleting department 40........');
  delete from departments where department_id=40;

3) Incluya una sección de excepciones para manejar la excepción e_childrecord_exists y muestre el mensaje adecuado.

EXCEPTION
  WHEN e_childrecord_exists THEN
  DBMS_OUTPUT.PUT_LINE(' Cannot delete this department. There are employees in this department (child records exist.) ');
END;

La salida de ejemplo es la siguiente:

Manejo de Excepciones Estándar
SET SERVEROUTPUT ON
DECLARE
  e_childrecord_exists EXCEPTION;
  PRAGMA EXCEPTION_INIT(e_childrecord_exists, -02292);
BEGIN
  DBMS_OUTPUT.PUT_LINE(' Deleting department 40........');
  delete from departments where department_id=40;
EXCEPTION
  WHEN e_childrecord_exists THEN
  DBMS_OUTPUT.PUT_LINE(' Cannot delete this department. There are employees in this department (child records exist.) ');
END;