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
(Es crea la pàgina amb «==T8- Cursors explícits == *'''Exercici 1''' 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 matei…».)
 
 
(Hi ha 17 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.
  
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):
+
1) Ejecute el comando en el archivo lab_05_01.sql para volver a crear la tabla messages.
  
a. obtenir un numero "n" entrat per teclat per l'usuari amb un paràmetre de substitució.
+
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.
b. en un bucle, obtenir els cognoms  i sous d'aquests "n" empleats de la taula EMP
+
<pre>
*'''Exercici 1'''
 
 
 
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. comprova varis casos: n=0 i n>que el número màxim d'empleats.
 
 
 
f. buida la taula TOP_DOGS després de cada prova
 
 
 
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_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.
  
  --declarem un cursor que guardarà totes les dades de la taula empleats
+
'''Nota:''' no utilice cursores explícitos.
  CURSOR c_emp IS SELECT * FROM emp ORDER BY sal DESC;
+
<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
+
  SELECT last_name INTO v_ename
  FETCH c_emp INTO v_emp; --carreguem el valor de la primera fila en la variablle c_emp, el cursor se situa
+
  FROM employees
 
+
  WHERE salary = v_emp_sal;
                          --en el seguent registre
+
  INSERT INTO messages (results)
      
+
  VALUES (v_ename || ' - ' || v_emp_sal);
     FOR i IN 1..v_numemp LOOP --usem un bucle per repetir la càrrega tantes vegades com v_numemp
+
</pre>
        IF c_emp%NOTFOUND THEN EXIT; --condició de sortida del for, si c_emp està buida, el fetch no
+
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>''”.
 
+
<pre>
                                    --retorna cap valor
+
EXCEPTION
        END IF;
+
  WHEN no_data_found THEN
 
+
     INSERT INTO messages (results)
        INSERT INTO top_dogs VALUES (v_emp.ename,v_emp.sal); --inserim una nova fila amb el valors carregats
+
     VALUES ('No employee with a salary of '|| TO_CHAR(v_emp_sal));
        FETCH c_emp INTO v_emp; --fem que el cursor carregui de nou i passi al següent registre
+
</pre>
    END LOOP;
+
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>
    CLOSE c_emp;--tanquem el cursor, alliberem memòria
+
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;
 
END;
 
+
</pre>
 
+
7) Muestre las filas de la tabla messages para comprobar si el bloque PL/SQL se ha ejecutado correctamente.
*'''Exercici 2'''
+
<pre>
 
 
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;
 
 
/
 
/
 +
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
  open emp_cursor;
+
  FROM employees
 
+
  WHERE salary = v_emp_sal;
  FETCH emp_cursor INTO v_ename, v_salari_actual;
+
  INSERT INTO messages (results)
 
+
  VALUES (v_ename || ' - ' || v_emp_sal);
  WHILE (emp_cursor%ROWCOUNT <= v_num OR v_salari_actual=v_ultimo_salario) AND emp_cursor%FOUND LOOP
+
EXCEPTION
 
+
  WHEN no_data_found THEN
              INSERT INTO top_dogs(name, salary)
+
    INSERT INTO messages (results)
 
+
    VALUES ('No employee with a salary of '|| TO_CHAR(v_emp_sal));
              VALUES (v_ename,v_salari_actual);
+
  WHEN too_many_rows THEN
 
+
    INSERT INTO messages (results)
              v_ultimo_salario:=v_salari_actual;
+
    VALUES ('More than one employee with a salary of '|| TO_CHAR(v_emp_sal));
 
+
  WHEN others THEN
              FETCH emp_cursor INTO v_ename, v_salari_actual;
+
    INSERT INTO messages (results)
 
+
    VALUES ('Some other error occurred.');
  END LOOP;
 
 
 
  close emp_cursor;
 
 
 
COMMIT;
 
 
 
 
END;
 
END;
 +
/
 +
SELECT * FROM messages;
 +
</source>
  
c. guarda aquestes dades en la taula TOP_DOGS.
+
==Solución 8-2: Manejo de Excepciones de Oracle Server Estándar==
 
 
d. comprova varis casos: n=0 i n>que el número màxim d'empleats.
 
  
f. buida la taula TOP_DOGS després de cada prova
+
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.
  
SET SERVEROUTPUT ON;
+
1) En la sección de declaraciones, declare una excepción e_childrecord_exists.
SET VERIFY OFF;
+
Asocie la excepción declarada al error de Oracle Server estándar –02292.
ACCEPT num_emp PROMPT  'Introdueixi el número de empleats amb sou més alt:  '
+
<pre>
 +
SET SERVEROUTPUT ON
 
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
 
DECLARE
  v_numemp number(3) :=&num_emp;   
+
  e_childrecord_exists EXCEPTION;
  v_sal emp.sal%TYPE :=-1;
+
  PRAGMA EXCEPTION_INIT(e_childrecord_exists, -02292);
 
 
  CURSOR c_emp IS SELECT * FROM emp ORDER BY NVL(sal,0) DESC;
 
 
 
BEGIN
 
BEGIN
  DELETE FROM top_dogs; --buidem la taula top_dogs
+
  DBMS_OUTPUT.PUT_LINE(' Deleting department 40........');
  FOR v_emp IN c_emp LOOP
+
  delete from departments where department_id=40;
        DBMS_OUTPUT.PUT_LINE(v_numemp);   
+
EXCEPTION
        EXIT WHEN  (c_emp%ROWCOUNT > v_numemp AND v_sal<>v_emp.sal) OR (v_numemp=0);
+
  WHEN e_childrecord_exists THEN
        INSERT INTO top_dogs VALUES (v_emp.ename,v_emp.sal);   
+
  DBMS_OUTPUT.PUT_LINE(' Cannot delete this department. There are employees in this department (child records exist.) ');
          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
 
 
 
  v_num  NUMBER(3):= &p_num;
 
 
 
  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
 
 
 
  open emp_cursor;
 
 
 
  FETCH emp_cursor INTO v_ename, v_salari_actual;
 
 
 
  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;