Tutorial de SQL
Tutorial de SQL
Tutorial de SQL
Algunas caracteristicas:
SQL: Structured query language.
Permite la comunicación con el sistema gestor de base de datos.
En su uso se puede especificar que quiere el usuario.
Permite hacer consulta de datos.
Tipos de datos:
CHAR:
Tienen una longitud fija.
Almacena de 1 a 255.
Si se introduce una cadena de menos longitud que la definida se rellenara con blancos a
la derecha hasta quedar completada.
Si se introduce una cadena de mayor longitud que la fijada nos dará un error.
VARCHAR:
Almacena cadenas de longitud variable.
La longitud máxima es de 2000 caracteres.
Si se introduce una cadena de menor longitud que la que esta definida, se almacena con
esa longitud y no se rellenara con blancos ni con ningún otro carácter a la derecha hasta
completar la longitud definida.
Si se introduce una cadena de mayor longitud que la fijada, nos dará un error
NUMBER:
Se almacenan tanto enteros como decimales.
Number (precisión, escala)
Ejemplo:
X=number (7,2)
X=155'862 à Error ya que solo puede tomar 2 decimales
X= 155'86 à Bien
Nota: El rango máximo va de 1 a 38.
LONG:
No almacena números de gran tamaño, sino cadenas de caracteres de hasta 2 GB
DATE:
Almacena la fecha. Se almacena de la siguiente forma:
Siglo/Año/Mes/Día/Hora/Minutos/Segundos
RAW:
Almacena cadenas de Bytes (gráficos, sonidos…)
LONGRAW:
Como el anterior pero con mayor capacidad.
ROWID:
Posición interna de cada una de las columnas de las tablas.
Sentencias de consultas de datos
Select:
Select [ALL | Distinct] [expresión_columna1, expresión_columna2, …., | *]
From [nombre1, nombre_tabla1, …, nombre_tablan]
{[Where condición]
[Order By expresión_columna [Desc | Asc]…]};
Vamos a explicar como leer la consulta anterior y así seguir la pauta para todas las
demás. Cuando ponemos [] significa que debemos la que va dentro debe existir, y si
además ponemos | significa que deberemos elegir un valor de los que ponemos y no mas
de uno. En cambio si ponemos {} significa que lo que va dentro de las llaves puede ir o
no, es decir es opcional y se pondrá según la consulta.
Nota: En el select el valor por defecto entre ALL y DISTINCT es ALL.
Alias = El nuevo nombre que se le da a una tabla. Se pondrá entre comillas
Order By = Ordena ascendentemente (Asc) (valor por defecto) o descendentemente
(Desc).
All = Recupera todas las filas de la tabla aunque estén repetidas.
Distinct = Solo recupera las filas que son distintas.
Desc Emple; = Nos da un resumen de la tabla y sus columnas. En este caso de la tabla
Emple.
Not Null= Si aparece en una lista de una columna significa que la columna no puede
tener valores nulos.
Null= Si está nulo.
Nota: Nótese que cada consulta de SQL que hagamos hemos de terminarla con un punto
y coma ";".
Con esto instalado ya podemos comenzar a explicar el SQL *Plus y sus múltiples
opciones.
Antes de comenzar os comento que necesitaremos una serie de tablas para ir haciendo
ejercicios y os aconsejaría que os creéis algunos usuarios más con distintos privilegios
para ir repasando lo que hemos comentado de la seguridad en Oracle . Esto lo podéis
hacer de forma visual o por linea de comando desde la pagina inicial de tu base de
datos.
Recurso Descripción
El número de sesiones concurrentes que un
SESSION_PER_USER
usuario puede tener en una instancia.
El tiempo de CPU, en centenas de segundos, que
CPU_PER_SESSION
una sesión puede utilizar.
El número de minutos que una sesión puede
CONNECT_TIME
permanecer activa.
El número de minutos que una sesión puede
IDLE_TIME
permanecer sin que sea utilizada de manera activa.
El número de bloques de datos que se pueden leer
LOGICAL_READS_PER_SESSION
en una sesión.
El número de bloques de datos que se pueden leer
LOGICAL_READS_PER_CALL
en una operación.
La cantidad de espacio privado que una sesión
PRIVATE_SGA puede reservar en la zona de SQL compartido de
la SGA.
El número de total de recursos por sesión, en
unidades de servicio. Esto resulta de un calculo
ponderado de CPU_PER_SESSION,
COMPOSITE_LIMIT CONNECT_TIME,
LOGICAL_READS_PER_SESSION y
PRIVATE_SGA, cuyos pesos se pueden variar con
el comando ALTER RESOURCE COST.
La sintaxis para la creación de un perfil con varias limitaciones seria:
create profile nombre_perfil limit
{Entero [K|M] | unlimited | default};
Donde unlimited significa que no hay limite sobre un recurso particular y default
significa que coge el limite del perfil DEFAULT
Para activar los perfiles el administrador debe ejecutar la siguiente orden:
alter system set resource_limit=true;
Para borrar un perfil tenemos que ejecutar la siguiente orden:
drop profile nombre_perfil [cascade];
Es importante saber si este perfil esta asignado a algún usuario ya que, si es así,
tendremos que poner "cascade", para que lo elimine de esos usuarios también.
Otro factor importante en la seguridad a nivel de sistema es la gestión de tablespaces.
Un tablespace es un espacio de la base de datos que contiene tablas o como su
definición oficial nos dice, es una unidad lógica de almacenamiento de datos compuesta
por uno o más archivos. En Oracle antes de introducir los datos en la base de datos
tenemos que crear un tablespace para que nos deje trabajar.
Es importante tener un tablespace para cada tipo de datos es decir, un tablespace para
cada aplicación.
La sintaxis de la creación de un tablespace es la siguiente:
create tablespace nombre_tablespace
datafile 'nombre_Archivo' [size entero [K|M]] [reuse]
[autoextend {off|on clausulas}]
[,'nombre_archivo' [size entero [K|M]] [reuse]
[autoextend {off|on clausulas}] ] ...
[ default storage {
initial tamaño
next tamaño
minextents tamaño
maxextents tamaño
pctincrease valor }] [online|offline];
Donde:
datafile: especifica el archivo/s de datos que constara el tablespace
size: especifica el tamaño del tablesapce
reuse: si el archivo ya existe lo reutiliza y sino lo crea.
Dafault storage: define el almacenamiento por defecto para todos los objectos que se
creen en ese tablespace
initial: indica la extensión inicial del tablespace
next: indica la extensión siguiente
minextents: reserva extensiones adicionales a la extensión inicial y nos permite asignar
gran cantidad de espacio cuando se crea un objeto. El valor por defecto es 1
maxextents: es el número máximo de extensiones que se le asigna a un objecto
pctincrease: factor de crecimiento para la extensión. Valor por defecto 50
offline|online: nos indica si el tablespace esta operativo o no, después de su creación
Por defecto Oracle crea los siguientes tablespace:
system: donde Oracle almacena toda la información para su propia gestión
users: espacio de tablas donde se almacena la información personal de los usuarios
temporary o temp: donde Oracle almacena las tablas temporales
tools: espacio para hacer pruebas sobre la base de datos
RBS: donde Oracle guarda la información al deshacer algún cambio.
Para modificar un tablespace cambiamos el create por el alter mientras que para borrarlo
basta con hacer drop tablespace nombre_tablespace;
Con la orden:
Se visualizan los objetos del diccionario de datos a los que se puede acceder.
Creación deusuarios:
Modificación de usuarios:
Borrado de usuarios:
Commit:
Cuando ejecutamos ordenes estas no son creadas en la tabla hasta que ponemos este
orden, por tanto los cambios realizados se perderán si al salir del programa no
realizamos esta acción. Puede programarse para que lo haga automáticamente.
Su primer carácter debe ser alfabético y el resto pueden ser letras, números y el carácter
subrayado.
Características:
Las definiciones individuales de columnas se separan mediante comas.
No se pone coma después de la última definición de columna.
Las mayúsculas y minúsculas son indiferentes.
Los usuarios pueden consultar las tablas creadas por medio de la vista USER_TABLES.
Integridad de datos:
La integridad hace referencia al hecho de que los datos de la base de datos han de
ajustarse a restricciones antes de almacenarse en ella. Una restricción de integridad será:
Una regla que restringe el rango de valores para una o más columnas en la tabla.
Usamos la cláusula CONSTRAINT, que puede restringir una sola columna o un grupo
de columnas de una misma tabla.
Hay dos modos de especificar restricciones:
Como parte de la definición de columnas.
Al final, una vez especificados todas las columnas.
Formato:
)[TABLESPACE ESPACIO_DE_TABLA];
Esta formada por una o varias columnas que están asociadas a una clave primaria de
otra o de la misma tabla. Se pueden definir tantas claves ajenas como se precise, y
pueden estar o no en la misma tabla que la clave primaria. El valor de la columna o
columnas que son claves ajenas debe ser: NULL o igual a un valor de la clave
referenciada (regla de integridad referencial).
Notas:
En la cláusula REFERENCES indicamos la tabla a la cual remite la clave ajena.
Hay que crear primero una tabla y después aquella que le hace referencia.
Hay que borrar primero la tabla que hace referencia a otra tabla y después la tabla que
no hace referencia.
Borrado en cascada (ON DELETE CASCADE): Si borramos una fila de una tabla
maestra, todas las filas de la tabla detalle cuya clave ajena sea referenciada se borraran
automáticamente. La restricción se declara en la tabla detalle. El mensaje "n filas
borradas" solo indica las filas borradas de la tabla maestra.
NOT NULL: Significa que la columna no puede tener valores nulos.
DEFAULT: Le proporcionamos a una columna un valor por defecto cuando el valor de
la columna no se especifica en la cláusula INSERT. En la especificación DEFAULT es
posible incluir varias expresiones: constantes, funciones SQL y variables UID y
SYSDATE.
Verificación de restricciones: CHECK: Actúa como una cláusula where. Puede hacer
referencia a una o más columnas, pero no a valores de otras filas. En una cláusula
CHECK no se pueden incluir subconsultas ni las pseudoconsultas SYSDATE, UID y
USER.
Nota: La restricción NOT NULL es similar a CHECK (NOMBRE_COLUMNA
IS NOT NULL)
UNIQUE: Evita valores repetidos en la misma columna. Puede contener una o varias
columnas. Es similar a la restricción PRIMARY KEY, salvo que son posibles varias
columnas UNIQUE definidas en una tabla. Admite valores NULL. Al igual que en
PRIMARY KEY, cuando se define una restricción UNIQUE se crea un índice
automáticamente.
CREATE TABLE: permite crear una tabla a partir de la consulta de otra tabla ya
existente. La nueva tabla contendrá los datos obtenidos en la consulta. Se lleva a cabo
esta acción con la cláusula AS colocada al final de la orden CREATE TABLE.
DROP TABLE: suprime una tabla de la base de datos. Cada usuario puede borrar sus
propias tablas, pero solo el administrador o algún usuario con el privilegio "DROP ANY
TABLE" puede borrar las tablas de otro usuario. Al suprimir una tabla también se
suprimen los índices y los privilegios asociados a ella. Las vistas y los sinónimos
creados a partir de esta tabla dejan de funcionar pero siguen existiendo en la base de
datos por tanto deberíamos eliminarlos.
Ejemplo:
DROP TABLE [USUARIO].NOMBRETABLA [CASCADE CONSTRAINTS];
TRUNCATE: permite suprimir todas las filas de una tabla y liberar el espacio ocupado
para otros usos sin que reaparezca la definición de la tabla de la base de datos. Una
orden TRUNCATE no se puede anular, como tampoco activa disparadores DELETE.
Modificación de tablas:
A la hora de añadir una columna a una tabla hay que tener en cuenta:
Si la columna no esta definida como NOT NULL se le puede añadir en cualquier
momento.
Si la columna esta definida como NOT NULL se pueden seguir estos pasos:
Se añade una columna sin especificar NOT NULL.
Se da valor a la columna para cada una de las filas.
Se modifica la columna NOT NULL.
Al modificar una columna de duna tabla se han de tener en cuenta:
Se puede aumentar la longitud de una columna en cualquier momento.
Es posible aumentar o disminuir el numero de posiciones decimales en una columna de
tipo NUMBER.
Si la columna es NULL en todas las filas de la tabla, se puede disminuir la longitud y
modificar el tipo de dato
La opción MODIFY… NOT NULL solo será posible cuando la tabla no contenga
ninguna fila con valor nulo en la columna que se modifica.
Adición de restricciones:
La orden ALTER TABLE con la cláusula DROP CONSTRAINT; con la que se borran
las restricciones con nombre y las asignadas por el sistema. Formato:
Insert:
Propiedades:
Si las columnas no se especifican en la cláusula Insert se consideran, por defecto, todas
las columnas de la tabla.
Las columnas a las que damos valores se identifican por su nombre.
La asociación columna valor es posicional.
Los valores que se dan a las columnas deben coincidir con el tipo de dato definido en la
columna.
Los valores constantes de tipo carácter han de ir encerrados entre comillas simples (' ')
(los de tipo fecha también).
Con Select:
Update:
Actualiza los valores de las columnas para una o varias filas de una tabla:
UPDATE NOMBRETABLA
SET COLUMNA1= VALOR1, …, COLUMNAN= VALORN
WHERE CONDICION;
Cuando la subconsulta (orden select) forma parte de SET, debe seleccionar el mismo
numero de columnas, (con tipos de datos adecuados) que los que hay entre paréntesis al
lado de SET.
UPDATE NOMBRETABLA
SET COLUMNA= VALOR1, COLUMNA2= VALOR2, …
WHERE COLUMNA3= (SELECT…)
UPDATE NOMBRETABLA
SET (COLUMNA1, COLUMNA2, …)= (SELECT …)
WHERE CONDICION;
Delete:
+ = Suma
- = Resta
* = Multiplicación
/ = división
Obtenemos los datos de los jugadores cuyos apellidos empiecen con una "S":
SELECT APELLIDO
FROM JUGADORES
WHERE APELLIDO LIKE 'S%';
SELECT APELLIDO
FROM JUGADORES
WHERE APELLIDO LIKE '_R*';
Obtenemos aquellos apellidos que empiezan por "A" y tiene una "o" en su interior:
SELECT APELLIDO
FROM JUGADORES
WHERE APELLDIOS LIKE 'A%O%';
SELECT APELLIDOS
FROM JUGADORES
WHERE JUGADOR_NUM IN (10, 20);
SELECT APELLIDOS
FROM JUGADORES
WHERE SALARIO NOT BETWEEN 15000000 AND 20000000;
Selecciona los apellidos de los jugadores donde el salario de estos no este entre (Not
Between) 15000000 y 20000000.
Consulta que se hace sobre los datos que nos da otra consulta. Su formato es:
SELECT______
FROM________
WHERE CONDICION OPERADOR (SELECT ______
FROM ___________
WHERE CONDICION OPERADOR); Ejemplo:
SELECT APELLIDO
FORM EMPLE
WHERE POSICION = (SELECT OFICIO
FROM EMPLE
WHERE APELLIDO LIKE 'GIL');
Seleccionamos en todos los campos de la tabla Jugadores cuya sede está en Madrid o
Barcelona:
SELECT *
FROM JUGADORES
WHERE EQUIPO_NOM IN (SELECT EQUIPO_NOM
FROM SEDE
WHERE LOC IN ('MADRID', 'BARCELONA');
FROM SEDE
WHERE LOC IN ('MADRID', 'BARCELONA');
Para saber cual es el salario medio de cada departamento de la tabla Jugadores sería:
Los datos seleccionados en la sentencia "Select" que lleva el "Group By" deben ser:
Una constante.
La cláusula Having se emplea para controlar cual de los conjuntos de filas se visualiza.
Se evalúa sobre la tabla que devuelve el Group By. No puede existir sin Group By.
Having es similar al Where, pero trabajo con grupos de filas; pregunta por una
característica de grupo, es decir, pregunta por los resultados de las funciones de grupo,
lo cual Where no pude hacer.
Nos permite seleccionar algunas filas de una tabla aunque estas no tengan
correspondencia con las filas de la otra tabla con la que se combina. Formato:
Esto selecciona todas las filas de la tabla "tabla1" aunque no tengan correspondencia
con las filas de la tabla "tabla2", se utiliza el símbolo +.
El resto de columnas de la tabla "tabla2" se rellena con NULL.
Permite combinar los resultados de varios "Select" para obtener un único resultado.
Formato:
UNION= Combina los resultados de dos consultas. Las filas duplicadas que aparecen se
reducen a una fila única.
UNION ALL= Como la anterior pero aparecerán nombres duplicados.
INTERSEC= Devuelve las filas que son iguales en ambas consultas. Todas las filas
duplicadas serán eliminadas.
MINUS= Devuelve aquellas filas que están en la primera "Select" y no están en la
segunda "Select". Las filas duplicadas del primer conjunto se reducirán a una fila única
antes de que empiece la comparación con el otro conjunto.
Por tanto, muchas veces no basta con especificar una sentencia SQL correcta, sino que
además, hay que indicarle como tiene que hacerlo si queremos que el tiempo de
respuesta sea el mínimo. En este apartado veremos como mejorar el tiempo de respuesta
de nuestro interprete ante unas determinadas situaciones:
Diseño de las tablas
Normaliza las tablas, al menos hasta la tercera forma normal, para asegurar que no hay
duplicidad de datos y se aprovecha al máximo el almacenamiento en las tablas. Si hay
que desnormalizar alguna tabla piensa en la ocupación y en el rendimiento antes de
proceder.
Los primeros campos de cada tabla deben ser aquellos campos requeridos y dentro de
los requeridos primero se definen los de longitud fija y después los de longitud variable.
Ajusta al máximo el tamaño de los campos para no desperdiciar espacio.
Es muy habitual dejar un campo de texto para observaciones en las tablas. Si este campo
se va a utilizar con poca frecuencia o si se ha definido con gran tamaño, por si acaso, es
mejor crear una nueva tabla que contenga la clave primaria de la primera y el campo
para observaciones.
Gestión y elección de los índices
Los índices son campos elegidos arbitrariamente por el constructor de la base de datos
que permiten la búsqueda a partir de dicho campo a una velocidad notablemente
superior. Sin embargo, esta ventaja se ve contrarrestada por el hecho de ocupar mucha
más memoria (el doble más o menos) y de requerir para su inserción y actualización un
tiempo de proceso superior.
Evidentemente, no podemos indexar todos los campos de una tabla extensa ya que
doblamos el tamaño de la base de datos. Igualmente, tampoco sirve de mucho el indexar
todos los campos en una tabla pequeña ya que las selecciones pueden efectuarse
rápidamente de todos modos.
Un caso en el que los índices pueden resultar muy útiles es cuando realizamos
peticiones simultáneas sobre varias tablas. En este caso, el proceso de selección puede
acelerarse sensiblemente si indexamos los campos que sirven de nexo entre las dos
tablas.
Campos a Seleccionar
En la medida de lo posible hay que evitar que las sentencias SQL estén embebidas
dentro del código de la aplicación. Es mucho más eficaz usar vistas o procedimientos
almacenados por que el gestor los guarda compilados. Si se trata de una sentencia
embebida el gestor debe compilarla antes de ejecutarla.
Seleccionar exclusivamente aquellos que se necesiten
No utilizar nunca SELECT * por que el gestor debe leer primero la estructura de la tabla
antes de ejecutar la sentencia
Si utilizas varias tablas en la consulta especifica siempre a que tabla pertenece cada
campo, le ahorras al gestor el tiempo de localizar a que tabla pertenece el campo. En
lugar de SELECT Nombre, Factura FROM Clientes, Facturacion WHERE IdCliente =
IdClienteFacturado, usa: SELECT Clientes.Nombre, Facturacion.Factura WHERE
Clientes.IdCliente = Facturacion.IdClienteFacturado.
Campos de Filtro
Se procurará elegir en la cláusula WHERE aquellos campos que formen parte de la
clave del fichero por el cual interrogamos. Además se especificarán en el mismo orden
en el que estén definidos en la clave.
Interrogar siempre por campos que sean clave.
Si deseamos interrogar por campos pertenecientes a índices compuestos es mejor
utilizar todos los campos de todos los índices. Supongamos que tenemos un índice
formado por el campo NOMBRE y el campo APELLIDO y otro índice formado por el
campo EDAD. La sentencia WHERE NOMBRE='Juan' AND APELLIDO Like '%'
AND EDAD = 20 sería más optima que WHERE NOMBRE = 'Juan' AND EDAD = 20
por que el gestor, en este segundo caso, no puede usar el primer índice y ambas
sentencias son equivalentes por que la condición APELLIDO Like '%' devolvería todos
los registros.
Orden de las Tablas
Cuando se utilizan varias tablas dentro de la consulta hay que tener cuidado con el
orden empleado en la cláusula FROM. Si deseamos saber cuantos alumnos se
matricularon en el año 1996 y escribimos: FROM Alumnos, Matriculas WHERE
Alumno.IdAlumno = Matriculas.IdAlumno AND Matriculas.Año = 1996 el gestor
recorrerá todos los alumnos para buscar sus matriculas y devolver las correspondientes.
Si escribimos FROM Matriculas, Alumnos WHERE Matriculas.Año = 1996 AND
Matriculas.IdAlumno = Alumnos.IdAlumnos, el gestor filtra las matrículas y después
selecciona los alumnos, de esta forma tiene que recorrer menos registros.
No contienen información por si mismas, sino que están basadas en las que contienen
otras tablas y refleja los datos de estas.
Si se suprime una tabla la vista asociada se invalida. Formato:
CREATE [OR REPLACE] VIEW NOMBREVISTA
[(COLUMNA [,COLUMNA])]
AS CONSULTA;
Borrado de vistas
Se pueden realizar las mismas operaciones que se hacen sobre las tablas. Restricciones:
Actualización Si una vista esta basada en una sola tabla, se pueden modificar las filas de
la vista.
La modificación de la vista cambia la tabla sobre la que esta definida.
Borrado de filas a través de una vista= Para borrar filas de una tabla a través de una
vista, esta se debe crear:
Con filas de una sola tabla.
Sin utilizar la cláusula GROUP BY ni DISTINCT.
Sin usar funciones de grupo o referencias a pseudocolumnas.
Actualización de filas a través de una vista: Para actualizar filas en una tabla a través de
una vista, esta ha de estar definida según las restricciones anteriores y , además, ninguna
de las columnas que se va a actualizar se habrá definido como una expresión.
Inserción de filas a través de una vista: Para insertar filas en una tabla a través de una
vista se han de tener en cuenta todas las restricciones anteriores y, además, todas las
columnas obligatorias de la tabla asociada deben estar presentes en la vista.
Manejo de expresiones y de funciones en vistas: Se pueden crear vistas usando
funciones, expresiones en columnas y consultas avanzadas pero únicamente se parean
consultar estas vistas. También podemos modificar filas siempre y cuando la columna
que se va a modificar no sea la columna expresad en forma de cálculo o con funciones.
Nota: No es posible insertar filas si las columnas de la vista contiene cálculos o
funciones.
Cambios de nombre
RENAME cambia el nombre de una tabla, vista o sinónimo. El nuevo nombre no puede
ser una palabra reservada ni el nombre de un objeto que tenga creado el usuario. Las
restricciones de integridad, los índices y los permisos dados al objeto se transfieren
automáticamente al nuevo objeto.
Con esta orden no podemos renombrar columnas de una tabla, estas se renombran
mediante CREATE TABLE AS
Otra cosa que nos diferencia los bloques anónimos de los procedimientos o funciones es
que en los procedimientos o funciones no se pueden utilizar variables de sustitución.
En cuanto a su construcción es la dada en el articulo Características de PL/SQL segunda
parte añadiendo al principio la siguiente secuencia “CREATE OR REPLACE” para
crearlo, o modificarlo si ya existe.
Pasamos a escribir un procedimiento que nos muestre los datos de un usuario:
CREATE OR REPLACE PROCEDURE ver_usuario(nomusu VARCHAR2)
IS
NIFusu VARCHAR2(10);
Domusu VARCHAR2(10);
BEGIN
select nif, domicilio into NIFusu,Domusu from usuario where nombre=nomusu;
DBMS_OUTPUT.PUT_LINE('Nombre:'||nomusu|| 'NIF:' ||NIFusu|| 'Domicilio' ||
Domusu);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('No hemos encontrado al usuario || nomusu);
END;
/
Si el compilador detecta errores nos saldrá un mensaje como este: “Procedimiento
creado con errores de compilación”. Para ver estos errores tenemos la orden SHOW
ERRORS.
Al tener almacenado el procedimiento en la base de datos, este puede ser llamado por
cualquier usuario que tenga los permisos oportunos. Para invocar un procedimiento
utilizamos la orden EXECUTE
Para invocar al procedimiento que hemos creado antes tendríamos que ejecutar la
siguiente orden:
EXECUTE ver_usuario('Luis');
Pero también podemos invocarlo desde un bloque PL/SQL de ls siguiente forma:
BEGIN
ver_usuario('Luis');
END;
.
Como en cualquier lenguaje, podemos agregar comentarios a nuestros procedimientos
de la siguiente forma:
- - para comentar en una sola linea
/* <comentario>*/ para varias lineas.
Otro ejemplo seria declarar una variable que fuera del mismo tipo que la columna
nombre de la tabla profesor.
nombre_alta nombre%ROWTYPE;
Ámbito y visibilidad de variables
La variable será local para el bloque en el que ha sido declarada y global para los bloque
hijos de éste, mientras que las variables declaradas en los bloque hijos no son globales a
los bloques padre.
Constantes
Cómo en la mayoría de los lenguajes, en este también podemos declaras constantes, de
la siguiente forma:
<nombreVariable> CONSTANT <tipo> := <valor>;
Operadores
Asignación :=
AND
Lógicos OR
NOT
Concatenación ||
Is null
=
!=
<>
<
>
Comparación
<=
>=
between...and
like
in
y sus correspondientes negaciones
Aritméticos + - * / **
Funciones predefinidas
En PL/SQL tenemos las mismas funciones predefinidas que en SQL (AVG, MIN, MAX,
COUNT, SUM, etc), pero tenemos que tener dos cosas muy claras a la hora de
utilizarlas y son:
La función no modifica el valor de las variables o expresiones que se pasan como
argumentos, sino que devuelve un valor a partir de dicho argumento.
Si a una función se le pasa un valor nulo en la llamada, posiblemente devolverá un valor
nulo.
Etiquetas
Podemos utilizar etiquetas para poder irnos a cualquier parte del programa utilizando la
sentencia GOTO siempre y cuando se cumplan las siguientes reglas:
No pueden haber etiquetas con los mismos nombres en un mismo programa.
La etiqueta debe preceder a un bloque o a un conjunto de ordenes ejecutables
la etiqueta no puede estar dentro de estructuras de control (IF, LOOP)
Para que esto quede más claro pasamos a escribir un ejemplo de paso de parámetros y
conversión de tipos.
Tenemos la especificación de un procedimiento como esta:
PROCEDURE departamento(
n_departamento INTEGER,
localidad VARCHAR2
IS...
Desde el siguiente bloque se podrán realizar las llamadas indicadas:
DECLARE
num_departamento INTEGER;
aula VARCHAR(30)
BEGIN
...
- - posicional departamento(num_departamento, aula);
- - nominal departamento(num_departamento => n_departamento, aula =>localidad);
...
END;
Esto nos pasaría los parámetros num_departamento al mismo tipo que n_departamento
y localidad al mismo tipo que aula.
Los parámetros que soporta PL/SQL pueden ser de entrada, salida o entrada/salida
Nos permite pasar valores a un subprograma. Dentro del subprograma, el
IN parámetro actuá como una constante. Puede ser una variable, constante,
literal o expresión.
Permite devolver valores al bloque que llamó al subprograma. Dentro
OUT del subprograma, el parámetro actúa como una variable no inicializada.
Solo puede ser una variable.
Permite pasar un valor inicial y devolver un valor actualizado. Dentro
IN
del subprograma, el parámetro actuá como variable inicializada. Puede
OUT
intervenir otras expresiones. El valor actual debe ser una variable.
END LOOP;
CLOSE C1;
END;
Variables de acoplamientos en el manejo de cursores
En el ejemplo siguiente podemos observar que en la cláusula WHERE se incluye una
variable que se debería haber declarado previamente. Este tipo de variables reciben el
nombre de variables de acoplamiento. El programa la sustituirá por su valor en el
momento en que se abre el cursor, y se seleccionarán las filas según dicho valor. Aunque
ese valor cambie durante la recuperación de los datos con FETCH, el conjunto de filas
que contiene el cursor no variará.
El ejemplo nos muestra los futbolistas de un equipo cualquiera.
CREATE OR REPLACE PROCEDURE ver_futbolistas_por_equipos(codeq
VARCHAR2)
IS
Vequi VARCHAR2(3);
CURSOR C1 IS SELECT nombre from futbolista where codeq=Vequi;
Vnom VARCHAR(15);
BEGIN
vequi:=codeq;
OPEN C1;
FETCH C1 INTO vnom;
WHILE C1%FOUND LOOP
DBMS_OUTPUT.PUT_LINE(Vnom);
FETCH C1 INTO Vnom;
END LOOP;
CLOSE C1;
END;
Para realizar una actualización con un cursor tenemos que añadir la siguiente FOR
UPDATE al final de la declaración del cursor:
CURSOR nombre_cursor <declaraciones> FOR UPDATE
Esto indica que las filas seleccionadas por el cursor van a ser actualizadas o borradas.
Una vez declarado un cursor FOR UPDATE, se incluirá el especificador CURRENT OF
nombre_cursor en la cláusula WHERE para actualizar o borrar la última fila recuperada
mediante la orden FETCH.
{UPDATE|DELETE}... WHERE CURRENT OF nombre_cursor.
Os pongo un ejemplo para que quede claro:
Subir el salario a todos los empleados del departamento indicado en la llamada. El
porcentaje se indicará también en la llamada.
CREATE OR REPLACE PROCEDURE subir_salario (num_dept NUMBER, incre
NUMBER)
IS
CURSOR c IS SELECT oficio, salario FROM empleados WHERE
cod_dept=num_dept
FOR UPDATE;
reg c%ROWTYPE;
inc NUMBER (8);
BEGIN
OPEN c;
FETCH c INTO reg;
WHILE c%FOUND LOOP
inc :=(reg.salario/100 )* inc;
UPDATE empleados SET salario=salario+inc WHERE CURRENT OF c
FETCH c INTO reg;
END LOOP;
END;
También podemos usar ROWID en lugar de FOR UPDATE. ROWID nos indicará la fila
que se va a actualizar. Para ello, al declarar el cursor en la cláusula SELECT
indicaremos que seleccione también el identificador de fila:
CURSOR nombre_cursor IS SELECT columna1,columna2,...ROWID FROM tabla;
Al ejecutarse el FETCH se guardará el número de fila en una variable y después ese
número se podrá usar en la cláusula WHERE de la actualización:
{UPDATE |DELETE } ... WHERE ROWID = variable_rowid
El ejemplo anterior utilizando ROWID quedaría de la siguiente manera:
CREATE OR REPLACE PROCEDURE subir_salario (num_dept NUMBER, incre
NUMBER)
IS
CURSOR c IS SELECT oficio, salario,ROWID FROM empleados WHERE
cod_dept=num_dept
FOR UPDATE;
reg c%ROWTYPE;
inc NUMBER (8);
BEGIN
OPEN c;
FETCH c INTO reg;
WHILE c%FOUND LOOP
inc :=(reg.salario/100 )* inc;
UPDATE empleados SET salario=salario+inc WHERE ROWID =
reg.ROWID;
FETCH c INTO reg;
END LOOP;
END;
Con este artículo damos por terminado todo lo referente a cursores y empezamos a tratar
las excepciones en el siguiente artículo.
...
EXCEPTION
WHEN OTHERS THEN
rollback work;
END;
Comandos utilizados para el control de transacciones
Commit
Este comando da por concluida la transacción actual y hace definitivos los cambios
realizados liberando las filas bloqueadas. Sólo después de que se ejecute commit
tendremos acceso a los datos modificados.
Rollback
Este comando da por concluida la transacción actual y deshace los cambios que se
pudiesen haber producido en la misma, liberando las filas bloqueadas. Se utiliza
especialmente cuando no se puede concluir una transacción porque se han levantado
excepciones.
Savepoint
Se utiliza para poner marcas o puntos de salvaguarda al procesar transacciones. Se
utiliza junto con rollback permitiendo deshacer cambios hasta los savepoint.
El número de savepoint esta limitado a 5 por sesión pero lo podemos modificar con la
siguiente sentencia:
savepoint numero;
Rollback implicito
Este comando se ejecuta cuando un programa almacenado (procedimiento o función)
falla y no se controla la excepción que produjo el fallo. Pero si en el programa tenemos
un commit estos cambios no serán deshechos.
Rollback to
Deshace el trabajo realizado después del punto indicado. Pero no se confirma el trabajo
hecho hasta el savepoint. La transacción no finaliza hasta que se ejecuta un comando de
control de transacciones o hasta que finaliza la sesión.
Os dejo a continuación un ejemplo bastante completo de lo que seria el control de
transacciones:
create or replace procedure prueba (nfilas number)
as
begin
savepoint ninguna;
insert into tmp values ('primera fila');
savepoint una;
insert into tmp values ('segunda fila');
savepoint dos;
if nfilas=1 then
rollback to una;
else if nfilas=2 then
rollback to dos;
else
rollback to ninguna;
end if;
commit;
exception
when other then
rollback
end prueba;
Con este artículo terminamos la parte básica sobre oracle, PL/SQL y pasamos a lo que
podemos denominar programación avanzada de sql. Empezaremos con triggers en el
siguiente artículo.
Oracle tiene algunas funciones que permiten acceder a los atributos del evento del
disparo ORA_YSEVENT, ORA_LOGIN, etc. Estas funciones pueden usarse en la
clausula WHEN o en el cuerpo del disparador. En el manual de Oracle podéis encontrar
el listado de todas estas funciones.
Un ejemplo seria un trigger que nos guarda los datos de un usuario al hacer login en la
base de datos:
create or replace trigger control
after logon
on database
begin
insert into control_conexion (usuario, momento, evento)
values {ORA_LOGIN_USER, SYSTIMESTAMP, ORA_SYSEVENT);
end;
30.- Paquetes en Oracle
Vamos a ver que son los paquetes en el sistema gestor de base de datos Oracle,
explicando estructura y funcionamiento.
En este artículo que pertenece al tutorial de Oracle trateremos el tema de los paquetes de
forma detenida.
Los paquetes en Oracle se utilizan para guardar subprogramas y otros objetos de la base
de datos.
Un paquete consta de los siguientes elementos:
Especificación o cabecera: contiene las declaraciones públicas (es decir, accesibles
desde cualquier parte de la aplicación) de sus programas, tipos, constantes, variables,
cursores, excepciones, etc.
Cuerpo: contiene los detalles de implementación y declaraciones privadas, es decir,
accesibles solamente desde los objetos del paquete.
La sintaxis de la cabecera es la siguiente:
create [or replace] package nombre_paquete as
<declaraciones públicas>
<especificaciones de subprogramas>
end nombre_paquete;
La sintaxis del cuerpo sería la siguiente:
create [or replace] package body nombre_paquete as
<declaraciones privadas>
<código de subprogramas>
[begin
<instrucciones iniciales>]
end nombre_paquete;
Como podéis observar la cabecera se compila independientemente del cuerpo. Os dejo
un ejemplo de paquete para que lo veáis más claro.
/* Cabecera */
create or replace package busar_emple as
TYPE t_reg_emple is RECORD
(num_empleado emple.emp_no%TYPE,
apellido emple.apellido%TYPE,
salario emple.salario%TYPE,
departamento emple.dept_no%TYPE);
procedure ver_por_numero(v_cod emple.emp_no%TYPE);
procedure ver_por_apellido(v_ape emple.apellido%TYPE);
function datos (v_cod emple.emp_no%TYPE)
return t_reg_emple;
end buscar_emple;
/* Cuerpo */