You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

421 lines
12 KiB
Markdown

---
title: "Práctica PL/SQL individual"
date: 2022-12-07T13:37:02+01:00
draft: false
image: featured.png
categories:
- documentación
- Administración de Bases de Datos
tags:
- Oracle
- PL/SQL
---
## Hacer un procedimiento que muestre el nombre y el salario del empleado cuyo código es 7782
```sql
CREATE OR REPLACE PROCEDURE mostrarnombresalario
is
v_nombre emp.ename%type;
v_salario emp.sal%type;
begin
select ename,sal into v_nombre,v_salario from emp where empno=7782;
dbms_output.put_line('El nombre del empleado es ' || v_nombre || ' y su salario es: ' || v_salario);
end;
/
```
![p1](https://i.imgur.com/CscMTfL.png)
## Hacer un procedimiento que reciba como parámetro un código de empleado y devuelva su nombre
```sql
CREATE OR REPLACE PROCEDURE mostrarnombresalario2 (p_empno emp.empno%TYPE)
is
v_nombre emp.ename%type;
v_salario emp.sal%type;
begin
select ename,sal into v_nombre,v_salario from emp where empno=p_empno;
dbms_output.put_line('El nombre del empleado es ' || v_nombre || ' y su salario es: ' || v_salario);
end;
/
```
![p2](https://i.imgur.com/o2tqMaP.png)
## Hacer un procedimiento que devuelva los nombres de los tres empleados más antiguos
```sql
CREATE OR REPLACE PROCEDURE topantiguos
is
cursor c_top is
select ename
from emp
order by hiredate asc
fetch first 3 rows only;
begin
dbms_output.put_line('Los 3 empleados mas antiguos son: ');
for v_empleado in c_top loop
dbms_output.put_line(v_empleado.ename);
end loop;
end;
/
```
![p3](https://i.imgur.com/FOSjg5a.png)
## Hacer un procedimiento que reciba el nombre de un tablespace y muestre los nombres de los usuarios que lo tienen como tablespace por defecto (Vista DBA_USERS)
```sql
CREATE OR REPLACE PROCEDURE verusuarios (p_tablespace dba_users.default_tablespace%type)
is
cursor c_usuarios is
SELECT username
from dba_users
where default_tablespace=p_tablespace;
begin
dbms_output.put_line('El tablespace ' || p_tablespace || ' es el predeterminado de los siguientes usuarios:');
for v_usuario in c_usuarios loop
dbms_output.put_line(v_usuario.username);
end loop;
end;
/
```
![p4](https://i.imgur.com/U3oRByX.png)
## Modificar el procedimiento anterior para que haga lo mismo pero devolviendo el número de usuarios que tienen ese tablespace como tablespace por defecto. Nota: Hay que convertir el procedimiento en función
```sql
CREATE OR REPLACE function f_numusuarios (p_tablespace dba_users.default_tablespace%type)
return number
is
v_num number;
begin
select count(username) into v_num from dba_users where default_tablespace=p_tablespace;
return v_num;
end;
/
```
## Hacer un procedimiento llamado mostrar_usuarios_por_tablespace que muestre por pantalla un listado de los tablespaces existentes con la lista de usuarios de cada uno y el número de los mismos, así: (Vistas DBA_TABLESPACES y DBA_USERS)
```sql
Tablespace xxxx:
Usr1
Usr2
...
Total Usuarios Tablespace xxxx: n1
Tablespace yyyy:
Usr1
Usr2
...
Total Usuarios Tablespace yyyy: n2
....
Total Usuarios BD: nn
```
He modificado el procedimiento del ejercicio 4:
```sql
CREATE OR REPLACE PROCEDURE verusuarios (p_tablespace dba_users.default_tablespace%type)
is
cursor c_usuarios is
SELECT username
from dba_users
where default_tablespace=p_tablespace;
begin
for v_usuario in c_usuarios loop
dbms_output.put_line(CHR(9)|| v_usuario.username);
end loop;
end;
/
```
Y el procedimiento nuevo es:
```sql
CREATE OR REPLACE PROCEDURE mostrar_usuarios_por_tablespace
is
cursor c_tablespaces is
SELECT tablespace_name
from dba_tablespaces;
v_total_usuario number;
v_total number:=0;
begin
for v_tablespace in c_tablespaces loop
dbms_output.put_line('Tablespace ' || v_tablespace.tablespace_name);
verusuarios(v_tablespace.tablespace_name);
v_total_usuario:=f_numusuarios(v_tablespace.tablespace_name);
v_total:=v_total+v_total_usuario;
dbms_output.put_line('Total Usuarios tablespace ' || v_tablespace.tablespace_name || ': ' || v_total_usuario);
end loop;
dbms_output.put_line('Total Usuarios BD : ' || v_total);
end;
/
```
![p5](https://i.imgur.com/1sCHBpU.png)
[...]
![p6](https://i.imgur.com/pbjFtsP.png)
## Hacer un procedimiento llamado mostrar_codigo_fuente que reciba el nombre de otro procedimiento y muestre su código fuente. (DBA_SOURCE)
```sql
CREATE OR REPLACE PROCEDURE mostrar_codigo_fuente (p_nombre dba_source.name%type)
is
cursor c_codigo is
SELECT text
from dba_source
where name=p_nombre;
begin
for v_codigo in c_codigo loop
dbms_output.put_line(v_codigo.text);
end loop;
end;
/
```
![p7](https://i.imgur.com/zx9BQyp.png)
## Hacer un procedimiento llamado mostrar_privilegios_usuario que reciba el nombre de un usuario y muestre sus privilegios de sistema y sus privilegios sobre objetos. (DBA_SYS_PRIVS y DBA_TAB_PRIVS)
```sql
CREATE OR REPLACE PROCEDURE mostrar_privilegios_usuario (p_nombre dba_source.name%type)
is
cursor c_sistema is
SELECT privilege
from dba_sys_privs
where grantee=p_nombre
and ADMIN_OPTION='YES'
OR INHERITED='YES';
cursor c_objetos is
SELECT privilege,table_name
from dba_tab_privs
where grantee=p_nombre;
begin
dbms_output.put_line('Privilegios del usuario '|| p_nombre || ' de sistema');
for v_sistema in c_sistema loop
dbms_output.put_line(CHR(9)||v_sistema.privilege);
end loop;
dbms_output.put_line('Privilegios del usuario '|| p_nombre || ' sobre objetos');
for v_objeto in c_objetos loop
dbms_output.put_line(CHR(9)||v_objeto.privilege || '---' || v_objeto.table_name);
end loop;
end;
/
```
![p8](https://i.imgur.com/V9bkArM.png)
## Realiza un procedimiento llamado listar_comisiones que nos muestre por pantalla un listado de las comisiones de los empleados agrupados según la localidad donde está ubicado su departamento con el siguiente formato:
```sql
Localidad NombreLocalidad
Departamento: NombreDepartamento
Empleado1 ……. Comisión 1
Empleado2 ……. Comisión 2
.
.
.
Empleadon ……. Comision n
Total Comisiones en el Departamento NombreDepartamento: SumaComisiones
Departamento: NombreDepartamento
Empleado1 ……. Comisión 1
Empleado2 ……. Comisión 2
.
.
.
Empleadon ……. Comision n
Total Comisiones en el Departamento NombreDepartamento: SumaComisiones
.
.
Total Comisiones en la Localidad NombreLocalidad: SumaComisionesLocalidad
Localidad NombreLocalidad
.
.
Total Comisiones en la Empresa: TotalComisiones
```
Nota: Los nombres de localidades, departamentos y empleados deben aparecer por orden alfabético.
Si alguno de los departamentos no tiene ningún empleado con comisiones, aparecerá un mensaje informando de ello en lugar de la lista de empleados.
El procedimiento debe gestionar adecuadamente las siguientes excepciones:
a) La tabla Empleados está vacía.
b) Alguna comisión es mayor que 10000.
He creado dos funciones y un procedimiento:
```sql
CREATE OR REPLACE FUNCTION listar_empleados(p_deptno dept.deptno%type)
return number
is
cursor c_empleados is
SELECT ename,comm
from emp
where deptno=p_deptno
order by ename;
v_vacio number;
v_suma number:=0;
v_valor number;
begin
select sum(comm) into v_vacio from emp where deptno=p_deptno;
if v_vacio>0 then
for v_empleado in c_empleados loop
IF v_empleado.comm is NULL THEN
v_valor:=0;
ELSE
v_suma:=v_suma+v_empleado.comm;
v_valor:=v_empleado.comm;
END IF;
dbms_output.put_line(CHR(9)||CHR(9)|| v_empleado.ename || ' ... ' || v_valor);
end loop;
else
dbms_output.put_line(CHR(9)||CHR(9)|| 'El departamento no tiene comisiones');
end if;
return v_suma;
EXCEPTION
WHEN NO_DATA_FOUND then
dbms_output.put_line('La tabla empleados está vacía');
return 0;
end;
/
CREATE OR REPLACE FUNCTION listar_departamentos(p_loc dept.loc%type)
return number
is
cursor c_departamentos is
SELECT dname,deptno
from dept
where loc=p_loc
order by dname;
v_total number;
v_suma number:=0;
begin
for v_departamento in c_departamentos loop
dbms_output.put_line(CHR(9)|| 'Departamento: ' || v_departamento.dname);
v_total:=listar_empleados(v_departamento.deptno);
dbms_output.put_line(CHR(9)|| 'Total Comisiones en el Departamento ' || v_departamento.dname || ': ' || v_total);
v_suma:=v_suma+v_total;
end loop;
return v_suma;
end;
/
CREATE OR REPLACE PROCEDURE listar_comisiones
is
cursor c_localidades is
SELECT loc
from dept
order by loc;
v_total number;
v_suma number:=0;
begin
for v_localidad in c_localidades loop
dbms_output.put_line('Localidad ' || v_localidad.loc);
v_total:=listar_departamentos(v_localidad.loc);
dbms_output.put_line('Total Comisiones en la Localidad ' || v_localidad.loc || ': ' || v_total);
v_suma:=v_suma+v_total;
end loop;
dbms_output.put_line('Total Comisiones de la Empresa ' || v_suma);
end;
/
```
![p9](https://i.imgur.com/DGWQS1b.png)
## . Realiza un procedimiento que reciba el nombre de una tabla y muestre los nombres de las restricciones que tiene, a qué columna afectan y en qué consisten exactamente. (DBA_TABLES, DBA_CONSTRAINTS, DBA_CONS_COLUMNS)
He realizado los siguientes procedimientos:
```sql
CREATE OR REPLACE PROCEDURE listar_restriccion(p_nombre user_constraints.table_name%type,p_tabla user_constraints.table_name%type)
is
v_tipo user_constraints.constraint_type%type;
v_nombre user_constraints.constraint_name%type;
v_referencia user_constraints.r_constraint_name%type;
v_condicion user_constraints.search_condition%type;
begin
select constraint_name,constraint_type,r_constraint_name,search_condition into v_nombre,v_tipo,v_referencia,v_condicion
from user_constraints
where table_name = p_tabla
and constraint_name=p_nombre;
if v_tipo='P' then
dbms_output.put_line(p_nombre || ' ... es de tipo CLAVE PRIMARIA');
elsif v_tipo='R' then
dbms_output.put_line(p_nombre || ' ... es de tipo CLAVE EXTERNA y hace referencia a: ' || v_nombre);
elsif v_tipo='C' then
dbms_output.put_line(p_nombre || ' ... es de tipo CHECK y contiene la siguiente comprobacion: ' || v_condicion);
end if;
end;
/
CREATE OR REPLACE PROCEDURE listar_restricciones(p_tabla user_constraints.table_name%type)
is
cursor c_columnas is
SELECT constraint_name,column_name
from user_cons_columns
where table_name=p_tabla;
begin
dbms_output.put_line('Restricciones de la tabla ' || p_tabla);
for v_columna in c_columnas loop
listar_restriccion(v_columna.constraint_name,p_tabla);
dbms_output.put_line(CHR(9)||'Hace referencia a la columna -> ' || v_columna.column_name);
end loop;
end;
/
```
En la comprobación introduzco una tabla diferente al esquema SCOTT ya que tiene más restricciones:
![p10](https://i.imgur.com/OMoSRQz.png)
## Realiza al menos dos de los ejercicios anteriores en Postgres usando PL/pgSQL.
## Ejercicio 1
```sql
CREATE or replace PROCEDURE mostrarnombresalario() AS $$
DECLARE
v_nombre emp.ename%type;
v_salario emp.sal%type;
BEGIN
select ename,sal into v_nombre,v_salario from emp where empno=7782;
RAISE NOTICE 'El nombre del empleado es %, y su salario es %', v_nombre,v_salario;
END;
$$ LANGUAGE plpgsql;
```
![p11](https://i.imgur.com/GifaOGt.png)
## Ejercicio 2
```sql
CREATE or replace PROCEDURE mostrarnombresalario2(p_empno emp.empno%type) AS $$
DECLARE
v_nombre emp.ename%type;
BEGIN
select ename into v_nombre from emp where empno=7782;
RAISE NOTICE 'El nombre del empleado cuyo codigo es %, es %', p_empno,v_nombre;
END;
$$ LANGUAGE plpgsql;
```
![p12](https://i.imgur.com/OKfLC2X.png)