Instalación de Oracle.
Para este curso utilizaremos la versión Oracle 10g XE (Express Edition para Windows) Para
descargar el mismo debemos ingresar al sitio de Oracle:
1. Oracle 10g XE
2. Para permitir descargarlo del sitio seleccionamos con el mouse el control Radio "Accept
License Agreement".
3. Luego seleccionamos la versión "Oracle Database 10g Express Edition (Universal)"
([Link] (216,933,372 bytes))
4. El sitio de Oracle requiere que nos registremos. Debemos seleccionar "sign up now" y
luego "Create your Oracle account now", es decir crear una cuenta Oracle.
Luego de habernos registrado podemos descargar el motor de base de datos Oracle.
5. El paso siguiente es instalar el gestor de base de datos propiamente dicho. Ejecutamos el
archivo que acabamos de descargar: [Link]
Debemos ir presionando el botón "siguiente" en el asistente de instalación, salvo cuando
nos pide ingresar la contraseña de la base de datos, es importante no olvidar dicha clave.
Luego de algunos minutos ya tenemos instalado el gestor de bases de datos Oracle en
nuestro equipo.
La segunda aplicación que instalaremos será el "Oracle SQL Developer". Es un entorno visual
que nos permite comunicar con nuestro gestor de base de datos Oracle. Desde este entorno
aprenderemos a administrar una base de datos Oracle.
1. Debemos ingresar a la siguiente página para descargar el Oracle SQL Developer
2. Aceptamos la licencia y seleccionamos "Oracle SQL Developer for Windows
(JDK1.5.0_06 is bundled in this zip)
3. Luego de descargar el archivo procedemos a descomprimir el archivo zip en una carpeta
(este programa no requiere instalación)
4. En la carpeta donde descomprimimos debemos ejecutar el archivo [Link]
5. 2 - Crear tablas (create table -
describe - all_tables - drop table)
Existen varios objetos de base de datos: tablas, constraints (restricciones), vistas, secuencias,
índices, agrupamientos (clusters), disparadores (triggers), instantaneas (snapshots),
procedimientos, funciones, paquetes, sinónimos, usuarios, perfiles, privilegios, roles, etc.
Los primeros objetos que veremos son tablas.
Una base de datos almacena su información en tablas, que es la unidad básica de
almacenamiento.
Una tabla es una estructura de datos que organiza los datos en columnas y filas; cada columna es
un campo (o atributo) y cada fila, un registro. La intersección de una columna con una fila,
contiene un dato específico, un solo valor.
Cada registro contiene un dato por cada columna de la tabla. Cada campo (columna) debe tener
un nombre. El nombre del campo hace referencia a la información que almacenará.
Cada campo (columna) también debe definir el tipo de dato que almacenará.
Las tablas forman parte de una base de datos.
Nosotros trabajaremos con la base de datos ya creada.
Para ver las tablas existentes tipeamos:
select *from all_tables;
Aparece una tabla que nos muestra en cada fila, los datos de una tabla específica; en la columna
"TABLE_NAME" aparece el nombre de cada tabla existente.
Al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo de datos
almacenarán cada uno de ellos, es decir, su estructura.
La sintaxis básica y general para crear una tabla es la siguiente:
create table NOMBRETABLA(
NOMBRECAMPO1 TIPODEDATO,
...
NOMBRECAMPON TIPODEDATO
);
La tabla debe ser definida con un nombre que la identifique y con el cual accederemos a ella.
Creamos una tabla llamada "usuarios" y entre paréntesis definimos los campos y sus tipos:
create table usuarios(
nombre varchar2(30),
clave varchar2(10)
);
Cada campo con su tipo debe separarse con comas de los siguientes, excepto el último.
Cuando se crea una tabla debemos indicar su nombre y definir al menos un campo con su tipo de
dato. En esta tabla "usuarios" definimos 2 campos:
- nombre: que contendrá una cadena de caracteres de 30 caracteres de longitud, que almacenará
el nombre de usuario y
- clave: otra cadena de caracteres de 10 de longitud, que guardará la clave de cada usuario.
Cada usuario ocupará un registro de esta tabla, con su respectivo nombre y clave.
Para nombres de tablas, se puede utilizar cualquier caracter permitido para nombres de
directorios, el primero debe ser un caracter alfabético y no puede contener espacios. La longitud
máxima es de 30 caracteres.
Si intentamos crear una tabla con un nombre ya existente (existe otra tabla con ese nombre),
mostrará un mensaje indicando que a tal nombre ya lo está utilizando otro objeto y la sentencia
no se ejecutará.
Para ver la estructura de una tabla usamos el comando "describe" junto al nombre de la tabla:
describe usuarios;
Aparece la siguiente información:
Name Null Type
-------------------------------
NOMBRE VARCHAR2(30)
CLAVE VARCHAR2(10)
Esta es la estructura de la tabla "usuarios"; nos muestra cada campo, su tipo y longitud y otros
valores que no analizaremos por el momento.
Para eliminar una tabla usamos "drop table" junto al nombre de la tabla a eliminar:
drop table NOMBRETABLA;
En el siguiente ejemplo eliminamos la tabla "usuarios":
drop table usuarios;
Si intentamos eliminar una tabla que no existe, aparece un mensaje de error indicando tal
situación y la sentencia no se ejecuta.
2 - Crear tablas (create table - describe -
all_tables - drop table)
Primer problema:
Necesita almacenar los datos de amigos en una tabla. Los datos que guardará serán: apellido,
nombre, domicilio y teléfono.
1- Elimine la tabla "agenda"
Si no existe, un mensaje indicará tal situación.
2- Intente crear una tabla llamada "*agenda"
create table *agenda(
apellido varchar2(30),
nombre varchar2(20),
domicilio varchar2(30),
telefono varchar2(11)
);
aparece un mensaje de error indicando que usamos un caracter inválido ("*") para el nombre de
la tabla.
3- Cree una tabla llamada "agenda", debe tener los siguientes campos: apellido, varchar2(30);
nombre, varchar2(20); domicilio, varchar2 (30) y telefono, varchar2(11)
Un mensaje indica que la tabla ha sido creada exitosamente.
4- Intente crearla nuevamente.
Aparece mensaje de error indicando que el nombre ya lo tiene otro objeto.
5- Visualice las tablas existentes (all_tables)
La tabla "agenda" aparece en la lista.
6- Visualice la estructura de la tabla "agenda" (describe)
Aparece la siguiente tabla:
Name Null Type
-----------------------
APELLIDO VARCHAR2(30)
NOMBRE VARCHAR2(20)
DOMICILIO VARCHAR2(30)
TELEFONO VARCHAR2(11)
Ver solución
Segundo problema:
Necesita almacenar información referente a los libros de su biblioteca personal. Los datos que
guardará serán: título del libro, nombre del autor y nombre de la editorial.
1- Elimine la tabla "libros"
Si no existe, un mensaje indica tal situación.
2- Verifique que la tabla "libros" no existe (all_tables)
No aparece en la lista.
3- Cree una tabla llamada "libros". Debe definirse con los siguientes campos: titulo,
varchar2(20); autor, varchar2(30) y editorial, varchar2(15)
4- Intente crearla nuevamente:
Aparece mensaje de error indicando que existe un objeto con el nombre "libros".
5- Visualice las tablas existentes
6- Visualice la estructura de la tabla "libros":
Aparece "libros" en la lista.
7- Elimine la tabla
8- Intente eliminar la tabla
Un mensaje indica que no existe.
Ver solución
3 - Ingresar registros (insert into- select)
Un registro es una fila de la tabla que contiene los datos propiamente dichos. Cada registro tiene
un dato por cada columna (campo). Nuestra tabla "usuarios" consta de 2 campos, "nombre" y
"clave".
Al ingresar los datos de cada registro debe tenerse en cuenta la cantidad y el orden de los
campos.
La sintaxis básica y general es la siguiente:
insert into NOMBRETABLA (NOMBRECAMPO1, ..., NOMBRECAMPOn)
values (VALORCAMPO1, ..., VALORCAMPOn);
Usamos "insert into", luego el nombre de la tabla, detallamos los nombres de los campos entre
paréntesis y separados por comas y luego de la cláusula "values" colocamos los valores para cada
campo, también entre paréntesis y separados por comas.
En el siguiente ejemplo se agrega un registro a la tabla "usuarios", en el campo "nombre" se
almacenará "Mariano" y en el campo "clave" se guardará "payaso":
insert into usuarios (nombre, clave)
values ('Mariano','payaso');
Luego de cada inserción aparece un mensaje indicando la cantidad de registros ingresados.
Note que los datos ingresados, como corresponden a cadenas de caracteres se colocan entre
comillas simples.
Para ver los registros de una tabla usamos "select":
select *from usuarios;
El comando "select" recupera los registros de una tabla. Con el asterisco indicamos que muestre
todos los campos de la tabla "usuarios".
Aparece la tabla, sus campos y registros ingresados; si no tiene registros, aparecerían solamente
los campos y la tabla vacía).
Es importante ingresar los valores en el mismo orden en que se nombran los campos: En el
siguiente ejemplo se lista primero el campo "clave" y luego el campo "nombre" por eso, los
valores también se colocan en ese orden:
insert into usuarios (clave, nombre)
values ('River','Juan');
Si ingresamos los datos en un orden distinto al orden en que se nombraron los campos, no
aparece un mensaje de error y los datos se guardan de modo incorrecto.
En el siguiente ejemplo se colocan los valores en distinto orden en que se nombran los campos,
el valor de la clave (la cadena "Boca") se guardará en el campo "nombre" y el valor del nombre
(la cadena "Luis") en el campo "clave":
insert into usuarios (nombre,clave)
values ('Boca','Luis');
3 - Ingresar registros (insert into- select)
Primer problema:
Trabaje con la tabla "agenda" que almacena información de sus amigos.
1- Elimine la tabla "agenda"
2- Cree una tabla llamada "agenda". Debe tener los siguientes campos: apellido (cadena de 30),
nombre (cadena de 20), domicilio (cadena de 30) y telefono (cadena de 11)
3- Visualice las tablas existentes para verificar la creación de "agenda" (all_tables)
4- Visualice la estructura de la tabla "agenda" (describe)
5- Ingrese los siguientes registros:
insert into agenda (apellido, nombre, domicilio, telefono)
values ('Moreno','Alberto','Colon 123','4234567');
insert into agenda (apellido,nombre, domicilio, telefono)
values ('Torres','Juan','Avellaneda 135','4458787');
6- Seleccione todos los registros de la tabla.
7- Elimine la tabla "agenda"
8- Intente eliminar la tabla nuevamente (aparece un mensaje de error)
Ver solución
Segundo problema:
Trabaje con la tabla "libros" que almacena los datos de los libros de su propia biblioteca.
1- Elimine la tabla "libros"
2- Cree una tabla llamada "libros". Debe definirse con los siguientes campos: titulo (cadena de
20), autor (cadena de 30) y editorial (cadena de 15)
3- Visualice las tablas existentes.
4- Visualice la estructura de la tabla "libros"
Muestra los campos y los tipos de datos de la tabla "libros".
5- Ingrese los siguientes registros:
insert into libros (titulo,autor,editorial)
values ('El aleph','Borges','Planeta');
insert into libros (titulo,autor,editorial)
values ('Martin Fierro','Jose Hernandez','Emece');
insert into libros (titulo,autor,editorial)
values ('Aprenda PHP','Mario Molina','Emece');
6- Muestre todos los registros (select) de "libros"
Ver solución
4 - Tipos de datos
Ya explicamos que al crear una tabla debemos resolver qué campos (columnas) tendrá y que tipo
de datos almacenará cada uno de ellos, es decir, su estructura.
El tipo de dato especifica el tipo de información que puede guardar un campo: caracteres,
números, etc.
Estos son algunos tipos de datos básicos de Oracle (posteriormente veremos otros y con más
detalle):
- varchar2: se emplea para almacenar cadenas de caracteres. Una cadena es una secuencia
de caracteres. Se coloca entre comillas simples; ejemplo: 'Hola', 'Juan Perez', 'Colon 123'.
Este tipo de dato definen una cadena de longitud variable en la cual determinamos el
máximo de caracteres entre paréntesis. Puede guardar hasta xxx caracteres. Por ejemplo,
para almacenar cadenas de hasta 30 caracteres, definimos un campo de tipo varchar2
(30), es decir, entre paréntesis, junto al nombre del campo colocamos la longitud.
Si intentamos almacenar una cadena de caracteres de mayor longitud que la definida, la
cadena no se carga, aparece un mensaje indicando tal situación y la sentencia no se
ejecuta.
Por ejemplo, si definimos un campo de tipo varchar(10) e intentamos almacenar en él la
cadena 'Buenas tardes', aparece un mensaje indicando que el valor es demasiado grande
para la columna.
- number(p,s): se usa para guardar valores numéricos con decimales, de 1.0 x10-120 a 9.9...(38
posiciones). Definimos campos de este tipo cuando queremos almacenar valores numéricos con
los cuales luego realizaremos operaciones matemáticas, por ejemplo, cantidades, precios, etc.
Puede contener números enteros o decimales, positivos o negativos. El parámetro "p" indica la
precisión, es decir, el número de dígitos en total (contando los decimales) que contendrá el
número como máximo. El parámetro "s" especifica la escala, es decir, el máximo de dígitos
decimales. Por ejemplo, un campo definido "number(5,2)" puede contener cualquier número
entre 0.00 y 999.99 (positivo o negativo).
Para especificar número enteros, podemos omitir el parámetro "s" o colocar el valor 0 como
parámetro "s". Se utiliza como separador el punto (.).
Si intentamos almacenar un valor mayor fuera del rango permitido al definirlo, tal valor no se
carga, aparece un mensaje indicando tal situación y la sentencia no se ejecuta.
Por ejemplo, si definimos un campo de tipo number(4,2) e intentamos guardar el valor 123.45,
aparece un mensaje indicando que el valor es demasiado grande para la columna. Si ingresamos
un valor con más decimales que los definidos, el valor se carga pero con la cantidad de
decimales permitidos, los dígitos sobrantes se omiten.
Antes de crear una tabla debemos pensar en sus campos y optar por el tipo de dato adecuado para
cada uno de ellos.
Por ejemplo, si en un campo almacenaremos números telefónicos o un números de documento,
usamos "varchar2", no "number" porque si bien son dígitos, con ellos no realizamos operaciones
matemáticas. Si en un campo guardaremos apellidos, y suponemos que ningún apellido superará
los 20 caracteres, definimos el campo "varchar2(20)". Si en un campo almacenaremos precios
con dos decimales que no superarán los 999.99 pesos definimos un campo de tipo
"number(5,2)", es decir, 5 dígitos en total, con 2 decimales. Si en un campo almacenaremos
valores enteros de no más de 3 dígitos, definimos un campo de tipo "number(3,0)".
4 - Tipos de datos
Primer problema:
Un videoclub que alquila películas en video almacena la información de sus películas en una
tabla llamada "peliculas"; para cada película necesita los siguientes datos:
-nombre, cadena de caracteres de 20 de longitud,
-actor, cadena de caracteres de 20 de longitud,
-duración, valor numérico entero que no supera los 3 dígitos.
-cantidad de copias: valor entero de un sólo dígito (no tienen más de 9
copias de cada película).
1- Elimine la tabla "peliculas" si ya existe.
2- Cree la tabla eligiendo el tipo de dato adecuado para cada campo.
Note que los campos "duracion" y "cantidad", que almacenarán valores sin decimales, fueron
definidos de maneras diferentes, en el primero especificamos el valor 0 como cantidad de
decimales, en el segundo no especificamos cantidad de decimales, es decir, por defecto, asume el
valor 0.
3- Vea la estructura de la tabla.
4- Ingrese los siguientes registros:
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mision imposible','Tom Cruise',128,3);
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mision imposible 2','Tom Cruise',130,2);
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mujer bonita','Julia Roberts',118,3);
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Elsa y Fred','China Zorrilla',110,2);
5- Muestre todos los registros (4 registros)
6- Intente ingresar una película con valor de cantidad fuera del rango permitido:
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mujer bonita','Richard Gere',1200,10);
Mensaje de error.
7- Ingrese un valor con decimales en un nuevo registro, en el campo "duracion":
insert into peliculas (nombre, actor, duracion, cantidad)
values ('Mujer bonita','Richard Gere',120.20,4);
8- Muestre todos los registros para ver cómo se almacenó el último registro ingresado.
9- Intente ingresar un nombre de película que supere los 20 caracteres.
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados" que guarda los
siguientes datos: nombre, documento, sexo, domicilio, sueldobasico.
1- Elimine la tabla si existe.
2- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table empleados(
nombre varchar2(20),
documento varchar2(8),
sexo varchar2(1),
domicilio varchar2(30),
sueldobasico number(6,2)
);
3- Verifique que la tabla existe consultando "all_tables"
4- Vea la estructura de la tabla (5 campos)
5- Ingrese algunos registros:
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Juan Perez','22333444','m','Sarmiento 123',500);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Ana Acosta','24555666','f','Colon 134',650);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Bartolome Barrios','27888999','m','Urquiza 479',800);
6- Seleccione todos los registros (3 registros)
7- Intente ingresar un registro con el valor "masculino" en el campo "sexo"
Un mensaje indica que el campo está definido para almacenar 1 solo caracter como máximo y
está intentando ingresar 9 caracteres.
8- Intente ingresar un valor fuera de rango, en un nuevo registro, para el campo "sueldobasico"
Mensaje de error.
9- Elimine la tabla
Ver solución
5 - Recuperar algunos campos (select)
Hemos aprendido cómo ver todos los registros de una tabla, empleando la instrucción "select".
La sintaxis básica y general es la siguiente:
select *from NOMBRETABLA;
El asterisco (*) indica que se seleccionan todos los campos de la tabla.
Podemos especificar el nombre de los campos que queremos ver, separándolos por comas:
select titulo,autor from libros;
La lista de campos luego del "select" selecciona los datos correspondientes a los campos
nombrados. En el ejemplo anterior seleccionamos los campos "titulo" y "autor" de la tabla
"libros", mostrando todos los registros.
5 - Recuperar algunos campos (select)
Primer problema:
Un videoclub que alquila películas en video almacena la información de sus películas en alquiler
en una tabla llamada "peliculas".
1- Elimine la tabla si existe.
2- Cree la tabla:
create table peliculas(
titulo varchar2(20),
actor varchar2(20),
duracion number(3),
cantidad number(1)
);
3- Vea la estructura de la tabla (4 campos)
4- Ingrese los siguientes registros:
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible','Tom Cruise',180,3);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible 2','Tom Cruise',190,2);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mujer bonita','Julia Roberts',118,3);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Elsa y Fred','China Zorrilla',110,2);
5- Realice un "select" mostrando solamente el título y actor de todas las películas
6- Muestre el título y duración de todas las peliculas.
7- Muestre el título y la cantidad de copias.
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla llamada "empleados".
1- Elimine la tabla si ya existe.
2- Cree la tabla:
create table empleados(
nombre varchar2(20),
documento varchar2(8),
sexo varchar2(1),
domicilio varchar2(30),
sueldobasico number(6,2)
);
3- Vea la estructura de la tabla (5 campos)
4- Ingrese algunos registros:
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Juan Juarez','22333444','m','Sarmiento 123',500);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Ana Acosta','27888999','f','Colon 134',700);
insert into empleados (nombre, documento, sexo, domicilio, sueldobasico)
values ('Carlos Caseres','31222333','m','Urquiza 479',850);
5- Muestre todos los datos de los empleados.
6- Muestre el nombre, documento y domicilio de los empleados.
7- Realice un "select" mostrando el documento, sexo y sueldo básico de todos los empleados.
Ver solución
6 - Recuperar algunos registros (where)
Hemos aprendido a seleccionar algunos campos de una tabla.
También es posible recuperar algunos registros.
Existe una cláusula, "where" con la cual podemos especificar condiciones para una consulta
"select". Es decir, podemos recuperar algunos registros, sólo los que cumplan con ciertas
condiciones indicadas con la cláusula "where". Por ejemplo, queremos ver el usuario cuyo
nombre es "Marcelo", para ello utilizamos "where" y luego de ella, la condición:
select nombre, clave
from usuarios
where nombre='Marcelo';
La sintaxis básica y general es la siguiente:
select NOMBRECAMPO1, ..., NOMBRECAMPOn
from NOMBRETABLA
where CONDICION;
Para las condiciones se utilizan operadores relacionales (tema que trataremos más adelante en
detalle). El signo igual(=) es un operador relacional. Para la siguiente selección de registros
especificamos una condición que solicita los usuarios cuya clave es igual a "River":
select nombre,clave
from usuarios
where clave='River';
Si ningún registro cumple la condición establecida con el "where", no aparecerá ningún registro.
Entonces, con "where" establecemos condiciones para recuperar algunos registros.
Para recuperar algunos campos de algunos registros combinamos en la consulta la lista de
campos y la cláusula "where":
select nombre
from usuarios
where clave='River';
En la consulta anterior solicitamos el nombre de todos los usuarios cuya clave sea igual a
"River".
6 - Recuperar algunos registros (where)
Primer problema:
Trabaje con la tabla "agenda" en la que registra los datos de sus amigos.
1- Elimine "agenda"
2- Cree la tabla, con los siguientes campos: apellido (cadena de 30), nombre (cadena de 20),
domicilio (cadena de 30) y telefono (cadena de 11):
create table agenda(
apellido varchar2(30),
nombre varchar2(30),
domicilio varchar2(30),
telefono varchar2(11)
);
3- Visualice la estructura de la tabla "agenda" (4 campos)
4- Ingrese los siguientes registros ("insert into"):
insert into agenda(apellido,nombre,domicilio,telefono) values
('Acosta', 'Ana', 'Colon 123', '4234567');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Bustamante', 'Betina', 'Avellaneda 135', '4458787');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Lopez', 'Hector', 'Salta 545', '4887788');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Lopez', 'Luis', 'Urquiza 333', '4545454');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Lopez', 'Marisa', 'Urquiza 333', '4545454');
5- Seleccione todos los registros de la tabla (5 registros)
6- Seleccione el registro cuyo nombre sea "Marisa" (1 registro)
7- Seleccione los nombres y domicilios de quienes tengan apellido igual a "Lopez" (3 registros)
8- Seleccione los nombres y domicilios de quienes tengan apellido igual a "lopez" (en
minúsculas)
No aparece ningún registro, ya que la cadena "Lopez" noe s igual a la cadena "lopez".
9- Muestre el nombre de quienes tengan el teléfono "4545454" (2 registros)
Ver solución
Segundo problema:
Un comercio que vende artículos de computación registra los datos de sus artículos en una tabla
llamada "articulos".
1- Elimine la tabla si existe.
2- Cree la tabla "articulos" con la siguiente estructura:
create table articulos(
codigo number(5),
nombre varchar2(20),
descripcion varchar2(30),
precio number(7,2)
);
3- Vea la estructura de la tabla:
describe articulos;
4- Ingrese algunos registros:
insert into articulos (codigo, nombre, descripcion, precio)
values (1,'impresora','Epson Stylus C45',400.80);
insert into articulos (codigo, nombre, descripcion, precio)
values (2,'impresora','Epson Stylus C85',500);
insert into articulos (codigo, nombre, descripcion, precio)
values (3,'monitor','Samsung 14',800);
insert into articulos (codigo, nombre, descripcion, precio)
values (4,'teclado','ingles Biswal',100);
insert into articulos (codigo, nombre, descripcion, precio)
values (5,'teclado','español Biswal',90);
5- Seleccione todos los datos de los registros cuyo nombre sea "impresora" (2 registros)
6- Muestre sólo el código, descripción y precio de los teclados (2 registros)
Ver solución
7 - Operadores relacionales
Los operadores son símbolos que permiten realizar operaciones matemáticas, concatenar
cadenas, hacer comparaciones.
Oracle reconoce de 4 tipos de operadores:
1) relacionales (o de comparación)
2) aritméticos
3) de concatenación
4) lógicos
Por ahora veremos solamente los primeros.
Los operadores relacionales (o de comparación) nos permiten comparar dos expresiones, que
pueden ser variables, valores de campos, etc.
Hemos aprendido a especificar condiciones de igualdad para seleccionar registros de una tabla;
por ejemplo:
select *from libros
where autor='Borges';
Utilizamos el operador relacional de igualdad.
Los operadores relacionales vinculan un campo con un valor para que Oracle compare cada
registro (el campo especificado) con el valor dado.
Los operadores relacionales son los siguientes:
= igual
<> distinto
> mayor
< menor
>= mayor o igual
<= menor o igual
Podemos seleccionar los registros cuyo autor sea diferente de "Borges", para ello usamos la
condición:
select * from libros
where autor<>'Borges';
Podemos comparar valores numéricos. Por ejemplo, queremos mostrar los títulos y precios de los
libros cuyo precio sea mayor a 20 pesos:
select titulo, precio
from libros
where precio>20;
Queremos seleccionar los libros cuyo precio sea menor o igual a 30:
select *from libros
where precio<=30;
Los operadores relacionales comparan valores del mismo tipo. Se emplean para comprobar si un
campo cumple con una condición.
No son los únicos, existen otros que veremos mas adelante.
7 - Operadores relacionales
Primer problema:
Un comercio que vende artículos de computación registra los datos de sus artículos en una tabla
con ese nombre.
1- Elimine "articulos"
2- Cree la tabla, con la siguiente estructura:
create table articulos(
codigo number(5),
nombre varchar2(20),
descripcion varchar2(30),
precio number(6,2),
cantidad number(3)
);
3- Vea la estructura de la tabla.
4- Ingrese algunos registros:
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (1,'impresora','Epson Stylus C45',400.80,20);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (2,'impresora','Epson Stylus C85',500,30);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (3,'monitor','Samsung 14',800,10);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (4,'teclado','ingles Biswal',100,50);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (5,'teclado','español Biswal',90,50);
5- Seleccione los datos de las impresoras (2 registros)
6- Seleccione los artículos cuyo precio sea mayor o igual a 400 (3 registros)
7- Seleccione el código y nombre de los artículos cuya cantidad sea menor a 30 (2 registros)
8- Selecciones el nombre y descripción de los artículos que NO cuesten $100 (4 registros)
Ver solución
Segundo problema:
Un video club que alquila películas en video almacena la información de sus películas en alquiler
en una tabla denominada "peliculas".
1- Elimine la tabla.
drop table peliculas;
2- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table peliculas(
titulo varchar2(20),
actor varchar2(20),
duracion number(3),
cantidad number(1)
);
3- Ingrese los siguientes registros:
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible','Tom Cruise',120,3);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mision imposible 2','Tom Cruise',180,4);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Mujer bonita','Julia R.',90,1);
insert into peliculas (titulo, actor, duracion, cantidad)
values ('Elsa y Fred','China Zorrilla',80,2);
4- Seleccione las películas cuya duración no supere los 90 minutos (2 registros)
5- Seleccione el título de todas las películas en las que el actor NO sea "Tom Cruise" (2
registros)
6- Muestre todos los campos, excepto "duracion", de todas las películas de las que haya más de 2
copias (2 registros)
Ver solución
8 - Borrar registros (delete)
Para eliminar los registros de una tabla usamos el comando "delete".
Sintaxis básica:
delete from NOMBRETABLA;
Se coloca el comando delete seguido de la palabra clave "from" y el nombre de la tabla de la cual
queremos eliminar los registros. En el siguiente ejemplo se eliminan los registros de la tabla
"usuarios":
delete from usuarios;
Luego, un mensaje indica la cantidad de registros que se han eliminado.
Si no queremos eliminar todos los registros, sino solamente algunos, debemos indicar cuál o
cuáles; para ello utilizamos el comando "delete" junto con la clausula "where" con la cual
establecemos la condición que deben cumplir los registros a borrar.
Por ejemplo, queremos eliminar aquel registro cuyo nombre de usuario es "Marcelo":
delete from usuarios
where nombre='Marcelo';
Si solicitamos el borrado de un registro que no existe, es decir, ningún registro cumple con la
condición especificada, aparecerá un mensaje indicando que ningún registro fue eliminado, pues
no encontró registros con ese dato.
Tenga en cuenta que si no colocamos una condición, se eliminan todos los registros de la tabla
especificada.
8 - Borrar registros (delete)
Primer problema:
Trabaje con la tabla "agenda" que registra la información referente a sus amigos.
1- Elimine la tabla.
2- Cree la tabla con los siguientes campos: apellido (cadena de 30), nombre (cadena de 20),
domicilio (cadena de 30) y telefono (cadena de 11):
create table agenda(
apellido varchar2(30),
nombre varchar2(20),
domicilio varchar2(30),
telefono varchar2(11)
);
3- Ingrese los siguientes registros (insert into):
insert into agenda(apellido,nombre,domicilio,telefono) values
('Alvarez','Alberto','Colon 123','4234567');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Juarez','Juan','Avellaneda 135','4458787');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Lopez','Maria','Urquiza 333','4545454');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Lopez','Jose','Urquiza 333','4545454');
insert into agenda(apellido,nombre,domicilio,telefono) values
('Salas','Susana','Gral. Paz 1234','4123456');
4- Elimine el registro cuyo nombre sea "Juan" (1 registro)
5- Elimine los registros cuyo número telefónico sea igual a "4545454" (2 registros)
6- Elimine todos los registros (2 registros)
Ver solución
Segundo problema:
Un comercio que vende artículos de computación registra los datos de sus artículos en una tabla
con ese nombre.
1- Elimine "articulos"
2- Cree la tabla, con la siguiente estructura:
create table articulos(
codigo number(4,0),
nombre varchar2(20),
descripcion varchar2(30),
precio number(7,2),
cantidad number(3)
);
3- Vea la estructura de la tabla.
4- Ingrese algunos registros:
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (1,'impresora','Epson Stylus C45',400.80,20);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (2,'impresora','Epson Stylus C85',500,30);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (3,'monitor','Samsung 14',800,10);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (4,'teclado','ingles Biswal',100,50);
insert into articulos (codigo, nombre, descripcion, precio,cantidad)
values (5,'teclado','español Biswal',90,50);
5- Elimine los artículos cuyo precio sea mayor o igual a 500 (2 registros)
7- Elimine todas las impresoras (1 registro)
8- Elimine todos los artículos cuyo código sea diferente a 4 (1 registro)
Ver solución
9 - Actualizar registros (update)
Decimos que actualizamos un registro cuando modificamos alguno de sus valores.
Para modificar uno o varios datos de uno o varios registros utilizamos "update" (actualizar).
Sintaxis básica:
update NOMBRETABLA set CAMPO=NUEVOVALOR;
Utilizamos "update" junto al nombre de la tabla y "set" junto con el campo a modificar y su
nuevo valor.
El cambio afectará a todos los registros.
Por ejemplo, en nuestra tabla "usuarios", queremos cambiar los valores de todas las claves, por
"RealMadrid":
update usuarios set clave='RealMadrid';
Podemos modificar algunos registros, para ello debemos establecer condiciones de selección con
"where".
Por ejemplo, queremos cambiar el valor correspondiente a la clave de nuestro usuario llamado
"Federicolopez", queremos como nueva clave "Boca", necesitamos una condición "where" que
afecte solamente a este registro:
update usuarios set clave='Boca'
where nombre='Federicolopez';
Si Oracle no encuentra registros que cumplan con la condición del "where", un mensaje indica
que ningún registro fue modificado.
Las condiciones no son obligatorias, pero si omitimos la cláusula "where", la actualización
afectará a todos los registros.
También podemos actualizar varios campos en una sola instrucción:
update usuarios set nombre='Marceloduarte', clave='Marce'
where nombre='Marcelo';
Para ello colocamos "update", el nombre de la tabla, "set" junto al nombre del campo y el nuevo
valor y separado por coma, el otro nombre del campo con su nuevo valor.
9 - Actualizar registros (update)
Primer problema:
Trabaje con la tabla "agenda" que almacena los datos de sus amigos.
1- Elimine la tabla y créela con la siguiente estructura:
drop table agenda;
create table agenda(
apellido varchar2(30),
nombre varchar2(20),
domicilio varchar2(30),
telefono varchar2(11)
);
3- Ingrese los siguientes registros:
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Acosta','Alberto','Colon 123','4234567');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Juarez','Juan','Avellaneda 135','4458787');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Lopez','Maria','Urquiza 333','4545454');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Lopez','Jose','Urquiza 333','4545454');
insert into agenda (apellido,nombre,domicilio,telefono)
values ('Suarez','Susana','Gral. Paz 1234','4123456');
4- Modifique el registro cuyo nombre sea "Juan" por "Juan Jose" (1 registro actualizado)
5- Actualice los registros cuyo número telefónico sea igual a "4545454" por "4445566" (2
registros)
6- Actualice los registros que tengan en el campo "nombre" el valor "Juan" por "Juan Jose"
(ningún registro afectado porque ninguno cumple con la condición del "where")
Ver solución
Segundo problema:
Trabaje con la tabla "libros" de una librería.
1- Elimine la tabla y créela con los siguientes campos: titulo (cadena de 30 caracteres de
longitud), autor (cadena de 20), editorial (cadena de 15) y precio (entero no mayor a 999.99):
drop table libros;
create table libros (
titulo varchar2(30),
autor varchar2(20),
editorial varchar2(15),
precio number(5,2)
);
3- Ingrese los siguientes registros:
insert into libros (titulo, autor, editorial, precio)
values ('El aleph','Borges','Emece',25.00);
insert into libros (titulo, autor, editorial, precio)
values ('Martin Fierro','Jose Hernandez','Planeta',35.50);
insert into libros (titulo, autor, editorial, precio)
values ('Aprenda PHP','Mario Molina','Emece',45.50);
insert into libros (titulo, autor, editorial, precio)
values ('Cervantes y el quijote','Borges','Emece',25);
insert into libros (titulo, autor, editorial, precio)
values ('Matematica estas ahi','Paenza','Siglo XXI',15);
4- Muestre todos los registros (5 registros)
5- Modifique los registros cuyo autor sea igual a "Paenza", por "Adrian Paenza" (1 registro)
6- Nuevamente, modifique los registros cuyo autor sea igual a "Paenza", por "Adrian Paenza"
(ningún registro afectado porque ninguno cumple la condición)
7- Actualice el precio del libro de "Mario Molina" a 27 pesos (1 registro)
8- Actualice el valor del campo "editorial" por "Emece S.A.", para todos los registros cuya
editorial sea igual a "Emece" (3 registros)
Ver solución
10 - Comentarios
Para aclarar algunas instrucciones, en ocasiones, necesitamos agregar comentarios.
Es posible ingresar comentarios en la línea de comandos, es decir, un texto que no se ejecuta;
para ello se emplean dos guiones (--):
select *from libros;--mostramos los registros de libros
en la línea anterior, todo lo que está luego de los guiones (hacia la derecha) no se ejecuta.
Para agregar varias líneas de comentarios, se coloca una barra seguida de un asterisco (/*) al
comienzo del bloque de comentario y al finalizarlo, un asterisco seguido de una barra (*/)
select titulo, autor
/*mostramos títulos y
nombres de los autores*/
from libros;
todo lo que está entre los símbolos "/*" y "*/" no se ejecuta.
11 - Valores nulos (null)
"null' significa "dato desconocido" o "valor inexistente".
A veces, puede desconocerse o no existir el dato correspondiente a algún campo de un registro.
En estos casos decimos que el campo puede contener valores nulos.
Por ejemplo, en nuestra tabla de libros, podemos tener valores nulos en el campo "precio" porque
es posible que para algunos libros no le hayamos establecido el precio para la venta.
En contraposición, tenemos campos que no pueden estar vacíos jamás.
Veamos un ejemplo. Tenemos nuestra tabla "libros". El campo "titulo" no debería estar vacío
nunca, igualmente el campo "autor". Para ello, al crear la tabla, debemos especificar que tales
campos no admitan valores nulos:
create table libros(
titulo varchar2(30) not null,
autor varchar2(20) not null,
editorial varchar2(15) null,
precio number(5,2)
);
Para especificar que un campo NO admita valores nulos, debemos colocar "not null" luego de la
definición del campo.
En el ejemplo anterior, los campos "editorial" y "precio" si admiten valores nulos.
Cuando colocamos "null" estamos diciendo que admite valores nulos (caso del campo
"editorial"); por defecto, es decir, si no lo aclaramos, los campos permiten valores nulos (caso
del campo "precio").
Cualquier campo, de cualquier tipo de dato permite ser definido para aceptar o no valores nulos.
Un valor "null" NO es lo mismo que un valor 0 (cero) o una cadena de espacios en blanco (" ").
Si ingresamos los datos de un libro, para el cual aún no hemos definido el precio podemos
colocar "null" para mostrar que no tiene precio:
insert into libros (titulo,autor,editorial,precio)
values('El aleph','Borges','Emece',null);
Note que el valor "null" no es una cadena de caracteres, NO se coloca entre comillas.
Entonces, si un campo acepta valores nulos, podemos ingresar "null" cuando no conocemos el
valor.
También podemos colocar "null" en el campo "editorial" si desconocemos el nombre de la
editorial a la cual pertenece el libro que vamos a ingresar:
insert into libros (titulo,autor,editorial,precio)
values('Alicia en el pais','Lewis Carroll',null,25);
Una cadena vacía es interpretada por Oracle como valor nulo; por lo tanto, si ingresamos una
cadena vacía, se almacena el valor "null".
Si intentamos ingresar el valor "null" (o una cadena vacía) en campos que no admiten valores
nulos (como "titulo" o "autor"), Oracle no lo permite, muestra un mensaje y la inserción no se
realiza; por ejemplo:
insert into libros (titulo,autor,editorial,precio)
values(null,'Borges','Siglo XXI',25);
Cuando vemos la estructura de una tabla con "describe", en la columna "Null", aparece "NOT
NULL" si el campo no admite valores nulos y no aparece en caso que si los permita.
Para recuperar los registros que contengan el valor "null" en algún campo, no podemos utilizar
los operadores relacionales vistos anteriormente: = (igual) y <> (distinto); debemos utilizar los
operadores "is null" (es igual a null) y "is not null" (no es null).
Los valores nulos no se muestran, aparece el campo vacío.
Entonces, para que un campo no permita valores nulos debemos especificarlo luego de definir el
campo, agregando "not null". Por defecto, los campos permiten valores nulos, pero podemos
especificarlo igualmente agregando "null".
11 - Valores nulos (null)
Primer problema:
Una farmacia guarda información referente a sus medicamentos en una tabla llamada
"medicamentos".
1- Elimine la tabla y créela con la siguiente estructura:
drop table medicamentos;
create table medicamentos(
codigo number(5) not null,
nombre varchar2(20) not null,
laboratorio varchar2(20),
precio number(5,2),
cantidad number(3,0) not null
);
3- Visualice la estructura de la tabla "medicamentos"
note que los campos "codigo", "nombre" y "cantidad", en la columna "Null" muestra "NOT
NULL".
4- Ingrese algunos registros con valores "null" para los campos que lo admitan:
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(1,'Sertal gotas',null,null,100);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(2,'Sertal compuesto',null,8.90,150);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(3,'Buscapina','Roche',null,200);
5- Vea todos los registros.
6- Ingrese un registro con valor "0" para el precio y cadena vacía para el laboratorio.
7- Intente ingresar un registro con cadena vacía para el nombre (mensaje de error)
8- Intente ingresar un registro con valor nulo para un campo que no lo admite (aparece un
mensaje de error)
9- Ingrese un registro con una cadena de 1 espacio para el laboratorio.
10- Recupere los registros cuyo laboratorio contenga 1 espacio (1 registro)
11- Recupere los registros cuyo laboratorio sea distinto de ' '(cadena de 1 espacio) (1 registro)
Ver solución
Segundo problema:
Trabaje con la tabla que almacena los datos sobre películas, llamada "peliculas".
1- Elimine la tabla:
2- Créela con la siguiente estructura:
create table peliculas(
codigo number(4) not null,
titulo varchar2(40) not null,
actor varchar2(20),
duracion number(3)
);
3- Visualice la estructura de la tabla.
note que el campo "codigo" y "titulo", en la columna "Null" muestran "NOT NULL".
4- Ingrese los siguientes registros:
insert into peliculas (codigo,titulo,actor,duracion)
values(1,'Mision imposible','Tom Cruise',120);
insert into peliculas (codigo,titulo,actor,duracion)
values(2,'Harry Potter y la piedra filosofal',null,180);
insert into peliculas (codigo,titulo,actor,duracion)
values(3,'Harry Potter y la camara secreta','Daniel R.',null);
insert into peliculas (codigo,titulo,actor,duracion)
values(0,'Mision imposible 2','',150);
insert into peliculas (codigo,titulo,actor,duracion)
values(4,'Titanic','L. Di Caprio',220);
insert into peliculas (codigo,titulo,actor,duracion)
values(5,'Mujer bonita','R. Gere-J. Roberts',0);
5- Recupere todos los registros para ver cómo Oracle los almacenó.
6- Intente ingresar un registro con valor nulo para campos que no lo admiten (aparece un
mensaje de error)
7- Muestre todos los registros.
8- Actualice la película en cuyo campo "duracion" hay 0 por "null" (1 registro)
9- Recupere todos los registros.
Ver solución
12 - Operadores relacionales (is null)
Para recuperar los registros que contengan el valor "null" en algún campo, no podemos utilizar
los operadores relacionales vistos anteriormente: = (igual) y <> (distinto); debemos utilizar los
operadores "is null" (es igual a null) y "is not null" (no es null).
Con la siguiente sentencia recuperamos los libros que contienen valor nulo en el campo
"editorial":
select *from libros
where editorial is null;
Recuerde que los valores nulos no se muestran, aparece el campo vacío.
Las siguientes sentencias tendrán una salida diferente:
select *from libros where editorial is null;
select *from libros where editorial=' ';
Con la primera sentencia veremos los libros cuya editorial almacena el valor "null"
(desconocido); con la segunda, los libros cuya editorial guarda una cadena de 3 espacios en
blanco.
Para obtener los registros que no contienen "null", se puede emplear "is not null", esto mostrará
los registros con valores conocidos.
Para ver los libros que NO tienen valor "null" en el campo "precio" tipeamos:
select *from libros where precio is not null;
12 - Operadores relacionales (is null)
Primer problema:
Una farmacia guarda información referente a sus medicamentos en una tabla llamada
"medicamentos".
1- Elimine la tabla y créela con la siguiente estructura:
drop table medicamentos;
create table medicamentos(
codigo number(5) not null,
nombre varchar2(20) not null,
laboratorio varchar2(20),
precio number(5,2),
cantidad number(3,0) not null
);
3- Visualice la estructura de la tabla "medicamentos"
note que los campos "codigo", "nombre" y "cantidad", en la columna "Null" muestra "NOT
NULL".
4- Ingrese algunos registros con valores "null" para los campos que lo admitan:
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(1,'Sertal gotas',null,null,100);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(2,'Sertal compuesto',null,8.90,150);
insert into medicamentos (codigo,nombre,laboratorio,precio,cantidad)
values(3,'Buscapina','Roche',null,200);
5- Vea todos los registros.
6- Ingrese un registro con valor "0" para el precio y cadena vacía para el laboratorio.
7- Intente ingresar un registro con cadena vacía para el nombre (mensaje de error)
8- Intente ingresar un registro con valor nulo para un campo que no lo admite (aparece un
mensaje de error)
9- Recupere los registros que contengan valor "null" en el campo "laboratorio" (3 registros)
10- Recupere los registros que contengan valor "null" en el campo "precio", luego los que tengan
el valor 0 en el mismo campo. Note que el resultado es distinto (2 y 1 registros respectivamente)
11- Recupere los registros cuyo laboratorio no contenga valor nulo (1 registro)
12- Recupere los registros cuyo precio sea distinto de 0, luego los que sean distintos de "null" (1
y 2 resgistros respectivamente)
Note que la salida de la primera sentencia no muestra los registros con valor 0 y tampoco los que
tienen valor nulo; el resultado de la segunda sentencia muestra los registros con valor para el
campo precio (incluso el valor 0).
13- Ingrese un registro con una cadena de 1 espacio para el laboratorio.
14- Recupere los registros cuyo laboratorio sea "null" y luego los que contengan 1 espacio (3 y 1
registros respectivamente)
Note que la salida de la primera sentencia no muestra los registros con valores para el campo
"laboratorio" (un caracter espacio es un valor); el resultado de la segunda sentencia muestra los
registros con el valor " " para el campo precio.
15- Recupere los registros cuyo laboratorio sea distinto de ' '(cadena de 1 espacio), luego los que
sean distintos de "null" (1 y 2 registros respectivamente)
Note que la salida de la primera sentencia no muestra los registros con valor ' ' y tampoco los que
tienen valor nulo; el resultado de la segunda sentencia muestra los registros con valor para el
campo laboratorio (incluso el valor ' ')
Ver solución
Segundo problema:
Trabaje con la tabla que almacena los datos sobre películas, llamada "peliculas".
1- Elimine la tabla:
drop table peliculas;
2- Créela con la siguiente estructura:
create table peliculas(
codigo number(4) not null,
titulo varchar2(40) not null,
actor varchar2(20),
duracion number(3)
);
3- Visualice la estructura de la tabla. note que el campo "codigo" y "titulo", en la columna "Null"
muestran "NOT NULL".
4- Ingrese los siguientes registros:
insert into peliculas (codigo,titulo,actor,duracion)
values(1,'Mision imposible','Tom Cruise',120);
insert into peliculas (codigo,titulo,actor,duracion)
values(2,'Harry Potter y la piedra filosofal',null,180);
insert into peliculas (codigo,titulo,actor,duracion)
values(3,'Harry Potter y la camara secreta','Daniel R.',null);
insert into peliculas (codigo,titulo,actor,duracion)
values(0,'Mision imposible 2','',150);
insert into peliculas (codigo,titulo,actor,duracion)
values(4,'Titanic','L. Di Caprio',220);
insert into peliculas (codigo,titulo,actor,duracion)
values(5,'Mujer bonita','R. Gere-J. Roberts',0);
5- Recupere todos los registros para ver cómo Oracle los almacenó.
6- Intente ingresar un registro con valor nulo para campos que no lo admiten (aparece un
mensaje de error)
7- Muestre los registros con valor nulo en el campo "actor" (2 registros)
8- Actualice los registros que tengan valor de duración desconocido (nulo) por "120" (1 registro
actualizado)
9- Coloque 'Desconocido' en el campo "actor" en los registros que tengan valor nulo en dicho
campo (2 registros)
10- Muestre todos los registros
11- Muestre todos los registros con valor nulo en el campo "actor" (ninguno)
12- Actualice la película en cuyo campo "duracion" hay 0 por "null" (1 registro)
13- Recupere todos los registros.
14- Borre todos los registros en los cuales haya un valor nulo en "duracion" (1 registro)
15- Verifique que se eliminó recuperando todos los registros.
Ver solución
13 - Clave primaria (primary key)
Una clave primaria es un campo (o varios) que identifica un solo registro (fila) en una tabla.
Para un valor del campo clave existe solamente un registro.
Veamos un ejemplo, si tenemos una tabla con datos de personas, el número de documento puede
establecerse como clave primaria, es un valor que no se repite; puede haber personas con igual
apellido y nombre, incluso el mismo domicilio (padre e hijo por ejemplo), pero su documento
será siempre distinto.
Si tenemos la tabla "usuarios", el nombre de cada usuario puede establecerse como clave
primaria, es un valor que no se repite; puede haber usuarios con igual clave, pero su nombre de
usuario será siempre diferente.
Podemos establecer que un campo sea clave primaria al momento de crear la tabla o luego que
ha sido creada. Vamos a aprender a establecerla al crear la tabla. No existe una única manera de
hacerlo, por ahora veremos la sintaxis más sencilla.
Tenemos nuestra tabla "usuarios" definida con 2 campos ("nombre" y "clave").
La sintaxis básica y general es la siguiente:
create table NOMBRETABLA(
CAMPO TIPO,
...,
CAMPO TIPO,
PRIMARY KEY (CAMPO)
);
Lo que hacemos agregar, luego de la definición de cada campo, "primary key" y entre paréntesis,
el nombre del campo que será clave primaria.
En el siguiente ejemplo definimos una clave primaria, para nuestra tabla "usuarios" para
asegurarnos que cada usuario tendrá un nombre diferente y único:
create table usuarios(
nombre varchar2(20),
clave varchar2(10),
primary key(nombre)
);
Una tabla sólo puede tener una clave primaria. Cualquier campo (de cualquier tipo) puede ser
clave primaria, debe cumplir como requisito, que sus valores no se repitan ni sean nulos. Por
ello, al definir un campo como clave primaria, automáticamente Oracle lo convierte a "not null".
Luego de haber establecido un campo como clave primaria, al ingresar los registros, Oracle
controla que los valores para el campo establecido como clave primaria no estén repetidos en la
tabla; si estuviesen repetidos, muestra un mensaje y la inserción no se realiza. Es decir, si en
nuestra tabla "usuarios" ya existe un usuario con nombre "juanperez" e intentamos ingresar un
nuevo usuario con nombre "juanperez", aparece un mensaje y la instrucción "insert" no se
ejecuta.
Igualmente, si realizamos una actualización, Oracle controla que los valores para el campo
establecido como clave primaria no estén repetidos en la tabla, si lo estuviese, aparece un
mensaje indicando que se viola la clave primaria y la actualización no se realiza.
Podemos ver el campo establecido como clave primaria de una tabla realizando la siguiente
consulta:
select uc.table_name, column_name from user_cons_columns ucc
join user_constraints uc
on ucc.constraint_name=uc.constraint_name
where uc.constraint_type='P' and
uc.table_name='USUARIOS';
No explicaremos la consulta anterior por el momento, sólo la ejecutaremos; si la consulta retorna
una tabla vacía, significa que la tabla especificada no tiene clave primaria. El nombre de la tabla
DEBE ir en mayúsculas, sino Oracle no la encontrará.
13 - Clave primaria (primary key)
Primer problema:
Trabaje con la tabla "libros" de una librería.
1- Elimine la tabla:
drop table libros;
2- Créela con los siguientes campos, estableciendo como clave primaria el campo "codigo":
create table libros(
codigo number(4) not null,
titulo varchar2(40) not null,
autor varchar2(20),
editorial varchar2(15),
primary key (codigo)
);
3- Ingrese los siguientes registros:
insert into libros (codigo,titulo,autor,editorial)
values (1,'El aleph','Borges','Emece');
insert into libros (codigo,titulo,autor,editorial)
values (2,'Martin Fierro','Jose Hernandez','Planeta');
insert into libros (codigo,titulo,autor,editorial)
values (3,'Aprenda PHP','Mario Molina','Nuevo Siglo');
4- Ingrese un registro con código repetido (aparece un mensaje de error)
5- Intente ingresar el valor "null" en el campo "codigo"
6- Intente actualizar el código del libro "Martin Fierro" a "1" (mensaje de error)
7- Actualice el código del libro "Martin Fierro" a "10"
8- Vea qué campo de la tabla "LIBROS" fue establecido como clave primaria
9- Vea qué campo de la tabla "libros" (en minúsculas) fue establecido como clave primaria
La tabla aparece vacía porque Oracle no encuentra la tabla "libros", ya que almacena los
nombres de las tablas con mayúsculas.
Ver solución
Segundo problema:
Un instituto de enseñanza almacena los datos de sus estudiantes en una tabla llamada "alumnos".
1- Elimine la tabla "alumnos":
drop table alumnos;
2- Cree la tabla con la siguiente estructura intentando establecer 2 campos como clave primaria,
el campo "documento" y "legajo":
create table alumnos(
legajo varchar2(4) not null,
documento varchar2(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key(codigo),
primary key(documento)
);
Un mensaje indica la tabla solamente puede tener UNA clave primaria.
3- Cree la tabla estableciendo como clave primaria el campo "documento":
create table alumnos(
legajo varchar2(4) not null,
documento varchar2(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key(documento)
);
4- Verifique que el campo "documento" no admite valores nulos
5- Ingrese los siguientes registros:
insert into alumnos (legajo,documento,nombre,domicilio)
values('A233','22345345','Perez Mariana','Colon 234');
insert into alumnos (legajo,documento,nombre,domicilio)
values('A567','23545345','Morales Marcos','Avellaneda 348');
6- Intente ingresar un alumno con número de documento existente (no lo permite)
7- Intente ingresar un alumno con documento nulo (no lo permite)
8- Vea el campo clave primaria de "ALUMNOS".
Ver solución
14 - Vaciar la tabla (truncate table)
Aprendimos que para borrar todos los registro de una tabla se usa "delete" sin condición
"where".
También podemos eliminar todos los registros de una tabla con "truncate table". Sintaxis:
truncate table NOMBRETABLA;
Por ejemplo, queremos vaciar la tabla "libros", usamos:
truncate table libros;
La sentencia "truncate table" vacía la tabla (elimina todos los registros) y conserva la estructura
de la tabla.
La diferencia con "drop table" es que esta sentencia elimina la tabla, no solamente los registros,
"truncate table" la vacía de registros.
La diferencia con "delete" es la siguiente, al emplear "delete", Oracle guarda una copia de los
registros borrados y son recuperables, con "truncate table" no es posible la recuperación porque
se libera todo el espacio en disco ocupado por la tabla; por lo tanto, "truncate table" es más
rápido que "delete" (se nota cuando la cantidad de registros es muy grande).
15 - Tipos de datos alfanuméricos
Ya explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir los
campos y sus tipos más precisos, según el caso.
Para almacenar valores alfanuméricos (texto) usamos cadenas de caracteres.
Las cadenas se colocan entre comillas simples.
Podemos almacenar letras, símbolos y dígitos con los que no se realizan operaciones
matemáticas, por ejemplo, códigos de identificación, números de documentos, números
telefónicos. Tenemos los siguientes tipos:
1) char(x): define una cadena de caracteres de longitud fija determinada por el argumento "x". Si
se omite el argumento, por defecto coloca 1. "char" viene de character, que significa caracter en
inglés. Su rango es de 1 a 2000 caracteres.
Que sea una cadena de longitud fija significa que, si definimos un campo como "char(10)" y
almacenamos el valor "hola" (4 caracteres), Oracle rellenará las 6 posiciones restantes con
espacios, es decir, ocupará las 10 posiciones; por lo tanto, si la longitud es invariable, es
conveniente utilizar el tipo char; caso contrario, el tipo varchar2.
Si almacenamos "hola" en un campo definido "char(10)" Oracle almacenará "hola ".
2) varchar2(x): almacena cadenas de caracteres de longitud variable determinada por el
argumento "x" (obligatorio). Que sea una cadena de longitud variable significa que, si definimos
un campo como "varchar2(10)" y almacenamos el valor "hola" (4 caracteres), Oracle solamente
ocupa las 4 posiciones (4 bytes y no 10 como en el caso de "char"); por lo tanto, si la longitud es
variable, es conveniente utilizar este tipo de dato y no "char", así ocupamos menos espacio de
almacenamiento en disco. Su rango es de 1 a 4000 caracteres.
3) nchar(x): es similar a "char" excepto que permite almacenar caracteres ASCII, EBCDIC y
Unicode; su rango va de 1 a 1000 caracteres porque se emplean 2 bytes por cada caracter.
4) nvarchar2(x): es similar a "varchar2", excepto que permite almacenar caracteres Unicode; su
rango va de 1 a 2000 caracteres porque se emplean 2 bytes por cada caracter.
5 y 6) varchar(x) y char2(x): disponibles en Oracle8.
7) long: guarda caracteres de longitud variable; puede contener hasta 2000000000 caracteres (2
Gb). No admite argumento para especificar su longitud. En Oracle8 y siguientes versiones
conviene emplear "clob" y "nlob" para almacenar grandes cantidades de datos alfanuméricos.
En general se usarán los 2 primeros.
Si intentamos almacenar en un campo alfanumérico una cadena de caracteres de mayor longitud
que la definida, aparece un mensaje indicando que el valor es demasiado grande y la sentencia no
se ejecuta.
Por ejemplo, si definimos un campo de tipo varchar2(10) y le asignamos la cadena 'Aprenda
PHP' (11 caracteres), aparece un mensaje y la sentencia no se ejecuta.
Si ingresamos un valor numérico (omitiendo las comillas), lo convierte a cadena y lo ingresa
como tal.
Por ejemplo, si en un campo definido como varchar2(5) ingresamos el valor 12345, lo toma
como si hubiésemos tipeado '12345', igualmente, si ingresamos el valor 23.56, lo convierte a
'23.56'. Si el valor numérico, al ser convertido a cadena supera la longitud definida, aparece un
mensaje de error y la sentencia no se ejecuta.
Es importante elegir el tipo de dato adecuado según el caso.
Para almacenar cadenas que varían en su longitud, es decir, no todos los registros tendrán la
misma longitud en un campo determinado, se emplea "varchar2" en lugar de "char".
Por ejemplo, en campos que guardamos nombres y apellidos, no todos los nombres y apellidos
tienen la misma longitud.
Para almacenar cadenas que no varían en su longitud, es decir, todos los registros tendrán la
misma longitud en un campo determinado, se emplea "char".
Por ejemplo, definimos un campo "codigo" que constará de 5 caracteres, todos los registros
tendrán un código de 5 caracteres, ni más ni menos.
Para almacenar valores superiores a 4000 caracteres se debe emplear "long".
15 - Tipos de datos alfanuméricos
Primer problema:
Una concesionaria de autos vende autos usados y almacena los datos de los autos en una tabla
llamada "autos".
1- Elimine la tabla "autos"
2- Cree la tabla eligiendo el tipo de dato adecuado para cada campo, estableciendo el campo
"patente" como clave primaria:
create table autos(
patente char(6),
marca varchar2(20),
modelo char(4),
precio number(8,2),
primary key (patente)
);
Hemos definido el campo "patente" de tipo "char" y no "varchar2" porque la cadena de
caracteres siempre tendrá la misma longitud (6 caracteres). Lo mismo sucede con el campo
"modelo", en el cual almacenaremos el año, necesitamos 4 caracteres fijos.
3- Ingrese los siguientes registros:
insert into autos (patente,marca,modelo,precio)
values('ABC123','Fiat 128','1970',15000);
insert into autos (patente,marca,modelo,precio)
values('BCD456','Renault 11','1990',40000);
insert into autos (patente,marca,modelo,precio)
values('CDE789','Peugeot 505','1990',80000);
insert into autos (patente,marca,modelo,precio)
values('DEF012','Renault Megane','1998',95000);
4- Ingrese un registro omitiendo las comillas en el valor de "modelo"
Oracle convierte el valor a cadena.
5- Vea cómo se almacenó.
6- Seleccione todos los autos modelo "1990"
7- Intente ingresar un registro con un valor de patente de 7 caracteres
8- Intente ingresar un registro con valor de patente repetida.
Ver solución
Segundo problema:
Una empresa almacena los datos de sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes"
2- Créela eligiendo el tipo de dato más adecuado para cada campo:
create table clientes(
documento char(8) not null,
apellido varchar2(20),
nombre varchar2(20),
domicilio varchar2(30),
telefono varchar2 (11)
);
3- Analice la definición de los campos. Se utiliza char(8) para el documento porque siempre
constará de 8 caracteres. Para el número telefónico se usar "varchar2" y no un tipo numérico
porque si bien es un número, con él no se realizarán operaciones matemáticas.
4- Ingrese algunos registros:
insert into clientes (documento,apellido,nombre,domicilio,telefono)
values('22333444','Perez','Juan','Sarmiento 980','4223344');
insert into clientes (documento,apellido,nombre,domicilio,telefono)
values('23444555','Perez','Ana','Colon 234',null);
insert into clientes (documento,apellido,nombre,domicilio,telefono)
values('30444555','Garcia','Luciana','Caseros 634',null);
5- Intente ingresar un registro con más caracteres que los permitidos para el campo "telefono"
6- Intente ingresar un registro con más caracteres que los permitidos para el campo "documento"
7- Intente ingresar un registro omitiendo las comillas en el campo "apellido"
8- Seleccione todos los clientes de apellido "Perez" (2 registros)
Ver solución
16 - Tipos de datos numéricos
Ya explicamos que al crear una tabla debemos elegir la estructura adecuada, esto es, definir los
campos y sus tipos más precisos, según el caso.
Los valores numéricos no se ingresan entre comillas. Se utiliza el punto como separador de
decimales.
Para almacenar valores NUMERICOS Oracle dispone de dos tipos de datos:
1) number(t,d): para almacenar valores enteros o decimales, positivos o negativos. Su rango va
de 1.0 x 10-130 hasta 9.999...(38 nueves). Definimos campos de este tipo cuando queremos
almacenar valores numéricos con los cuales luego realizaremos operaciones matemáticas, por
ejemplo, cantidades, precios, etc.
El parámetro "t" indica el número total de dígitos (contando los decimales) que contendrá el
número como máximo (es la precisión). Su rango va de 1 a 38. El parámetro "d" indica el
máximo de dígitos decimales (escala). La escala puede ir de -84 a 127. Para definir número
enteros, se puede omitir el parámetro "d" o colocar un 0.
Un campo definido "number(5,2)" puede contener cualquier número entre -999.99 y 999.99.
Para especificar número enteros, podemos omitir el parámetro "d" o colocar el valor 0.
Si intentamos almacenar un valor mayor fuera del rango permitido al definirlo, tal valor no se
carga, aparece un mensaje indicando tal situación y la sentencia no se ejecuta.
Por ejemplo, si definimos un campo de tipo "number(4,2)" e intentamos guardar el valor 123.45,
aparece un mensaje indicando que el valor es demasiado grande para la columna. Si ingresamos
un valor con más decimales que los definidos, el valor se carga pero con la cantidad de decimales
permitidos, los dígitos sobrantes se omiten.
2) float (x): almacena un número en punto decimal. El parámetro indica la precisión binaria
máxima; con un rango de 1 a 126. Si se omite, por defecto es 126.
Para ambos tipos numéricos:
- si ingresamos un valor con más decimales que los permitidos, redondea al más cercano; por
ejemplo, si definimos "float(4,2)" e ingresamos el valor "12.686", guardará "12.69",
redondeando hacia arriba; si ingresamos el valor "12.682", guardará "12.67", redondeando hacia
abajo.
- si intentamos ingresar un valor fuera de rango, no lo acepta.
- si ingresamos una cadena, Oracle intenta convertirla a valor numérico, si dicha cadena consta
solamente de dígitos, la conversión se realiza, luego verifica si está dentro del rango, si es así, la
ingresa, sino, muestra un mensaje de error y no ejecuta la sentencia. Si la cadena contiene
caracteres que Oracle no puede convertir a valor numérico, muestra un mensaje de error y la
sentencia no se ejecuta.
Por ejemplo, definimos un campo de tipo "numberl(5,2)", si ingresamos la cadena '12.22', la
convierte al valor numérico 12.22 y la ingresa; si intentamos ingresar la cadena '1234.56', la
convierte al valor numérico 1234.56, pero como el máximo valor permitido es 999.99, muestra
un mensaje indicando que está fuera de rango. Si intentamos ingresar el valor '12y.25', Oracle no
puede realizar la conversión y muestra un mensaje de error.
16 - Tipos de datos numéricos
Primer problema:
Un banco tiene registrados las cuentas corrientes de sus clientes en una tabla llamada "cuentas".
La tabla contiene estos datos:
Número de Cuenta Documento Nombre Saldo
______________________________________________________________
1234 25666777 Pedro Perez 500000.60
2234 27888999 Juan Lopez -250000
3344 27888999 Juan Lopez 4000.50
3346 32111222 Susana Molina 1000
1- Elimine la tabla "cuentas":
drop table cuentas;
2- Cree la tabla eligiendo el tipo de dato adecuado para almacenar los datos descriptos arriba:
- Número de cuenta: entero hasta 9999, no nulo, no puede haber valores repetidos, clave
primaria;
- Documento del propietario de la cuenta: cadena de caracteres de 8 de longitud (siempre 8), no
nulo;
- Nombre del propietario de la cuenta: cadena de caracteres de 30 de longitud,
- Saldo de la cuenta: valores que no superan 999999.99
create table cuentas(
numero number(4) not null,
documento char(8),
nombre varchar2(30),
saldo number(8,2),
primary key (numero)
);
3- Ingrese los siguientes registros:
insert into cuentas(numero,documento,nombre,saldo)
values('1234','25666777','Pedro Perez',500000.60);
insert into cuentas(numero,documento,nombre,saldo)
values('2234','27888999','Juan Lopez',-250000);
insert into cuentas(numero,documento,nombre,saldo)
values('3344','27888999','Juan Lopez',4000.50);
insert into cuentas(numero,documento,nombre,saldo)
values('3346','32111222','Susana Molina',1000);
Note que hay dos cuentas, con distinto número de cuenta, de la misma persona.
4- Seleccione todos los registros cuyo saldo sea mayor a "4000" (2 registros)
5- Muestre el número de cuenta y saldo de todas las cuentas cuyo propietario sea "Juan Lopez"
(2 registros)
6- Muestre las cuentas con saldo negativo (1 registro)
7- Muestre todas las cuentas cuyo número es igual o mayor a "3000" (2 registros)
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados" que guarda los
siguientes datos: nombre, documento, sexo, domicilio, sueldobasico.
1- Elimine la tabla:
drop table empleados;
2- Cree la tabla eligiendo el tipo de dato adecuado para cada campo:
create table empleados(
nombre varchar2(30),
documento char(8),
sexo char(1),
domicilio varchar2(30),
sueldobasico numberl(7,2),--máximo estimado 99999.99
cantidadhijos number(2)--no superará los 99
);
3- Ingrese algunos registros:
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Juan Perez','22333444','m','Sarmiento 123',500,2);
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Ana Acosta','24555666','f','Colon 134',850,0);
insert into empleados
(nombre,documento,sexo,domicilio,sueldobasico,cantidadhijos)
values ('Bartolome Barrios','27888999','m','Urquiza 479',10000.80,4);
4- Ingrese un valor de "sueldobasico" con más decimales que los definidos (redondea los
decimales al valor más cercano 800.89)
5- Intente ingresar un sueldo que supere los 7 dígitos (no lo permite)
6- Muestre todos los empleados cuyo sueldo no supere los 900 pesos
7- Seleccione los nombres de los empleados que tengan hijos (3 registros)
Ver solución
17 - Ingresar algunos campos
Hemos aprendido a ingresar registros listando todos los campos y colocando valores para todos y
cada uno de ellos luego de "values".
Si ingresamos valores para todos los campos, podemos omitir la lista de nombres de los campos.
Por ejemplo, si tenemos creada la tabla "libros" con los campos "titulo", "autor" y "editorial",
podemos ingresar un registro de la siguiente manera:
insert into libros values ('Uno','Richard Bach','Planeta');
También es posible ingresar valores para algunos campos. Ingresamos valores solamente para los
campos "titulo" y "autor":
insert into libros (titulo, autor)
values ('El aleph','Borges');
Oracle almacenará el valor "null" en el campo "editorial", para el cual no hemos explicitado un
valor.
Al ingresar registros debemos tener en cuenta:
- la lista de campos debe coincidir en cantidad y tipo de valores con la lista de valores luego de
"values". Si se listan más (o menos) campos que los valores ingresados, aparece un mensaje de
error y la sentencia no se ejecuta.
- si ingresamos valores para todos los campos podemos obviar la lista de campos.
- podemos omitir valores para los campos que permitan valores nulos (se guardará "null"); si
omitimos el valor para un campo "not null", la sentencia no se ejecuta.
17 - Ingresar algunos campos
Primer problema:
Un banco tiene registrados las cuentas corrientes de sus clientes en una tabla llamada "cuentas".
1- Elimine la tabla "cuentas":
drop table cuentas;
2- Cree la tabla :
create table cuentas(
numero number(10) not null,
documento char(8) not null,
nombre varchar2(30),
saldo number(9,2)
);
3- Ingrese un registro con valores para todos sus campos, omitiendo la lista de campos.
4- Ingrese un registro omitiendo algún campo que admita valores nulos.
5- Verifique que en tal campo se almacenó "null"
6- Intente ingresar un registro listando 3 campos y colocando 4 valores. Un mensaje indica que
hay demasiados valores.
7- Intente ingresar un registro listando 3 campos y colocando 2 valores. Un mensaje indica que
no hay suficientes valores.
8- Intente ingresar un registro sin valor para un campo definido "not null".
9- Vea los registros ingresados.
Ver solución
18 - Valores por defecto (default)
Hemos visto que si al insertar registros no se especifica un valor para un campo que admite
valores nulos, se ingresa automáticamente "null". A este valor se le denomina valor por defecto o
predeterminado.
Un valor por defecto se inserta cuando no está presente al ingresar un registro.
Para campos de cualquier tipo no declarados "not null", es decir, que admiten valores nulos, el
valor por defecto es "null". Para campos declarados "not null", no existe valor por defecto, a
menos que se declare explícitamente con la cláusula "default".
Podemos establecer valores por defecto para los campos cuando creamos la tabla. Para ello
utilizamos "default" al definir el campo. Por ejemplo, queremos que el valor por defecto del
campo "autor" de la tabla "libros" sea "Desconocido" y el valor por defecto del campo "cantidad"
sea "0":
create table libros(
titulo varchar2(40) not null,
autor varchar2(30) default 'Desconocido' not null,
editorial varchar2(20),
precio number(5,2),
cantidad number(3) default 0
);
Si al ingresar un nuevo registro omitimos los valores para el campo "autor" y "cantidad", Oracle
insertará los valores por defecto; en "autor" colocará "Desconocido" y en cantidad "0".
Entonces, si al definir el campo explicitamos un valor mediante la cláusula "default", ése será el
valor por defecto.
La cláusula "default" debe ir antes de "not null" (si existiese), sino aparece un mensaje de error.
Para ver si los campos de la tabla "libros" tiene definidos valores por defecto y cuáles son,
podemos realizar la siguiente consulta:
select column_name,nullable,data_default
from user_tab_columns where TABLE_NAME = 'libros';
Muestra una fila por cada campo, en la columna "data_default" aparece el valor por defecto (si lo
tiene), en la columna "nullable" aparece "N" si el campo no está definido "not null" y "Y" si
admite valores "null".
También se puede utilizar "default" para dar el valor por defecto a los campos en sentencias
"insert", por ejemplo:
insert into libros (titulo,autor,editorial,precio,cantidad)
values ('El gato con botas',default,default,default,100);
Entonces, la cláusula "default" permite especificar el valor por defecto de un campo. Si no se
explicita, el valor por defecto es "null", siempre que el campo no haya sido declarado "not null".
Los campos para los cuales no se ingresan valores en un "insert" tomarán los valores por defecto:
- si permite valores nulos y no tiene cláusula "default", almacenará "null";
- si tiene cláusula "default" (admita o no valores nulos), el valor definido como predeterminado;
- si está declarado explícitamente "not null" y no tiene valor "default", no hay valor por defecto,
así que causará un error y el "insert" no se ejecutará.
Un campo sólo puede tener un valor por defecto. Una tabla puede tener todos sus campos con
valores por defecto. Que un campo tenga valor por defecto no significa que no admita valores
nulos, puede o no admitirlos.
Un campo definido como clave primaria acepta un valor "default", pero no tiene sentido ya que
el valor por defecto solamente podrá ingresarse una vez; si intenta ingresarse cuando otro
registro ya lo tiene almacenado, aparecerá un mensaje de error indicando que se intenta duplicar
la clave.
18 - Valores por defecto (default)
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes" algunos
datos de las personas que visitan o compran en su stand para luego enviarle publicidad de sus
productos.
1- Elimine la tabla "visitantes"
2- Cree la tabla con la siguiente estructura:
create table visitantes(
nombre varchar2(30),
edad number(2),
sexo char(1) default 'f',
domicilio varchar2(30),
ciudad varchar2(20) default 'Cordoba',
telefono varchar(11),
mail varchar(30) default 'no tiene',
montocompra number (6,2)
);
4- Analice la información que retorna la siguiente consulta:
select column_name,nullable,data_default
from user_tab_columns where TABLE_NAME = 'VISITANTES';
Todos los campos admiten valores nulos; hay 3 campos con valores predeterminados.
5- Ingrese algunos registros sin especificar valores para algunos campos para ver cómo opera la
cláusula "default":
insert into visitantes (domicilio,ciudad,telefono,mail,montocompra)
values ('Colon 123','Cordoba','4334455','juanlopez@[Link]',59.80);
insert into visitantes (nombre,edad,sexo,telefono,mail,montocompra)
values ('Marcos Torres',29,'m','4112233','marcostorres@[Link]',60);
insert into visitantes (nombre,edad,sexo,domicilio,ciudad)
values ('Susana Molina',43,'f','Bulnes 345','Carlos Paz');
6- Recupere todos los registros.
Los campos de aquellos registros para los cuales no se ingresó valor almacenaron el valor por
defecto ("null" o el especificado con "default").
7- Use la palabra "default" para ingresar valores en un "insert"
8- Recupere el registro anteriormente ingresado.
Ver solución
Segundo problema:
Una pequeña biblioteca de barrio registra los préstamos de sus libros en una tabla llamada
"prestamos". En ella almacena la siguiente información: título del libro, documento de identidad
del socio a quien se le presta el libro, fecha de préstamo, fecha en que tiene que devolver el libro
y si el libro ha sido o no devuelto.
1- Elimine la tabla "prestamos"
2- Cree la tabla:
create table prestamos(
titulo varchar2(40) not null,
documento char(8) not null,
fechaprestamo date not null,
fechadevolucion date,
devuelto char(1) default 'n'
);
3- Consulte "user_tab_columns" y analice la información.
Hay 3 campos que no admiten valores nulos y 1 solo campo con valor por defecto.
4- Ingrese algunos registros omitiendo el valor para los campos que lo admiten.
5- Seleccione todos los registros.
6- Ingrese un registro colocando "default" en los campos que lo admiten y vea cómo se
almacenó.
7- Intente ingresar un registro colocando "default" como valor para un campo que no admita
valores nulos y no tenga definido un valor por defecto.
Ver solución
19 - Operadores aritméticos y de
concatenación (columnas calculadas)
Aprendimos que los operadores son símbolos que permiten realizar distintos tipos de
operaciones.
Dijimos que Oracle tiene 4 tipos de operadores: 1) relacionales o de comparación (los vimos), 2)
aritméticos, 3) de concatenación y 4) lógicos (lo veremos más adelante).
Los operadores aritméticos permiten realizar cálculos con valores numéricos.
Son: multiplicación (*), división (/), suma (+) y resta (-).
Es posible obtener salidas en las cuales una columna sea el resultado de un cálculo y no un
campo de una tabla.
Si queremos ver los títulos, precio y cantidad de cada libro escribimos la siguiente sentencia:
select titulo,precio,cantidad
from libros;
Si queremos saber el monto total en dinero de un título podemos multiplicar el precio por la
cantidad por cada título, pero también podemos hacer que Oracle realice el cálculo y lo incluya
en una columna extra en la salida:
select titulo, precio,cantidad,
precio*cantidad
from libros;
Si queremos saber el precio de cada libro con un 10% de descuento podemos incluir en la
sentencia los siguientes cálculos:
select titulo,precio,
precio-(precio*0.1)
from libros;
También podemos actualizar los datos empleando operadores aritméticos:
update libros set precio=precio-(precio*0.1);
Para concatenar cadenas de caracteres existe el operador de concatenación ||.
Para concatenar el título y el autor de cada libro usamos el operador de concatenación ("||"):
select titulo||'-'||autor
from libros;
Note que concatenamos además un guión para separar los campos.
Oracle puede convertir automáticamente valores numéricos a cadenas para una concatenación;
por ejemplo, en el siguiente ejemplo mostramos el título y precio de cada libro concatenado con
el operador "||":
select titulo||' $'||precio
from libros;
19 - Operadores aritméticos y de
concatenación (columnas calculadas)
Primer problema:
Un comercio que vende artículos de computación registra los datos de sus artículos en una tabla
con ese nombre.
1- Elimine la tabla:
drop table articulos;
2- Cree la tabla:
create table articulos(
codigo number(4),
nombre varchar2(20),
descripcion varchar2(30),
precio number(8,2),
cantidad number(3) default 0,
primary key (codigo)
);
3- Ingrese algunos registros:
insert into articulos
values (101,'impresora','Epson Stylus C45',400.80,20);
insert into articulos
values (203,'impresora','Epson Stylus C85',500,30);
insert into articulos
values (205,'monitor','Samsung 14',800,10);
insert into articulos
values (300,'teclado','ingles Biswal',100,50);
4- El comercio quiere aumentar los precios de todos sus artículos en un 15%. Actualice todos los
precios empleando operadores aritméticos.
5- Vea el resultado.
6- Muestre todos los artículos, concatenando el nombre y la descripción de cada uno de ellos
separados por coma.
7- Reste a la cantidad de todas las impresoras, el valor 5, empleando el operador aritmético
menos ("-")
8- Recupere todos los datos de las impresoras para verificar que la actualización se realizó.
9- Muestre todos los artículos concatenado los campos para que aparezcan de la siguiente manera
"Cod. 101: impresora Epson Stylus C45 $460,92 (15)"
Ver solución
20 - Alias (encabezados de columnas)
Una manera de hacer más comprensible el resultado de una consulta consiste en cambiar los
encabezados de las columnas. Por ejemplo, tenemos la tabla "libros" con un campo "cantidad"
(entre otros) en el cual se almacena la cantidad de libros en stock; queremos que al mostrar la
información de dicha tabla aparezca como encabezado del campo "cantidad" el texto "stock",
para ello colocamos un alias de la siguiente manera:
select titulo,
cantidad as stock,
precio
from libros;
Para reemplazar el nombre de un campo del encabezado por otro, se coloca la palabra clave "as"
seguido del texto del encabezado.
Si el alias consta de una sola cadena las comillas no son necesarias, pero si contiene más de una
palabra, es necesario colocarla entre comillas dobles:
select titulo,
cantidad as "stock disponible",
precio
from libros;
También se puede crear un alias para columnas calculadas. Por ejemplo:
select titulo,precio,
precio*0.1 as descuento,
precio-(precio*0.1) as "preciofinal"
from libros;
La palabra clave "as" es opcional, pero es conveniente usarla.
Entonces, un "alias" se usa como nombre de un campo o de una expresión. En estos casos, son
opcionales, sirven para hacer más comprensible el resultado.
20 - Alias (encabezados de columnas)
Primer problema:
Un comercio que vende artículos de computación registra los datos de sus artículos en una tabla
con ese nombre.
1- Elimine la tabla:
drop table articulos;
2- Cree la tabla:
create table articulos(
codigo number(4),
nombre varchar2(20),
descripcion varchar2(30),
precio number(8,2),
cantidad number(3) default 0,
primary key (codigo)
);
3- Ingrese algunos registros:
insert into articulos
values (101,'impresora','Epson Stylus C45',400.80,20);
insert into articulos
values (203,'impresora','Epson Stylus C85',500,30);
insert into articulos
values (205,'monitor','Samsung 14',800,10);
insert into articulos
values (300,'teclado','ingles Biswal',100,50);
4- El comercio hace un descuento del 15% en ventas mayoristas. Necesitamos recuperar el
código, nombre, decripción de todos los artículos con una columna extra que muestre el precio
de cada artículo para la venta mayorista con el siguiente encabezado "precio mayorista"
5- Muestre los precios de todos los artículos, concatenando el nombre y la descripción con el
encabezado "artículo" (sin emplear "as" ni comillas)
6- Muestre todos los campos de los artículos y un campo extra, con el encabezado "monto total"
en la que calcule el monto total en dinero de cada artículo (precio por cantidad)
7- Muestre la descripción de todas las impresoras junto al precio con un 20% de recargo con un
encabezado que lo especifique.
Ver solución
21 - Funciones string
Las funciones de manejo de caracteres alfanuméricos aceptan argumentos de tipo caracter y
retornan caracteres o valores numéricos.
Las siguientes son algunas de las funciones que ofrece Oracle para trabajar con cadenas de
caracteres:
- chr(x): retorna un caracter equivalente al código enviado como argumento "x". Ejemplo:
select chr(65) from dual;-- retorna 'A'.
select chr(100) from dual;-- retorna 'd'.
- concat(cadena1,cadena2): concatena dos cadenas de caracteres; es equivalente al operador ||.
Ejemplo:
select concat('Buenas',' tardes') from dual;--retorna 'Buenas tardes'.
- initcap(cadena): retorna la cadena enviada como argumento con la primera letra (letra capital)
de cada palabra en mayúscula. Ejemplo:
select initcap('buenas tardes alumno') from dual;--retorna 'Buenas Tardes
Alumno'.
- lower(cadena): retorna la cadena enviada como argumento en minúsculas. "lower" significa
reducir en inglés. Ejemplo:
select lower('Buenas tardes ALUMNO') from dual;--retorna "buenas tardes
alumno".
- upper(cadena): retorna la cadena con todos los caracteres en mayúsculas. Ejemplo:
select upper('[Link]') from dual;-- '[Link]'
- lpad(cadena,longitud,cadenarelleno): retorna la cantidad de caracteres especificados por el
argumento "longitud", de la cadena enviada como primer argumento (comenzando desde el
primer caracter); si "longitud" es mayor que el tamaño de la cadena enviada, rellena los espacios
restantes con la cadena enviada como tercer argumento (en caso de omitir el tercer argumento
rellena con espacios); el relleno comienza desde la izquierda. Ejemplos:
select lpad('alumno',10,'xyz') from dual;-- retorna 'xyzxalumno'
select lpad('alumno',4,'xyz') from dual;-- retorna 'alum'
- rpad(cadena,longitud,cadenarelleno): retorna la cantidad de caracteres especificados por el
argumento "longitud", de la cadena enviada como primer argumento (comenzando desde el
primer caracter); si "longitud" es mayor que el tamaño de la cadena enviada, rellena los espacios
restantes con la cadena enviada como tercer argumento (en caso de omitir el tercer argumento
rellena con espacios); el relleno comienza desde la derecha (último caracter). Ejemplos:
select rpad('alumno',10,'xyz') from dual;-- retorna 'alumnoxyzx'
select rpad('alumno',4,'xyz') from dual;-- retorna 'alum'
- ltrim(cadena1,cadena2): borra todas las ocurrencias de "cadena2" en "cadena1", si se
encuentran al comienzo; si se omite el segundo argumento, se eliminan los espacios. Ejemplo:
select ltrim('la casa de la cuadra','la') from dual;-- ' casa de la cuadra'
select ltrim(' es la casa de la cuadra','la') from dual;-- no elimina ningún
caracter
select ltrim(' la casa') from dual;-- 'la casa'
- rtrim(cadena1,cadena2): borra todas las ocurrencias de "cadena2" en "cadena1", si se
encuentran por la derecha (al final de la cadena); si se omite el segundo argumento, se borran los
espacios. Ejemplo:
select rtrim('la casa lila','la') from dual;-- 'la casa li'
select rtrim('la casa lila ','la') from dual;-- no borra ningún caracter
select rtrim('la casa lila ') from dual; --'la casa lila'
- trim(cadena): retorna la cadena con los espacios de la izquierda y derecha eliminados. "Trim"
significa recortar. Ejemplo:
select trim(' oracle ') from dual;--'oracle'
- replace(cadena,subcade1,subcade2): retorna la cadena con todas las ocurrencias de la
subcadena de reemplazo (subcade2) por la subcadena a reemplazar (subcae1). Ejemplo:
select replace('[Link]','x','w') from dual;
retorna "[Link]'.
- substr(cadena,inicio,longitud): devuelve una parte de la cadena especificada como primer
argumento, empezando desde la posición especificada por el segundo argumento y de tantos
caracteres de longitud como indica el tercer argumento. Ejemplo:
select substr('[Link]',1,10) from dual;-- '[Link]'
select substr('[Link]',5,6) from dual;-- 'oracle'
- length(cadena): retorna la longitud de la cadena enviada como argumento. "lenght" significa
longitud en inglés. Ejemplo:
select length('[Link]') from dual;-- devuelve 14.
- instr (cadena,subcadena): devuelve la posición de comienzo (de la primera ocurrencia) de la
subcadena especificada en la cadena enviada como primer argumento. Si no la encuentra retorna
0. Ejemplos:
select instr('Jorge Luis Borges','or') from dual;-- 2
select instr('Jorge Luis Borges','ar') from dual;-- 0, no se encuentra
- translate(): reemplaza cada ocurrencia de una serie de caracteres con otra serie de acracteres. La
diferencia con "replace" es que aquella trabaja con cadenas de caracteres y reemplaza una cadena
completa por otra, en cambio "translate" trabaja con caracteres simples y reemplaza varios. En el
siguiente ejemplo se especifica que se reemplacen todos los caracteres "O" por el caracter "0",
todos los caracteres "S" por el caracter "5" y todos los caracteres "G" por "6":
select translate('JORGE LUIS BORGES','OSG','056') from dual;--'J0R6E LUI5
B0R6E5'
Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
caracter.
22 - Funciones matemáticas.
Las funciones matemáticas realizan operaciones con expresiones numéricas y retornan un
resultado, operan con tipos de datos numéricos.
Las funciones numéricas aceptan parámetros de entrada de tipo numérico y retornan valores
numéricos.
Oracle tiene algunas funciones para trabajar con números. Aquí presentamos algunas.
- abs(x): retorna el valor absoluto del argumento "x". Ejemplo:
select abs(-20) from dual;--retorna 20.
La tabla dual es una tabla virtual que existe en todas las Bases de datos Oracle.
- ceil(x): redondea a entero, hacia arriba, el argumento "x". Ejemplo:
select ceil(12.34) from dual;--retorna 13.
- floor(x): redondea a entero, hacia abajo, el argumento "x". Ejemplo:
select floor(12.34) from dual; --12
- mod(x,y): devuelve el resto de la división x/y. Ejemplos:
select mod(10,3) from dual;--retorna 1.
select mod(10,2) from dual;--retorna 0.
- power(x,y): retorna el valor de "x" elevado a la "y" potencia. Ejemplo:
select power(2,3) from dual;--retorna 8.
- round(n,d): retorna "n" redondeado a "d" decimales; si se omite el segundo argumento,
redondea todos los decimales. Si el segundo argumento es positivo, el número de decimales es
redondeado según "d"; si es negativo, el número es redondeado desde la parte entera según el
valor de "d". Ejemplos:
select round(123.456,2) from dual;-- retorna "123.46", es decir, redondea
desde el segundo decimal.
select round(123.456,1) from dual;-- 123.5, es decir, redondea desde el
primer decimal.
select round(123.456,-1) from dual;-- 120, redondea desde el primer valor
entero (hacia la izquierda).
select round(123.456,-2) from dual;-- 100, redondea desde el segundo valor
entero (hacia la izquierda).
select round(123.456) from dual;-- 123.
- sign(x): si el argumento es un valor positivo, retorna 1, si es negativo, devuelve -1 y 0 si es 0.
Ejemplo:
select sign(-120) from dual;--retorna -1
select sign(120) from dual;--retorna 1
- trunc(n,d): trunca un número a la cantidad de decimales especificada por el segundo argumento.
Si se omite el segundo argumento, se truncan todos los decimales. Si "d" es negativo, el número
es truncado desde la parte entera. Ejemplo:
select trunc(1234.5678,2) from dual;--retorna 1234.56
select trunc(1234.5678,-2) from dual;--retorna 1200
select trunc(1234.5678,-1) from dual;--retorna 1230
select trunc(1234.5678) from dual;--retorna 1234
- sqrt(x): devuelve la raiz cuadrada del valor enviado como argumento. Ejemplo:
select sqrt(9) from dual;--retorna 3
Oracle dispone de funciones trigonométricas que retornan radianes, calculan seno, coseno,
inversas, etc.: acos, asin, atan, atan2, cos, cosh, exp, ln, log, sin, sinh, tan, tanh. No las veremos
en detalle.
Se pueden emplear las funciones matemáticas enviando como argumento el nombre de un campo
de tipo numérico.
23 - Funciones de fechas y horas
Oracle dispone de varias funciones que operan con tipos de datos "date". Estas son algunas:
- add_months(f,n): agrega a una fecha, un número de meses. Si el segundo argumento es
positivo, se le suma a la fecha enviada tal cantidad de meses; si es negativo, se le resta a la fecha
enviada tal cantidad de meses. Ejemplo:
select add_months('10/06/2007',5) from dual; --retorna "10/11/07"
select add_months('10/06/2007',-5) from dual; --retorna "10/01/07"
select add_months('30/01/2007',1) from dual;-- retorna "25/02/07" ya que es
el último día de ese mes.
- last_day(f): retorna el ultimo día de mes de la fecha enviada como argumento. Ejemplo:
select last_day('10/02/2007') from dual;-- "28/02/07"
select last_day('10/08/2007') from dual;-- "31/08/07"
- months_between(f1,f2): retorna el numero de meses entre las fechas enviadas como argumento.
Ejemplo:
select months_between('19/05/2003','21/06/05') from dual;-- retorna
- next_day(fecha,dia): retorna una fecha correspondiente al primer día especificado en "dia"
luego de la fecha especificada. En el siguiente ejemplo se busca el lunes siguiente a la fecha
especificada:
select next_day('10/08/2007','LUNES') from dual;
- current_date: retorna la fecha actual. Ejemplo:
select current_date from dual;
- current_timestamp: retorna la fecha actual
select current_timestamp from dual;
Retorna: 10/08/07 09:59:44,109000000 AMERICA/BUENOS_AIRES
- sysdate: retorna la fecha y hora actuales en el servidor de Oracle.
-systimestamp: retorna fecha y hora actuales.
select systimestamp from dual;
Retorna 10/08/07 10:33:48,984000000 -03:00
- to_date: convierte una cadena a tipo de dato "date". Ejemplo:
select to_date ('05-SEP-2007 10:00 AM','DD-MON-YYYY HH:MI AM') from dual;
Retorna 05/09/07
- to_char: convierte una fecha a cadena de caracteres. Ejemplo:
select to_char('10/10/2007')from dual;
- extract(parte,fecha): retorna la parte (especificada por el primer argumento) de una fecha.
Puede extraer el año (year), mes (month), día (day), hora (hour), minuto (minute), segundo
(second), etc. Ejemplo:
select extract(month from sysdate) from dual;
retorna el número mes de la fecha actual.
En Oracle: Los operadores aritméticos "+" (más) y "-" (menos) pueden emplearse con fechas.
Por ejemplos:
select sysdate-3:
Retorna 3 días antes de la fecha actual.
select to_date('15/12/2007')-5 from dual;
Retorna 10/12/07
Se pueden emplear estas funciones enviando como argumento el nombre de un campo de tipo
date.
24 - Ordenar registros (order by)
Podemos ordenar el resultado de un "select" para que los registros se muestren ordenados por
algún campo, para ello usamos la cláusula "order by".
La sintaxis básica es la siguiente:
select *from NOMBRETABLA
order by CAMPO;
Por ejemplo, recuperamos los registros de la tabla "libros" ordenados por el título:
select *from libros
order by titulo;
Aparecen los registros ordenados alfabéticamente por el campo especificado.
También podemos colocar el número de orden del campo por el que queremos que se ordene en
lugar de su nombre, es decir, referenciar a los campos por su posición en la lista de selección.
Por ejemplo, queremos el resultado del "select" ordenado por "precio":
select titulo,autor,precio
from libros order by 3;
Si colocamos un número mayor a la cantidad de campos de la lista de selección, aparece un
mensaje de error y la sentencia no se ejecuta.
Por defecto, si no aclaramos en la sentencia, los ordena de manera ascendente (de menor a
mayor). Podemos ordenarlos de mayor a menor, para ello agregamos la palabra clave "desc":
select *libros
order by editorial desc;
También podemos ordenar por varios campos, por ejemplo, por "titulo" y "editorial":
select *from libros
order by titulo,editorial;
Incluso, podemos ordenar en distintos sentidos, por ejemplo, por "titulo" en sentido ascendente y
"editorial" en sentido descendente:
select *from libros
order by titulo asc, editorial desc;
Debe aclararse al lado de cada campo, pues estas palabras claves afectan al campo
inmediatamente anterior.
Es posible ordenar por un campo que no se lista en la selección incluso por columnas calculados.
Se puede emplear "order by" con campos de tipo caracter, numérico y date.
24 - Ordenar registros (order by)
Primer problema:
En una página web se guardan los siguientes datos de las visitas: nombre, mail, pais y fecha.
1- Elimine la tabla "visitas" y créela con la siguiente estructura:
drop table visitas;
create table visitas (
nombre varchar2(30) default 'Anonimo',
mail varchar2(50),
pais varchar2(20),
fecha date
);
3- Ingrese algunos registros:
insert into visitas values ('Ana Maria
Lopez','AnaMaria@[Link]','Argentina','10/10/2006 10:10');
insert into visitas values ('Gustavo
Gonzalez','GustavoGGonzalez@[Link]','Chile','10/10/2006 21:30');
insert into visitas values
('Juancito','JuanJosePerez@[Link]','Argentina','11/10/2006 15:45');
insert into visitas values ('Fabiola
Martinez','MartinezFabiola@[Link]','Mexico','12/10/2006 08:15');
insert into visitas values ('Fabiola
Martinez','MartinezFabiola@[Link]','Mexico','12/09/2006 20:45');
insert into visitas values
('Juancito','JuanJosePerez@[Link]','Argentina','12/09/2006 16:20');
insert into visitas values
('Juancito','JuanJosePerez@[Link]','Argentina','15/09/2006 16:25');
4- Ordene los registros por fecha, en orden descendente.
5- Muestre el nombre del usuario, pais y el mes, ordenado por pais (ascendente) y el mes
(descendente)
6- Muestre los mail, país, ordenado por país, de todos los que visitaron la página en octubre (4
registros)
Ver solución
25 - Operadores lógicos (and - or - not)
Hasta el momento, hemos aprendido a establecer una condición con "where" utilizando
operadores relacionales. Podemos establecer más de una condición con la cláusula "where", para
ello aprenderemos los operadores lógicos.
Son los siguientes:
- and, significa "y",
- or, significa "y/o",
- not, significa "no", invierte el resultado
- (), paréntesis
Los operadores lógicos se usan para combinar condiciones.
Si queremos recuperar todos los libros cuyo autor sea igual a "Borges" y cuyo precio no supere
los 20 pesos, necesitamos 2 condiciones:
select *from libros
where (autor='Borges') and
(precio<=20);
Los registros recuperados en una sentencia que une dos condiciones con el operador "and",
cumplen con las 2 condiciones.
Queremos ver los libros cuyo autor sea "Borges" y/o cuya editorial sea "Planeta":
select *from libros
where autor='Borges' or
editorial='Planeta';
En la sentencia anterior usamos el operador "or"; indicamos que recupere los libros en los cuales
el valor del campo "autor" sea "Borges" y/o el valor del campo "editorial" sea "Planeta", es decir,
seleccionará los registros que cumplan con la primera condición, con la segunda condición y con
ambas condiciones.
Los registros recuperados con una sentencia que une dos condiciones con el operador "or",
cumplen una de las condiciones o ambas.
Queremos recuperar los libros que NO cumplan la condición dada, por ejemplo, aquellos cuya
editorial NO sea "Planeta":
select *from libros
where not editorial='Planeta';
El operador "not" invierte el resultado de la condición a la cual antecede.
Los registros recuperados en una sentencia en la cual aparece el operador "not", no cumplen con
la condición a la cual afecta el "NOT".
Los paréntesis se usan para encerrar condiciones, para que se evalúen como una sola expresión.
Cuando explicitamos varias condiciones con diferentes operadores lógicos (combinamos "and",
"or") permite establecer el orden de prioridad de la evaluación; además permite diferenciar las
expresiones más claramente.
Por ejemplo, las siguientes expresiones devuelven un resultado diferente:
select *from libros
where (autor='Borges') or
(editorial='Paidos' and precio<20);
select *from libros
where (autor='Borges' or editorial='Paidos') and
(precio<20);
Si bien los paréntesis no son obligatorios en todos los casos, se recomienda utilizarlos para evitar
confusiones.
El orden de prioridad de los operadores lógicos es el siguiente: "not" se aplica antes que "and" y
"and" antes que "or", si no se especifica un orden de evaluación mediante el uso de paréntesis. El
orden en el que se evalúan los operadores con igual nivel de precedencia es indefinido, por ello
se recomienda usar los paréntesis.
Entonces, para establecer más de una condición en un "where" es necesario emplear operadores
lógicos. "and" significa "y", indica que se cumplan ambas condiciones; "or" significa "y/o",
indica que se cumpla una u otra condición (o ambas); "not" significa "no.", indica que no se
cumpla la condición especificada.
25 - Operadores lógicos (and - or - not)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Elimine la tabla y créela con la siguiente estructura:
drop table medicamentos;
create table medicamentos(
codigo number(5),
nombre varchar2(20),
laboratorio varchar2(20),
precio number(5,2),
cantidad number(3),
primary key(codigo)
);
3- Ingrese algunos registros:
insert into medicamentos values(100,'Sertal','Roche',5.2,100);
insert into medicamentos values(102,'Buscapina','Roche',4.10,200);
insert into medicamentos values(205,'Amoxidal 500','Bayer',15.60,100);
insert into medicamentos values(230,'Paracetamol 500','Bago',1.90,200);
insert into medicamentos values(345,'Bayaspirina','Bayer',2.10,150);
insert into medicamentos values(347,'Amoxidal jarabe','Bayer',5.10,250);
4- Recupere los códigos y nombres de los medicamentos cuyo laboratorio sea "Roche' y cuyo
precio sea menor a 5 (1 registro cumple con ambas condiciones)
5- Recupere los medicamentos cuyo laboratorio sea "Roche" o cuyo precio sea menor a 5 (4
registros)
6- Muestre todos los medicamentos cuyo laboratorio NO sea "Bayer" y cuya cantidad sea=100.
Luego muestre todos los medicamentos cuyo laboratorio sea "Bayer" y cuya cantidad NO
sea=100
7- Recupere los nombres de los medicamentos cuyo precio esté entre 2 y 5 inclusive (2 registros)
8- Elimine todos los registros cuyo laboratorio sea igual a "Bayer" y su precio sea mayor a 10 (1
registro eliminado)
9- Cambie la cantidad por 200, de todos los medicamentos de "Roche" cuyo precio sea mayor a 5
(1 registro afectado)
10- Muestre todos los registros para verificar el cambio.
11- Borre los medicamentos cuyo laboratorio sea "Bayer" o cuyo precio sea menor a 3 (3
registros borrados)
Ver solución
Segundo problema:
Trabajamos con la tabla "peliculas" de un video club que alquila películas en video.
1- Elimine la tabla y créela con la siguiente estructura:
drop table peliculas;
create table peliculas(
codigo number(4),
titulo varchar2(40) not null,
actor varchar2(20),
duracion number(3),
primary key (codigo)
);
3- Ingrese algunos registros:
insert into peliculas
values(1020,'Mision imposible','Tom Cruise',120);
insert into peliculas
values(1021,'Harry Potter y la piedra filosofal','Daniel R.',180);
insert into peliculas
values(1022,'Harry Potter y la camara secreta','Daniel R.',190);
insert into peliculas
values(1200,'Mision imposible 2','Tom Cruise',120);
insert into peliculas
values(1234,'Mujer bonita','Richard Gere',120);
insert into peliculas
values(900,'Tootsie','D. Hoffman',90);
insert into peliculas
values(1300,'Un oso rojo','Julio Chavez',100);
insert into peliculas
values(1301,'Elsa y Fred','China Zorrilla',110);
4- Recupere los registros cuyo actor sea "Tom Cruise" o "Richard Gere" (3 registros)
5- Recupere los registros cuyo actor sea "Tom Cruise" y duración menor a 100 (ninguno cumple
ambas condiciones)
6- Recupere los nombres de las películas cuya duración se encuentre entre 100 y 120 minutos(5
registros)
7- Cambie la duración a 200, de las películas cuyo actor sea "Daniel R." y cuya duración sea 180
(1 registro afectado)
8- Recupere todos los registros para verificar la actualización anterior
9- Borre todas las películas donde el actor NO sea "Tom Cruise" y cuya duración sea mayor o
igual a 100 (2 registros eliminados)
Ver solución
26 - Otros operadores relacionales (between)
Hemos visto los operadores relacionales: = (igual), <> (distinto), > (mayor), < (menor), >=
(mayor o igual), <= (menor o igual), is null/is not null (si un valor es NULL o no).
Otro operador relacional es "between", trabajan con intervalos de valores.
Hasta ahora, para recuperar de la tabla "libros" los libros con precio mayor o igual a 20 y menor
o igual a 40, usamos 2 condiciones unidas por el operador lógico "and":
select *from libros
where precio>=20 and
precio<=40;
Podemos usar "between" y así simplificar la consulta:
select *from libros
where precio between 20 and 40;
Averiguamos si el valor de un campo dado (precio) está entre los valores mínimo y máximo
especificados (20 y 40 respectivamente).
"between" significa "entre". Trabaja con intervalo de valores.
Este operador no tiene en cuenta los valores "null".
Si agregamos el operador "not" antes de "between" el resultado se invierte, es decir, se recuperan
los registros que están fuera del intervalo especificado. Por ejemplo, recuperamos los libros cuyo
precio NO se encuentre entre 20 y 30, es decir, los menores a 20 y mayores a 30:
select *from libros
where precio not between 20 and 30;
Podemos especificar un intervalo de valores de tipo fecha con "between":
select *from libros
where edicion between '01/05/2000' and '01/05/2007';
Entonces, empleamos el operador "between" para reducir las condiciones "where".
26 - Otros operadores relacionales
(between)
Primer problema:
En una página web se guardan los siguientes datos de las visitas: número de visita, nombre, mail,
pais, fechayhora de la visita.
1- Elimine la tabla "visitas" y créela con la siguiente estructura:
drop table visitas;
create table visitas (
nombre varchar2(30) default 'Anonimo',
mail varchar2(50),
pais varchar2(20),
fecha date
);
2- Ingrese algunos registros:
insert into visitas
values ('Ana Maria Lopez','AnaMaria@[Link]','Argentina','10/10/2006');
insert into visitas
values ('Gustavo
Gonzalez','GustavoGGonzalez@[Link]','Chile','10/10/2006');
insert into visitas
values ('Juancito','JuanJosePerez@[Link]','Argentina','11/10/2006');
insert into visitas
values ('Fabiola
Martinez','MartinezFabiola@[Link]','Mexico','12/10/2006');
insert into visitas
values ('Fabiola
Martinez','MartinezFabiola@[Link]','Mexico','12/09/2006');
insert into visitas
values ('Juancito','JuanJosePerez@[Link]','Argentina','12/09/2006');
insert into visitas
values ('Juancito','JuanJosePerez@[Link]','Argentina','15/09/2006');
insert into visitas
values ('Federico1','federicogarcia@[Link]','Argentina',null);
3- Seleccione los usuarios que visitaron la página entre el '12/09/2006' y '11/10/2006' (6
registros)
Note que incluye los de fecha mayor o igual al valor mínimo y menores o iguales al valor
máximo, y que los valores nulos no se incluyen.
Ver solución
Segundo problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Elimine la tabla y créela con la siguiente estructura:
drop table medicamentos;
create table medicamentos(
codigo number(6) not null,
nombre varchar2(20),
laboratorio varchar2(20),
precio number(6,2),
cantidad number(4),
fechavencimiento date not null,
primary key(codigo)
);
2- Ingrese algunos registros:
insert into medicamentos
values(102,'Sertal','Roche',5.2,10,'01/02/2010');
insert into medicamentos
values(120,'Buscapina','Roche',4.10,200,'01/12/2007');
insert into medicamentos
values(230,'Amoxidal 500','Bayer',15.60,100,'28/12/2007');
insert into medicamentos
values(250,'Paracetamol 500','Bago',1.90,20,'01/02/2008');
insert into medicamentos
values(350,'Bayaspirina','Bayer',2.10,150,'01/12/2009');
insert into medicamentos
values(456,'Amoxidal jarabe','Bayer',5.10,250,'01/10/2010');
3- Recupere los nombres y precios de los medicamentos cuyo precio esté entre 5 y 15 (2
registros)
4- Seleccione los registros cuya cantidad se encuentre entre 100 y 200 (3 registros)
5- Recupere los remedios cuyo vencimiento se encuentre entre la fecha actual y '01/01/2008'
inclusive (2 registros)
6- Elimine los remedios cuyo vencimiento se encuentre entre el año 2007 y 2008 inclusive (3
registros)
Ver solución
27 - Otros operadores relacionales (in)
Se utiliza "in" para averiguar si el valor de un campo está incluido en una lista de valores
especificada.
En la siguiente sentencia usamos "in" para averiguar si el valor del campo autor está incluido en
la lista de valores especificada (en este caso, 2 cadenas).
Hasta ahora, para recuperar los libros cuyo autor sea 'Paenza' o 'Borges' usábamos 2 condiciones:
select *from libros
where autor='Borges' or autor='Paenza';
Podemos usar "in" y simplificar la consulta:
select *from libros
where autor in('Borges','Paenza');
Para recuperar los libros cuyo autor no sea 'Paenza' ni 'Borges' usábamos:
select *from libros
where autor<>'Borges' and
autor<>'Paenza';
También podemos usar "in" anteponiendo "not":
select *from libros
where autor not in ('Borges','Paenza');
Empleando "in" averiguamos si el valor del campo está incluido en la lista de valores
especificada; con "not" antecediendo la condición, invertimos el resultado, es decir, recuperamos
los valores que no se encuentran (no coinciden) con la lista de valores.
Los valores "null" no se consideran.
27 - Otros operadores relacionales (in)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Elimine la tabla y créela con la siguiente estructura:
drop table medicamentos;
create table medicamentos(
codigo number(5),
nombre varchar2(20),
laboratorio varchar2(20),
precio number(6,2),
cantidad number(3) not null,
fechavencimiento date not null,
primary key(codigo)
);
3- Ingrese algunos registros:
insert into medicamentos
values(100,'Sertal','Roche',5.2,1,'01/02/2005');
insert into medicamentos
values(230,'Buscapina',null,4.10,3,'01/03/2006');
insert into medicamentos
values(280,'Amoxidal 500','Bayer',15.60,100,'01/05/2007');
insert into medicamentos
values(301,'Paracetamol 500','Bago',1.90,10,'01/02/2008');
insert into medicamentos
values(400,'Bayaspirina','Bayer',2.10,150,'01/08/2009');
insert into medicamentos
values(560,'Amoxidal jarabe','Bayer',5.10,250,'01/10/2010');
4- Recupere los nombres y precios de los medicamentos cuyo laboratorio sea "Bayer" o "Bago"
empleando el operador "in" (4 registros)
5- Recupere los nombres y precios de los medicamentos cuyo laboratorio NO sea "Bayer" o
"Bago" empleando el operador "in" (1 registro)
Note que los valores nulos no se incluyen.
6- Seleccione los remedios cuya cantidad se encuentre entre 1 y 5 empleando el operador
"between" y luego el operador "in" (2 registros)
Note que es más conveniente emplear, en este caso, el operador "between", simplifica la
consulta.
7- Recupere los registros cuyas fechas de vencimiento se encuentra entre enero de 2005 y enero
del 2007 (emplee el operador apropiado) (2 registros)
8- Recupere los registros cuyo año de vencimiento sea 2005 o 2006 (emplee el operador
apropiado) (2 registros)
Ver solución
28 - Búsqueda de patrones (like - not like)
Existe un operador relacional que se usa para realizar comparaciones exclusivamente de cadenas,
"like" y "not like".
Hemos realizado consultas utilizando operadores relacionales para comparar cadenas. Por
ejemplo, sabemos recuperar los libros cuyo autor sea igual a la cadena "Borges":
select *from libros
where autor='Borges';
El operador igual ("=") nos permite comparar cadenas de caracteres, pero al realizar la
comparación, busca coincidencias de cadenas completas, realiza una búsqueda exacta.
Imaginemos que tenemos registrados estos 2 libros:
"El Aleph", "Borges";
"Antologia poetica", "J.L. Borges";
Si queremos recuperar todos los libros de "Borges" y especificamos la siguiente condición:
select *from libros
where autor='Borges';
sólo aparecerá el primer registro, ya que la cadena "Borges" no es igual a la cadena "J.L.
Borges".
Esto sucede porque el operador "=" (igual), también el operador "<>" (distinto) comparan
cadenas de caracteres completas. Para comparar porciones de cadenas utilizamos los operadores
"like" y "not like".
Entonces, podemos comparar trozos de cadenas de caracteres para realizar consultas. Para
recuperar todos los registros cuyo autor contenga la cadena "Borges" debemos tipear:
select *from libros
where autor like "%Borges%";
El símbolo "%" (porcentaje) reemplaza cualquier cantidad de caracteres (incluyendo ningún
caracter). Es un caracter comodín. "like" y "not like" son operadores de comparación que señalan
igualdad o diferencia.
Para seleccionar todos los libros que comiencen con "M":
select *from libros
where titulo like 'M%';
Note que el símbolo "%" ya no está al comienzo, con esto indicamos que el título debe tener
como primera letra la "M" y luego, cualquier cantidad de caracteres.
Para seleccionar todos los libros que NO comiencen con "M":
select *from libros
where titulo not like 'M%';
Así como "%" reemplaza cualquier cantidad de caracteres, el guión bajo "_" reemplaza un
caracter, es otro caracter comodín. Por ejemplo, queremos ver los libros de "Lewis Carroll" pero
no recordamos si se escribe "Carroll" o "Carrolt", entonces tipeamos esta condición:
select *from libros
where autor like "%Carrol_";
"like" se emplea con tipos de datos caracter y date. Si empleamos "like" con tipos de datos que
no son caracteres, Oracle convierte (si es posible) el tipo de dato a caracter. Por ejemplo,
queremos buscar todos los libros cuyo precio se encuentre entre 10.00 y 19.99:
select titulo,precio from libros
where precio like '1_,%';
Queremos los libros que NO incluyen centavos en sus precios:
select titulo,precio from libros
where precio not like '%,%';
Los valores nulos no se incluyen en las búsquedas con "like" y "not like".
28 - Búsqueda de patrones (like - not like)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Elimine la tabla:
drop table empleados;
2- Cree la tabla:
create table empleados(
nombre varchar2(30),
documento char(8) not null,
domicilio varchar2(30),
fechaingreso date,
seccion varchar2(20),
sueldo number(6,2),
primary key(documento)
);
3- Ingrese algunos registros:
insert into empleados
values('Juan Perez','22333444','Colon 123','08/10/1990','Gerencia',900.50);
insert into empleados
values('Ana Acosta','23444555','Caseros
987','18/12/1995','Secretaria',590.30);
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','15/05/2005','Sistemas',790);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento
873','12/02/1999','Secretaria',550);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia
801','22/09/2002','Contaduria',630.70);
insert into empleados
values('Yolanda perez','35111222','Colon
180','08/10/1990','Administracion',400);
insert into empleados
values('Rodolfo perez','35555888','Coronel Olmedo
588','28/05/1990','Sistemas',800);
4- Muestre todos los empleados con apellido "Perez" empleando el operador "like" (1 registro)
Note que no incluye los "perez" (que comienzan con minúscula).
5- Muestre todos los empleados cuyo domicilio comience con "Co" y tengan un "8" (2 registros)
6- Seleccione todos los empleados cuyo documento finalice en 0 ó 4 (2 registros)
7- Seleccione todos los empleados cuyo documento NO comience con 2 y cuyo nombre finalice
en "ez" (1 registro)
8- Recupere todos los nombres que tengan una "G" o una "J" en su nombre o apellido (3
registros)
9- Muestre los nombres y sección de los empleados que pertenecen a secciones que comiencen
con "S" o "G" y tengan 8 caracteres (3 registros)
10- Muestre los nombres y sección de los empleados que pertenecen a secciones que NO
comiencen con "S" (3 registros)
11- Muestre todos los nombres y sueldos de los empleados cuyos sueldos se encuentren entre
500,00 y 599,99 empleando "like" (2 registros)
12- Muestre los empleados que hayan ingresado en la década del 90 (5 registros)
13- Agregue 50 centavos a todos los sueldos que no tengan centavos (4 registros) y verifique
recuperando todos los registros.
14- Elimine todos los empleados cuyos apellidos comiencen con "p" (minúscula) (2 registros)
Ver solución
29 - Contar registros (count)
Existen en Oracle funciones que nos permiten contar registros, calcular sumas, promedios,
obtener valores máximos y mínimos. Estas funciones se denominan funciones de grupo y operan
sobre un conjunto de valores (registros), no con datos individuales y devuelven un único valor.
Imaginemos que nuestra tabla "libros" contiene muchos registros. Para averiguar la cantidad sin
necesidad de contarlos manualmente usamos la función "count()":
select count(*)
from libros;
La función "count()" cuenta la cantidad de registros de una tabla, incluyendo los que tienen valor
nulo.
También podemos utilizar esta función junto con la clausula "where" para una consulta más
específica. Queremos saber la cantidad de libros de la editorial "Planeta":
select count(*)
from libros
where editorial='Planeta';
Para contar los registros que tienen precio (sin tener en cuenta los que tienen valor nulo), usamos
la función "count()" y en los paréntesis colocamos el nombre del campo que necesitamos contar:
select count(precio)
from libros;
Note que "count(*)" retorna la cantidad de registros de una tabla (incluyendo los que tienen valor
"null") mientras que "count(precio)" retorna la cantidad de registros en los cuales el campo
"precio" no es nulo. No es lo mismo. "count(*)" cuenta registros, si en lugar de un asterisco
colocamos como argumento el nombre de un campo, se contabilizan los registros cuyo valor en
ese campo NO es nulo.
29 - Contar registros (count)
Primer problema:
Trabaje con la tabla llamada "medicamentos" de una farmacia.
1- Elimine la tabla:
drop table medicamentos;
2- Cree la tabla con la siguiente estructura:
create table medicamentos(
codigo number(5),
nombre varchar2(20),
laboratorio varchar2(20),
precio number(6,2),
cantidad number(3),
fechavencimiento date not null,
numerolote number(6) default null,
primary key(codigo)
);
3- Ingrese algunos registros:
insert into medicamentos
values(120,'Sertal','Roche',5.2,1,'01/02/2005',123456);
insert into medicamentos
values(220,'Buscapina','Roche',4.10,3,'01/02/2006',null);
insert into medicamentos
values(228,'Amoxidal 500','Bayer',15.60,100,'01/05/2007',null);
insert into medicamentos
values(324,'Paracetamol 500','Bago',1.90,20,'01/02/2008',null);
insert into medicamentos
values(587,'Bayaspirina',null,2.10,null,'01/12/2009',null);
insert into medicamentos
values(789,'Amoxidal jarabe','Bayer',null,null,'15/12/2009',null);
4- Muestre la cantidad de registros empleando la función "count(*)" (6 registros)
5- Cuente la cantidad de medicamentos que tienen laboratorio conocido (5 registros)
6- Cuente la cantidad de medicamentos que tienen precio y cantidad, con alias (5 y 4
respectivamente)
7- Cuente la cantidad de remedios con precio conocido, cuyo laboratorio comience con "B" (2
registros)
8- Cuente la cantidad de medicamentos con número de lote distinto de "null" (1 registro)
9- Cuente la cantidad de medicamentos con fecha de vencimiento conocida (6 registros)
Ver solución
30 - Funciones de grupo (count - max - min -
sum - avg)
Hemos visto que Oracle dispone de funciones que nos permiten contar registros, calcular sumas,
promedios, obtener valores máximos y mínimos, las funciones de grupo. Las funciones de grupo
operan sobre un conjunto de valores (registros) y retornan un solo valor.
Ya hemos aprendido una de ellas, "count()", veamos otras.
Se pueden usar en una instrucción "select" y combinarlas con la cláusula "group by" (la veremos
posteriormente).
Todas estas funciones retornan "null" si ningún registro cumple con la condicion del "where"
(excepto "count" que en tal caso retorna cero).
El tipo de dato del campo determina las funciones que se pueden emplear con ellas.
Las relaciones entre las funciones de agrupamiento y los tipos de datos es la siguiente:
- count: se puede emplear con cualquier tipo de dato.
- min y max: con cualquier tipo de dato.
- sum y avg: sólo en campos de tipo numérico.
La función "sum()" retorna la suma de los valores que contiene el campo especificado. Si
queremos saber la cantidad total de libros que tenemos disponibles para la venta, debemos sumar
todos los valores del campo "cantidad":
select sum(cantidad)
from libros;
Para averiguar el valor máximo o mínimo de un campo usamos las funciones "max()" y "min()"
respectivamente. Queremos saber cuál es el mayor precio de todos los libros:
select max(precio)
from libros;
Entonces, dentro del paréntesis de la función colocamos el nombre del campo del cuál queremos
el máximo valor.
La función "avg()" retorna el valor promedio de los valores del campo especificado. Queremos
saber el promedio del precio de los libros referentes a "PHP":
select avg(precio)
from libros
where titulo like '%PHP%';
Ahora podemos entender porque estas funciones se denominan "funciones de grupo", porque
operan sobre conjuntos de registros, no con datos individuales.
Tratamiento de los valores nulos:
Si realiza una consulta con la función "count" incluyendo entre paréntesis un campo y la tabla
contiene 18 registros, 2 de los cuales contienen valor nulo en "precio", el resultado devuelve un
total de 16 filas porque no considera aquellos con valor nulo.
Todas las funciones de grupo, excepto "count(*)", excluye los valores nulos de los campos;
"count(*)" cuenta todos los registros, incluidos los que contienen "null".
30 - Funciones de grupo (count - max - min
- sum - avg)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Elimine la tabla y créela con la siguiente estructura:
drop table empleados;
create table empleados(
nombre varchar2(30),
documento char(8),
domicilio varchar2(30),
seccion varchar2(20),
sueldo number(6,2),
cantidadhijos number(2),
fechaingreso date,
primary key(documento)
);
3- Ingrese algunos registros:
insert into empleados
values('Juan Perez','22333444','Colon 123','Gerencia',5000,2,'10/10/1980');
insert into empleados
values('Ana Acosta','23444555','Caseros
987','Secretaria',2000,0,'15/08/1998');
insert into empleados
values('Lucas Duarte','25666777','Sucre 235','Sistemas',4000,1,null);
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento
873','Secretaria',2200,3,null);
insert into empleados
values('Marcos Juarez','30000111','Rivadavia
801','Contaduria',3000,0,'26/08/2000');
insert into empleados
values('Yolanda Perez','35111222','Colon
180','Administracion',3200,1,'25/09/2001');
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo
588','Sistemas',4000,3,null);
insert into empleados
values('Martina Rodriguez','30141414','Sarmiento
1234','Administracion',3800,4,'14/12/2000');
insert into empleados
values('Andres
Costa','28444555',default,'Secretaria',null,null,'08/08/1990');
4- Muestre la cantidad de empleados usando "count" (9 empleados)
5- Muestre la cantidad de empleados con fecha de ingreso conocida (6 empleados)
6- Muestre la cantidad de empleados con sueldo (8 empleados)
7- Muestre la cantidad de empleados con sueldo de la sección "Secretaria" (2 empleados)
8- Muestre el sueldo más alto y el más bajo colocando un alias (5000 y 2000 respectivamente)
9- Muestre el valor mayor de "cantidadhijos" de los empleados "Perez" (3 hijos)
10- Muestre la fecha de ingreso más reciente (max) y la más lejana (min) (25/09/01 y 10/10/80
respectivamente)
11- Muestre el documento menor (22333444)
12- Muestre el promedio de sueldos de todo los empleados (3400. Note que hay un sueldo nulo y
no es tenido en cuenta)
13- Muestre el promedio de sueldos de los empleados de la sección "Secretaría" (2100. Note que
hay 3 registros de la sección solicitada, pero como uno de ellos tiene sueldo nulo, no es tenido en
cuenta)
14- Muestre el promedio de hijos de todos los empleados de "Sistemas" (retorna 2)
15- Muestre la cantidad de empleados, la cantidad de empleados con domicilio conocido, la
suma de los hijos, el promedio de los sueldos y los valores mínimo y máximo del campo
"fechaingreso" de todos los empleados. Empleamos todas las funciones de grupo en una sola
consulta y nos retorna 9, 8, 14, 3400, 10/10/80 y 25/09/01.
16- Realice la misma consulta anterior pero ahora de los empleados de la sección "Recursos". Al
no existir tal sección, "count(*)" y "count(domicilio)" retornan 0 (cero) y las demás funciones de
grupo retornan "null".
Ver solución
31 - Agrupar registros (group by)
Hemos aprendido que las funciones de grupo permiten realizar varios cálculos operando con
conjuntos de registros.
Las funciones de grupo solas producen un valor de resumen para todos los registros de un
campo.
Podemos generar valores de resumen para un solo campo, combinando las funciones de agregado
con la cláusula "group by", que agrupa registros para consultas detalladas.
Queremos saber la cantidad de libros de cada editorial, podemos tipear la siguiente sentencia:
select count(*) from libros
where editorial='Planeta';
y repetirla con cada valor de "editorial":
select count(*) from libros
where editorial='Emece';
select count(*) from libros
where editorial='Paidos';
...
Pero hay otra manera, utilizando la cláusula "group by":
select editorial, count(*)
from libros
group by editorial;
La instrucción anterior solicita que muestre el nombre de la editorial y cuente la cantidad
agrupando los registros por el campo "editorial". Como resultado aparecen los nombres de las
editoriales y la cantidad de registros para cada valor del campo.
Los valores nulos se procesan como otro grupo.
Entonces, para saber la cantidad de libros que tenemos de cada editorial, utilizamos la función
"count()", agregamos "group by" (que agrupa registros) y el campo por el que deseamos que se
realice el agrupamiento, también colocamos el nombre del campo a recuperar; la sintaxis básica
es la siguiente:
select CAMPO, FUNCIONDEAGREGADO
from NOMBRETABLA
group by CAMPO;
También se puede agrupar por más de un campo, en tal caso, luego del "group by" se listan los
campos, separados por comas. Todos los campos que se especifican en la cláusula "group by"
deben estar en la lista de selección.
select CAMPO1, CAMPO2, FUNCIONDEAGREGADO
from NOMBRETABLA
group by CAMPO1,CAMPO2;
Para obtener la cantidad libros con precio no nulo, de cada editorial utilizamos la función
"count()" enviándole como argumento el campo "precio", agregamos "group by" y el campo por
el que deseamos que se realice el agrupamiento (editorial):
select editorial, count(precio)
from libros
group by editorial;
Como resultado aparecen los nombres de las editoriales y la cantidad de registros de cada una,
sin contar los que tienen precio nulo.
Recuerde la diferencia de los valores que retorna la función "count()" cuando enviamos como
argumento un asterisco o el nombre de un campo: en el primer caso cuenta todos los registros
incluyendo los que tienen valor nulo, en el segundo, los registros en los cuales el campo
especificado es no nulo.
Para conocer el total de libros agrupados por editorial:
select editorial, sum(cantidad)
from libros
group by editorial;
Para saber el máximo y mínimo valor de los libros agrupados por editorial:
select editorial,
max(precio) as mayor,
min(precio) as menor
from libros
group by editorial;
Para calcular el promedio del valor de los libros agrupados por editorial:
select editorial, avg(precio)
from libros
group by editorial;
Es posible limitar la consulta con "where".
Si incluye una cláusula "where", sólo se agrupan los registros que cumplen las condiciones.
Vamos a contar y agrupar por editorial considerando solamente los libros cuyo precio sea menor
a 30 pesos:
select editorial, count(*)
from libros
where precio<30
group by editorial;
Note que las editoriales que no tienen libros que cumplan la condición, no aparecen en la salida.
Entonces, usamos "group by" para organizar registros en grupos y obtener un resumen de dichos
grupos. Oracle produce una columna de valores por cada grupo, devolviendo filas por cada grupo
especificado.
31 - Agrupar registros (group by)
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes" algunos
datos de las personas que visitan o compran en su stand para luego enviarle publicidad de sus
productos.
1- Elimine la tabla "visitantes" y créela con la siguiente estructura:
drop table visitantes;
create table visitantes(
nombre varchar2(30),
edad number(2),
sexo char(1) default 'f',
domicilio varchar2(30),
ciudad varchar2(20) default 'Cordoba',
telefono varchar2(11),
mail varchar2(30) default 'no tiene',
montocompra number(6,2)
);
3- Ingrese algunos registros:
insert into visitantes
values ('Susana Molina',35,default,'Colon 123',default,null,null,59.80);
insert into visitantes
values ('Marcos Torres',29,'m',default,'Carlos
Paz',default,'marcostorres@[Link]',150.50);
insert into visitantes
values ('Mariana Juarez',45,default,default,'Carlos
Paz',null,default,23.90);
insert into visitantes (nombre, edad,sexo,telefono, mail)
values ('Fabian Perez',36,'m','4556677','fabianperez@[Link]');
insert into visitantes (nombre, ciudad, montocompra)
values ('Alejandra Gonzalez','La Falda',280.50);
insert into visitantes (nombre, edad,sexo, ciudad, mail,montocompra)
values ('Gaston Perez',29,'m','Carlos Paz','gastonperez1@[Link]',95.40);
insert into visitantes
values ('Liliana Torres',40,default,'Sarmiento
876',default,default,default,85);
insert into visitantes
values ('Gabriela Duarte',21,null,null,'Rio
Tercero',default,'gabrielaltorres@[Link]',321.50);
4- Queremos saber la cantidad de visitantes de cada ciudad utilizando la cláusula "group by" (4
filas devueltas)
5- Queremos la cantidad visitantes con teléfono no nulo, de cada ciudad (4 filas devueltas)
6- Necesitamos el total del monto de las compras agrupadas por sexo (3 filas)
Note que los registros con valor nulo en el campo "sexo" se procesan como un grupo diferente.
7- Se necesita saber el máximo y mínimo valor de compra agrupados por sexo y ciudad (6 filas)
8- Calcule el promedio del valor de compra agrupados por ciudad (4 filas)
9- Cuente y agrupe por ciudad sin tener en cuenta los visitantes que no tienen mail (3 filas)
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla "empleados".
1- Elimine la tabla y luego créela con la estructura definida a continuación:
drop table empleados;
create table empleados(
nombre varchar2(30),
documento char(8),
domicilio varchar2(30),
seccion varchar2(20),
sueldo number(6,2),
cantidadhijos number(2),
fechaingreso date,
primary key(documento)
);
3- Ingrese algunos registros:
insert into empleados
values('Juan Perez','22333444','Colon 123','Gerencia',5000,2,'10/05/1980');
insert into empleados
values('Ana Acosta','23444555','Caseros
987','Secretaria',2000,0,'12/10/1980');
insert into empleados
values('Lucas Duarte','25666777','Sucre
235','Sistemas',4000,1,'25/05/1985');
insert into empleados
values('Pamela Gonzalez','26777888','Sarmiento
873','Secretaria',2200,3,'25/06/1990');
insert into empleados
values('Marcos Juarez','30000111','Rivadavia
801','Contaduria',3000,0,'01/05/1996');
insert into empleados
values('Yolanda Perez','35111222','Colon
180','Administracion',3200,1,'01/05/1996');
insert into empleados
values('Rodolfo Perez','35555888','Coronel Olmedo
588','Sistemas',4000,3,'01/05/1996');
insert into empleados
values('Martina Rodriguez','30141414','Sarmiento
1234','Administracion',3800,4,'01/09/2000');
insert into empleados
values('Andres Costa','28444555',default,'Secretaria',null,null,null);
4- Cuente la cantidad de empleados agrupados por sección (5 filas)
5- Calcule el promedio de hijos por sección (5 filas)
6- Cuente la cantidad de empleados agrupados por año de ingreso (6 filas)
7- Calcule el promedio de sueldo por sección de los empleados con hijos (4 filas)
Ver solución
32 - Seleccionar grupos (Having)
Así como la cláusula "where" permite seleccionar (o rechazar) registros individuales; la cláusula
"having" permite seleccionar (o rechazar) un grupo de registros.
Si queremos saber la cantidad de libros agrupados por editorial usamos la siguiente instrucción
ya aprendida:
select editorial, count(*)
from libros
group by editorial;
Si queremos saber la cantidad de libros agrupados por editorial pero considerando sólo algunos
grupos, por ejemplo, los que devuelvan un valor mayor a 2, usamos la siguiente instrucción:
select editorial, count(*) from libros
group by editorial
having count(*)>2;
Se utiliza "having", seguido de la condición de búsqueda, para seleccionar ciertas filas retornadas
por la cláusula "group by".
Veamos otros ejemplos. Queremos el promedio de los precios agrupados por editorial, pero
solamente de aquellos grupos cuyo promedio supere los 25 pesos:
select editorial, avg(precio) from libros
group by editorial
having avg(precio)>25;
En algunos casos es posible confundir las cláusulas "where" y "having". Queremos contar los
registros agrupados por editorial sin tener en cuenta a la editorial "Planeta".
Analicemos las siguientes sentencias:
select editorial, count(*) from libros
where editorial<>'Planeta'
group by editorial;
select editorial, count(*) from libros
group by editorial
having editorial<>'Planeta';
Ambas devuelven el mismo resultado, pero son diferentes. La primera, selecciona todos los
registros rechazando los de editorial "Planeta" y luego los agrupa para contarlos. La segunda,
selecciona todos los registros, los agrupa para contarlos y finalmente rechaza fila con la cuenta
correspondiente a la editorial "Planeta".
No debemos confundir la cláusula "where" con la cláusula "having"; la primera establece
condiciones para la selección de registros de un "select"; la segunda establece condiciones para
la selección de registros de una salida "group by".
Veamos otros ejemplos combinando "where" y "having". Queremos la cantidad de libros, sin
considerar los que tienen precio nulo, agrupados por editorial, sin considerar la editorial
"Planeta":
select editorial, count(*) from libros
where precio is not null
group by editorial
having editorial<>'Planeta';
Aquí, selecciona los registros rechazando los que no cumplan con la condición dada en "where",
luego los agrupa por "editorial" y finalmente rechaza los grupos que no cumplan con la
condición dada en el "having".
Se emplea la cláusula "having" con funciones de grupo, esto no puede hacerlo la cláusula
"where". Por ejemplo queremos el promedio de los precios agrupados por editorial, de aquellas
editoriales que tienen más de 2 libros:
select editorial, avg(precio) from libros
group by editorial
having count(*) > 2;
En una cláusula "having" puede haber varias condiciones. Cuando utilice varias condiciones,
tiene que combinarlas con operadores lógicos (and, or, not).
Podemos encontrar el mayor valor de los libros agrupados y ordenados por editorial y
seleccionar las filas que tengan un valor menor a 100 y mayor a 30:
select editorial, max(precio) as mayor
from libros
group by editorial
having min(precio)<100 and
min(precio)>30
order by editorial;
Entonces, usamos la clausula "having" para restringir las filas que devuelve una salida "group
by". Va siempre después de la cláusula "group by" y antes de la cláusula "order by" si la hubiere.
32 - Seleccionar grupos (Having)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes":
drop table clientes;
2- Créela con la siguiente estructura:
create table clientes (
nombre varchar2(30) not null,
domicilio varchar2(30),
ciudad varchar2(20),
provincia varchar2(20),
telefono varchar2(11)
);
3- Ingrese algunos registros:
insert into clientes
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba','null');
insert into clientes
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba','4578585');
insert into clientes
values ('Garcia Juan','Rivadavia 333','Villa del
Rosario','Cordoba','4578445');
insert into clientes
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe',null);
insert into clientes
values ('Pereyra Lucas','San Martin 555','Cruz del
Eje','Cordoba','4253685');
insert into clientes
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe','0345252525');
insert into clientes
values ('Torres Fabiola','Alem 777','Villa del
Rosario','Cordoba','4554455');
insert into clientes
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba',null);
insert into clientes
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba','4223366');
insert into clientes
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones','0457858745');
4- Obtenga el total de los registros agrupados por ciudad y provincia (6 filas)
5- Obtenga el total de los registros agrupados por ciudad y provincia sin considerar los que
tienen menos de 2 clientes (3 filas)
6- Obtenga el total de los clientes que viven en calle "San Martin" (where), agrupados por
provincia (group by), de aquellas ciudades que tengan menos de 2 clientes (having) y omitiendo
la fila correspondiente a la ciudad de "Cordoba" (having) (2 filas devueltas)
Ver solución
Segundo problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes" algunos
datos de las personas que visitan o compran en su stand para luego enviarle publicidad de sus
productos.
1- Elimine la tabla "visitantes":
drop table visitantes;
2- Créela con la siguiente estructura:
create table visitantes(
nombre varchar2(30),
edad number(2),
sexo char(1),
domicilio varchar2(30),
ciudad varchar2(20),
telefono varchar2(11),
montocompra number(6,2) not null
);
3- Ingrese algunos registros:
insert into visitantes
values ('Susana Molina',28,'f',null,'Cordoba',null,45.50);
insert into visitantes
values ('Marcela Mercado',36,'f','Avellaneda
345','Cordoba','4545454',22.40);
insert into visitantes
values ('Alberto Garcia',35,'m','Gral. Paz 123','Alta
Gracia','03547123456',25);
insert into visitantes
values ('Teresa Garcia',33,'f',default,'Alta Gracia','03547123456',120);
insert into visitantes
values ('Roberto Perez',45,'m','Urquiza 335','Cordoba','4123456',33.20);
insert into visitantes
values ('Marina Torres',22,'f','Colon 222','Villa
Dolores','03544112233',95);
insert into visitantes
values ('Julieta Gomez',24,'f','San Martin 333','Alta Gracia',null,53.50);
insert into visitantes
values ('Roxana Lopez',20,'f','null','Alta Gracia',null,240);
insert into visitantes
values ('Liliana Garcia',50,'f','Paso 999','Cordoba','4588778',48);
insert into visitantes
values ('Juan Torres',43,'m','Sarmiento 876','Cordoba',null,15.30);
4- Obtenga el total de las compras agrupados por ciudad y sexo de aquellas filas que devuelvan
un valor superior a 50 (3 filas)
5- Obtenga el total de las compras agrupados por ciudad y sexo (group by), considerando sólo
los montos de compra superiores a 50 (where), los visitantes con teléfono (where), sin considerar
la ciudad de "Cordoba" (having), ordenados por ciudad (order by) (2 filas)
6- Muestre el monto mayor de compra agrupado por ciudad, siempre que dicho valor supere los
50 pesos (having), considerando sólo los visitantes de sexo femenino y domicilio conocido
(where) (2 filas)
7- Agrupe por ciudad y sexo, muestre para cada grupo el total de visitantes, la suma de sus
compras y el promedio de compras, ordenado por la suma total y considerando las filas con
promedio superior a 30 (3 filas)
Ver solución
33 - Registros duplicados (Distinct)
Con la cláusula "distinct" se especifica que los registros con ciertos datos duplicados sean
obviadas en el resultado. Por ejemplo, queremos conocer todos los autores de los cuales tenemos
libros, si utilizamos esta sentencia:
select autor from libros;
Aparecen repetidos. Para obtener la lista de autores sin repetición usamos:
select distinct autor from libros;
También podemos tipear:
select autor from libros
group by autor;
Note que en los tres casos anteriores aparece "null" como un valor para "autor"· Si sólo
queremos la lista de autores conocidos, es decir, no queremos incluir "null" en la lista, podemos
utilizar la sentencia siguiente:
select distinct autor from libros
where autor is not null;
Para contar los distintos autores, sin considerar el valor "null" usamos:
select count(distinct autor)
from libros;
Note que si contamos los autores sin "distinct", no incluirá los valores "null" pero si los
repetidos:
select count(autor)
from libros;
Esta sentencia cuenta los registros que tienen autor.
Podemos combinarla con "where". Por ejemplo, queremos conocer los distintos autores de la
editorial "Planeta":
select distinct autor from libros
where editorial='Planeta';
También puede utilizarse con "group by" para contar los diferentes autores por editorial:
select editorial, count(distinct autor)
from libros
group by editorial;
La cláusula "distinct" afecta a todos los campos presentados. Para mostrar los títulos y editoriales
de los libros sin repetir títulos ni editoriales, usamos:
select distinct titulo,editorial
from libros
order by titulo;
Note que los registros no están duplicados, aparecen títulos iguales pero con editorial diferente,
cada registro es diferente.
Entonces, "distinct" elimina registros duplicados.
33 - Registros duplicados (Distinct)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes".
1- Elimine la tabla "clientes" y créela con la siguiente estructura:
drop table clientes;
create table clientes (
nombre varchar2(30) not null,
domicilio varchar2(30),
ciudad varchar2(20),
provincia varchar2(20)
);
2- Ingrese algunos registros:
insert into clientes
values ('Lopez Marcos','Colon 111','Cordoba','Cordoba');
insert into clientes
values ('Perez Ana','San Martin 222','Cruz del Eje','Cordoba');
insert into clientes
values ('Garcia Juan','Rivadavia 333','Villa del Rosario','Cordoba');
insert into clientes
values ('Perez Luis','Sarmiento 444','Rosario','Santa Fe');
insert into clientes
values ('Pereyra Lucas','San Martin 555','Cruz del Eje','Cordoba');
insert into clientes
values ('Gomez Ines','San Martin 666','Santa Fe','Santa Fe');
insert into clientes
values ('Torres Fabiola','Alem 777','Villa del Rosario','Cordoba');
insert into clientes
values ('Lopez Carlos',null,'Cruz del Eje','Cordoba');
insert into clientes
values ('Ramos Betina','San Martin 999','Cordoba','Cordoba');
insert into clientes
values ('Lopez Lucas','San Martin 1010','Posadas','Misiones');
3- Obtenga las provincias sin repetir (3 registros)
4- Cuente las distintas provincias (retorna 3)
5- Se necesitan los nombres de las ciudades sin repetir (6 registros)
6- Obtenga la cantidad de ciudades distintas (devuelve 6)
7- Combine con "where" para obtener las distintas ciudades de la provincia de Cordoba (3
registros)
8- Contamos las distintas ciudades de cada provincia empleando "group by" (3 filas)
Ver solución
Segundo problema:
La provincia almacena en una tabla llamada "inmuebles" los siguientes datos de los inmuebles y
sus propietarios para cobrar impuestos:
1- Elimine la tabla:
drop table inmuebles;
2- Créela con la siguiente estructura:
create table inmuebles (
documento varchar2(8) not null,
apellido varchar2(30),
nombre varchar2(30),
domicilio varchar2(20),
barrio varchar2(20),
ciudad varchar2(20),
tipo char(1),--b=baldio, e: edificado
superficie number(8,2)
);
3- Ingrese algunos registros:
insert into inmuebles
values ('11000000','Perez','Alberto','San Martin
800','Centro','Cordoba','e',100);
insert into inmuebles
values ('11000000','Perez','Alberto','Sarmiento 245','Gral.
Paz','Cordoba','e',200);
insert into inmuebles
values ('12222222','Lopez','Maria','San Martin
202','Centro','Cordoba','e',250);
insert into inmuebles
values ('13333333','Garcia','Carlos','Paso
1234','Alberdi','Cordoba','b',200);
insert into inmuebles
values ('13333333','Garcia','Carlos','Guemes
876','Alberdi','Cordoba','b',300);
insert into inmuebles
values ('14444444','Perez','Mariana','Caseros
456','Flores','Cordoba','b',200);
insert into inmuebles
values ('15555555','Lopez','Luis','San Martin 321','Centro','Carlos
Paz','e',500);
insert into inmuebles
values ('15555555','Lopez','Luis','Lopez y Planes 853','Flores','Carlos
Paz','e',350);
insert into inmuebles
values ('16666666','Perez','Alberto','Sucre
1877','Flores','Cordoba','e',150);
4- Muestre los distintos apellidos de los propietarios, sin repetir (3 registros)
5- Recupere los distintos documentos de los propietarios y luego muestre los distintos
documentos de los propietarios, sin repetir y vea la diferencia (9 y 6 registros respectivamente)
6- Cuente, sin repetir, la cantidad de propietarios de inmuebles de la ciudad de Cordoba (5)
7- Cuente la cantidad de inmuebles con domicilio en 'San Martin' (3)
8- Cuente la cantidad de inmuebles con domicilio en 'San Martin', sin repetir la ciudad (2
registros). Compare con la sentencia anterior.
9- Muestre los apellidos y nombres de todos los registros(9 registros)
10- Muestre los apellidos y nombres, sin repetir (5 registros)
Note que si hay 2 personas con igual nombre y apellido aparece una sola vez.
11- Muestre la cantidad de inmuebles que tiene cada propietario en barrios conocidos, agrupando
por documento (6 registros)
12- Realice la misma consulta anterior pero en esta oportunidad, sin repetir barrio (6 registros)
Compare los valores con los obtenidos en el punto 11.
Ver solución
34 - Clave primaria compuesta
Las claves primarias pueden ser simples, formadas por un solo campo o compuestas, más de un
campo.
Recordemos que una clave primaria identifica un solo registro en una tabla.
Para un valor del campo clave existe solamente un registro. Los valores no se repiten ni pueden
ser nulos.
Existe una playa de estacionamiento que almacena cada día los datos de los vehículos que
ingresan en la tabla llamada "vehiculos" con los siguientes campos:
- patente char(6) not null,
- tipo char (1), 'a'= auto, 'm'=moto,
- horallegada date,
- horasalida date,
Necesitamos definir una clave primaria para una tabla con los datos descriptos arriba. No
podemos usar solamente la patente porque un mismo auto puede ingresar más de una vez en el
día a la playa; tampoco podemos usar la hora de entrada porque varios autos pueden ingresar a
una misma hora. Tampoco sirven los otros campos.
Como ningún campo, por si sólo cumple con la condición para ser clave, es decir, debe
identificar un solo registro, el valor no puede repetirse, debemos usar dos campos.
Definimos una clave compuesta cuando ningún campo por si solo cumple con la condición para
ser clave.
En este ejemplo, un auto puede ingresar varias veces en un día a la playa, pero siempre será a
distinta hora.
Usamos 2 campos como clave, la patente junto con la hora de llegada, así identificamos
unívocamente cada registro.
Para establecer más de un campo como clave primaria usamos la siguiente sintaxis:
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada date,
horasalida date,
primary key(patente,horallegada)
);
Nombramos los campos que formarán parte de la clave separados por comas.
Al ingresar los registros, Oracle controla que los valores para los campos establecidos como
clave primaria no estén repetidos en la tabla; si estuviesen repetidos, muestra un mensaje y la
inserción no se realiza. Lo mismo sucede si realizamos una actualización.
Para ver la clave primaria de una tabla podemos realizar la siguiente consulta:
select uc.table_name, column_name, position from user_cons_columns ucc
join user_constraints uc
on ucc.constraint_name=uc.constraint_name
where uc.constraint_type='P' and
uc.table_name='VEHICULOS';
Entonces, si un solo campo no identifica unívocamente un registro podemos definir una clave
primaria compuesta, es decir formada por más de un campo.
34 - Clave primaria compuesta
Primer problema:
Un consultorio médico en el cual trabajan 3 médicos registra las consultas de los pacientes en
una tabla llamada "consultas".
1- Elimine la tabla:
drop table consultas;
2- La tabla contiene los siguientes datos:
- fechayhora: date not null, fecha y hora de la consulta,
- medico: varchar2(30), not null, nombre del médico (Perez,Lopez,Duarte),
- documento: char(8) not null, documento del paciente,
- paciente: varchar2(30), nombre del paciente,
- obrasocial: varchar2(30), nombre de la obra social (IPAM,PAMI, etc.).
3- Setee el formato de "date" para que nos muestre día, mes, año, hora y minutos:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI';
4- Un médico sólo puede atender a un paciente en una fecha y hora determinada. En una fecha y
hora determinada, varios médicos atienden a distintos pacientes. Cree la tabla definiendo una
clave primaria compuesta:
create table consultas(
fechayhora date not null,
medico varchar2(30) not null,
documento char(8) not null,
paciente varchar2(30),
obrasocial varchar2(30),
primary key(fechayhora,medico)
);
4- Ingrese varias consultas para un mismo médico en distintas horas el mismo día:
insert into consultas
values ('05/11/2006 8:00','Lopez','12222222','Acosta Betina','PAMI');
insert into consultas
values ('05/11/2006 8:30','Lopez','23333333','Fuentes Carlos','PAMI');
5- Ingrese varias consultas para diferentes médicos en la misma fecha y hora:
insert into consultas
values ('05/11/2006 8:00','Perez','34444444','Garcia Marisa','IPAM');
insert into consultas
values ('05/11/2006 8:00','Duarte','45555555','Pereyra Luis','PAMI');
6- Intente ingresar una consulta para un mismo médico en la misma hora el mismo día (mensaje
de error)
7- Intente cambiar la hora de la consulta de "Acosta Betina" por una no disponible ("8:30")
(error)
8- Cambie la hora de la consulta de "Acosta Betina" por una disponible ("9:30")
9- Ingrese una consulta para el día "06/11/2006" a las 10 hs. para el doctor "Perez"
10- Recupere todos los datos de las consultas de "Lopez" (3 registros)
11- Recupere todos los datos de las consultas programadas para el "05/11/2006 8:00" (2
registros)
12- Muestre día y mes de todas las consultas de "Lopez"
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes. En una tabla llamada "inscriptos" almacena la
información necesaria.
1- Elimine la tabla "inscriptos":
drop table inscriptos;
2- La tabla contiene los siguientes campos:
- documento del socio alumno: char(8) not null
- nombre del socio: varchar2(30),
- nombre del deporte (tenis, futbol, natación, basquet): varchar2(15) not
null,
- año de inscripcion: date,
- matrícula: si la matrícula ha sido o no pagada ('s' o 'n').
3- Necesitamos una clave primaria que identifique cada registro. Un socio puede inscribirse en
varios deportes en distintos años. Un socio no puede inscribirse en el mismo deporte el mismo
año. Varios socios se inscriben en un mismo deporte en distintos años. Cree la tabla con una
clave compuesta:
create table inscriptos(
documento char(8) not null,
nombre varchar2(30),
deporte varchar2(15) not null,
año date,
matricula char(1),
primary key(documento,deporte,año)
);
4- Setee el formato de "date" para que nos muestre solamente el año (no necesitamos las otras
partes de la fecha ni la hora)
5- Inscriba a varios alumnos en el mismo deporte en el mismo año:
insert into inscriptos
values ('12222222','Juan Perez','tenis','2005','s');
insert into inscriptos
values ('23333333','Marta Garcia','tenis','2005','s');
insert into inscriptos
values ('34444444','Luis Perez','tenis','2005','n');
6- Inscriba a un mismo alumno en varios deportes en el mismo año:
insert into inscriptos
values ('12222222','Juan Perez','futbol','2005','s');
insert into inscriptos
values ('12222222','Juan Perez','natacion','2005','s');
insert into inscriptos
values ('12222222','Juan Perez','basquet','2005','n');
7- Ingrese un registro con el mismo documento de socio en el mismo deporte en distintos años:
insert into inscriptos
values ('12222222','Juan Perez','tenis','2006','s');
insert into inscriptos
values ('12222222','Juan Perez','tenis','2007','s');
8- Intente inscribir a un socio alumno en un deporte en el cual ya esté inscripto en un año en el
cual ya se haya inscripto (mensaje de error)
9- Intente actualizar un registro para que la clave primaria se repita (error)
10- Muestre los nombres y años de los inscriptos en "tenis" (5 registros)
11- Muestre los nombres y deportes de los inscriptos en el año 2005 (6 registros)
12- Muestre el deporte y año de todas las incripciones del socio documento "12222222" (6
registros)
Ver solución
35 - Secuencias (create sequence - currval -
nextval - drop sequence)
Hemos aprendido que existen varios objetos de base de datos, hasta ahora hemos visto TABLAS
y algunas FUNCIONES predefinidas. Otro objeto de base de datos es la secuencia.
Una secuencia (sequence) se emplea para generar valores enteros secuenciales únicos y
asignárselos a campos numéricos; se utilizan generalmente para las claves primarias de las tablas
garantizando que sus valores no se repitan.
Una secuencia es una tabla con un campo numérico en el cual se almacena un valor y cada vez
que se consulta, se incrementa tal valor para la próxima consulta.
Sintaxis general:
create sequence NOMBRESECUENCIA
start with VALORENTERO
increment by VALORENTERO
maxvalue VALORENTERO
minvalue VALORENTERO
cycle | nocycle;
- La cláusula "start with" indica el valor desde el cual comenzará la generación de números
secuenciales. Si no se especifica, se inicia con el valor que indique "minvalue".
- La cláusula "increment by" especifica el incremento, es decir, la diferencia entre los números
de la secuencia; debe ser un valor numérico entero positivo o negativo diferente de 0. Si no se
indica, por defecto es 1.
- "maxvalue" define el valor máximo para la secuencia. Si se omite, por defecto es
99999999999999999999999999.
- "minvalue" establece el valor mínimo de la secuencia. Si se omite será 1.
- La cláusula "cycle" indica que, cuando la secuencia llegue a máximo valor (valor de
"maxvalue") se reinicie, comenzando con el mínimo valor ("minvalue") nuevamente, es decir, la
secuencia vuelve a utilizar los números. Si se omite, por defecto la secuencia se crea "nocycle".
Si no se especifica ninguna cláusula, excepto el nombre de la secuencia, por defecto, comenzará
en 1, se incrementará en 1, el mínimo valor será 1, el máximo será
999999999999999999999999999 y "nocycle".
En el siguiente ejemplo creamos una secuencia llamada "sec_codigolibros", estableciendo que
comience en 1, sus valores estén entre 1 y 99999 y se incrementen en 1, por defecto, será
"nocycle":
create sequence sec_codigolibros
start with 1
increment by 1
maxvalue 99999
minvalue 1;
Si bien, las secuencias son independientes de las tablas, se utilizarán generalmente para una tabla
específica, por lo tanto, es conveniente darle un nombre que referencie a la misma.
Otro ejemplo:
create sequence sec_numerosocios
increment by 5
cycle;
La secuencia anterior, "sec_numerosocios", incrementa sus valores en 5 y al llegar al máximo
valor recomenzará la secuencia desde el valor mínimo; no se especifican las otras cláusulas, por
lo tanto, por defecto, el valor mínimo es 1, el máximo 999999999999999999999999999 y el
valor inicial es 1.
Dijimos que las secuencias son tablas; por lo tanto se accede a ellas mediante consultas,
empleando "select". La diferencia es que utilizamos pseudocolumnas para recuperar el valor
actual y el siguiente de la secuencia. Estas pseudocolumnas pueden incluirse en el "from" de una
consulta a otra tabla o de la tabla "dual".
Para recuperar los valores de una secuencia empleamos las pseudocolumnas "currval" y
"nextval".
Primero debe inicializarse la secuencia con "nextval". La primera vez que se referencia "nextval"
retorna el valor de inicio de la secuencia; las siguientes veces, incrementa la secuencia y nos
retorna el nuevo valor:
[Link];
se coloca el nombre de la secuencia seguido de un punto y la pseudocolumna "nextval" (que es
una forma abreviada de "next value", siguiente valor).
Para recuperar el valor actual de una secuencia usamos:
[Link];
es decir, el nombre de la secuencia, un punto y la pseudocolumna "currval" (que es una forma
abreviada de "current value", valor actual).
Los valores retornados por "currval" y "nextval" pueden usarse en sentencias "insert" y "update".
Veamos un ejemplo completo:
Creamos una secuencia para el código de la tabla "libros", especificando el valor máximo, el
incremento y que no sea circular:
create sequence sec_codigolibros
maxvalue 999999
increment by 1
nocycle;
Luego inicializamos la secuencia
select sec_codigolibros.nextval from dual;
Recuerde que la primera vez que se referencie la secuencia debe emplearse "nextval" para
inicializarla.
Ingresamos un registro en "libros", almacenando en el campo "codigo" el valor actual de la
secuencia:
insert into libros values
(sec_codigolibros.currval,'El aleph', 'Borges','Emece');
Ingresamos otro registro en "libros", almacenando en el campo "codigo" el valor siguiente de la
secuencia:
insert into libros values
(sec_codigolibros.nextval,'Matematica estas ahi', 'Paenza','Nuevo siglo');
Para ver todas las secuencias de la base de datos actual realizamos la siguiente consulta:
select *from all_sequences;
Nos muestra el propietario de la secuencia, el nombre de la misma, los valores mínimo y
máximo, el valor de incremento y si es circular o no, entre otros datos que no analizaremos por el
momento.
También podemos ver todos los objetos de la base de datos actual tipeando;
select *from all_objects;
En la tabla resultado aparecen todos los objetos de la base de datos, incluidas las secuencias; si es
una secuencia en la columna OBJECT_TYPE se muestra "SEQUENCE".
Podemos consultar "all_objects" especificando que nos muestre el nombre de todas las
secuencias:
select object_name from all_objects
where object_type='SEQUENCE';
Para eliminar una secuencia empleamos "drop sequence". Sintaxis:
drop sequence NOMBRESECUENCIA;
Si la secuencia no existe aparecerá un mensaje indicando tal situación.
En el siguiente ejemplo se elimina la secuencia "sec_codigolibros":
drop sequence sec_codigolibros;
35 - Secuencias (create sequence - currval -
nextval - drop sequence)
Primer problema:
Una empresa registra los datos de sus empleados en una tabla llamada "empleados".
1- Elimine la tabla "empleados":
drop table empleados;
2- Cree la tabla:
create table empleados(
legajo number(3),
documento char(8) not null,
nombre varchar2(30) not null,
primary key(legajo)
);
3- Elimine la secuencia "sec_legajoempleados" y luego créela estableciendo el valor mínimo (1),
máximo (999), valor inicial (100), valor de incremento (2) y no circular. Finalmente inicialice la
secuencia.
4- Ingrese algunos registros, empleando la secuencia creada para los valores de la clave primaria:
insert into empleados
values (sec_legajoempleados.currval,'22333444','Ana Acosta');
insert into empleados
values (sec_legajoempleados.nextval,'23444555','Betina Bustamante');
insert into empleados
values (sec_legajoempleados.nextval,'24555666','Carlos Caseros');
insert into empleados
values (sec_legajoempleados.nextval,'25666777','Diana Dominguez');
insert into empleados
values (sec_legajoempleados.nextval,'26777888','Estela Esper');
5- Recupere los registros de "libros" para ver los valores de clave primaria.
Note que los valores se incrementaron en 2, porque así se estableció el valor de incremento al
crear la secuencia.
6- Vea el valor actual de la secuencia empleando la tabla "dual". Retorna 108.
7- Recupere el valor siguiente de la secuencia empleando la tabla "dual" Retorna 110.
8- Ingrese un nuevo empleado (recuerde que la secuencia ya tiene el próximo valor, emplee
"currval" para almacenar el valor de legajo)
9- Recupere los registros de "libros" para ver el valor de clave primaria ingresado anteriormente.
10- Incremente el valor de la secuencia empleando la tabla "dual" (retorna 112)
11- Ingrese un empleado con valor de legajo "112".
12- Intente ingresar un registro empleando "currval":
insert into empleados
values (sec_legajoempleados.currval,'29000111','Hector Huerta');
Mensaje de error porque el legajo está repetido y la clave primaria no puede repetirse.
13- Incremente el valor de la secuencia. Retorna 114.
14- Ingrese el registro del punto 11.
Ahora si lo permite, pues el valor retornado por "currval" no está repetido en la tabla
"empleados".
15- Recupere los registros.
16- Vea las secuencias existentes y analice la información retornada.
Debe aparecer "sec_legajoempleados".
17- Vea todos los objetos de la base de datos actual que contengan en su nombre la cadena
"EMPLEADOS".
Debe aparacer la tabla "empleados" y la secuencia "sec_legajoempleados".
18- Elimine la secuencia creada.
19- Consulte todos los objetos de la base de datos que sean secuencias y verifique que
"sec_legajoempleados" ya no existe.
Ver solución
36 - Alterar secuencia (alter sequence)
Es posible modificar una secuencia, su valor de incremento, los valores mínimo y máximo y el
atributo "cycle" (el valor de inicio no puede modificarse); para ello empleamos la sentencia "alter
sequence". Sintaxis:
alter sequence NOMBRESECUENCIA ATRIBUTOSAMODIFICAR;
Definimos una secuencia denominada "sec_codigolibros" con los siguientes atributos:
create sequence sec_codigolibros
start with 1
increment by 1
maxvalue 999
minvalue 1
nocycle;
Para modificar el máximo valor a 99999 y el incremento a 2, tipeamos:
alter sequence sec_codigolibros
increment by 2
maxvalue 99999;
Los valores de incremento y mínimo han sido modificados, los demás atributos no especificados
en la sentencia "alter sequence" se mantienen.
36 - Alterar secuencia (alter sequence)
Primer problema:
Una empresa registra los datos de sus empleados en una tabla llamada "empleados".
1- Elimine la tabla "empleados":
drop table empleados;
2- Cree la tabla:
create table empleados(
legajo number(3),
documento char(8) not null,
nombre varchar2(30) not null,
primary key(legajo)
);
3- Elimine la secuencia "sec_legajoempleados" y luego créela estableciendo el valor mínimo (1),
máximo (210), valor inicial (206), valor de incremento (2) y no circular. Finalmente inicialice la
secuencia.
4- Ingrese algunos registros, empleando la secuencia creada para los valores de la clave primaria.
insert into empleados
values (sec_legajoempleados.currval,'22333444','Ana Acosta');
insert into empleados
values (sec_legajoempleados.nextval,'23444555','Betina Bustamante');
insert into empleados
values (sec_legajoempleados.nextval,'24555666','Carlos Caseros');
5- Recupere los registros de "libros" para ver los valores de clave primaria.
6- Vea el valor actual de la secuencia empleando la tabla "dual"
7- Intente ingresar un registro empleando "nextval":
insert into empleados
values (sec_legajoempleados.nextval,'25666777','Diana Dominguez');
Oracle muestra un mensaje de error indicando que la secuencia ha llegado a su valor máximo.
8- Altere la secuencia modificando el atributo "maxvalue" a 999.
9- Obtenga información de la secuencia.
10- Ingrese el registro del punto 7.
11- Recupere los registros.
12- Modifique la secuencia para que sus valores se incrementen en 1.
13- Ingrese un nuevo registro:
insert into empleados
values (sec_legajoempleados.nextval,'26777888','Federico Fuentes');
14- Recupere los registros.
15- Elimine la secuencia creada.
16- Consulte todos los objetos de la base de datos que sean secuencias y verifique que
"sec_legajoempleados" ya no existe.
Ver solución
37 - Integridad de datos
Es importante, al diseñar una base de datos y las tablas que contiene, tener en cuenta la
integridad de los datos, esto significa que la información almacenada en las tablas debe ser
válida, coherente y exacta.
Hasta el momento, hemos controlado y restringido la entrada de valores a un campo mediante el
tipo de dato que le definimos (cadena, numéricos, etc.), la aceptación o no de valores nulos, el
valor por defecto. También hemos asegurado que cada registro de una tabla sea único definiendo
una clave primaria y empleando secuencias.
Oracle ofrece más alternativas, además de las aprendidas, para restringir y validar los datos, las
veremos ordenadamente y al finalizar haremos un resumen de las mismas.
Comenzamos por las restricciones.
Las restricciones (constraints) son un método para mantener la integridad de los datos,
asegurando que los valores ingresados sean válidos y que las relaciones entre las tablas se
mantenga.
Las restricciones pueden establecerse a nivel de campo o de tabla.
Pueden definirse al crear la tabla ("create table") o agregarse a una tabla existente (empleando
"alter table") y se pueden aplicar a un campo o a varios. También es posible habilitarlas y
deshabilitarlas.
Oracle ofrece varios tipos de restricciones:
- not null: a nivel de campo.
- primary key: a nivel de tabla. Es un campo o varios que identifican cada registro de una tabla.
- foreign key: a nivel de tabla. Establece que un campo (o varios) relacione una clave primaria de
una tabla con otra.
- check: a nivel de tabla. Restringe los valores que pueden ingresarse en un campo especifico.
- unique: a nivel de tabla.
Se pueden crear, modificar y eliminar las restricciones sin eliminar la tabla y volver a crearla.
Para obtener información de las restricciones podemos consultar los catálogos "all_objects",
"all_constraints" y "all_cons_columns".
El catálogo "all_constraints" retorna varias columnas, entre ellas: OWNER (propietario),
CONSTRAINT_NAME (nombre de la restricción), CONSTRAINT_TYPE (tipo de restricción,
si es primary key (P), foreign key (), unique (U), etc.), TABLE_NAME (nombre de la tabla),
SEARCH_CONDITION (en caso de ser Check u otra), DELETE_RULE (), STATUS (estado),
DEFERRABLE (), DEFERRED (), VALIDATED (), GENERATED (), INDEX_OWNER (),
INDEX_NAME ().
El catálogo "all_cons_columnas" retorna las siguientes columnas: OWNER (propietario),
CONSTRAINT_NAME (nombre), TABLE_NAME (nombre de la tabla), COLUMN_NAME
(campo), POSITION (posición).
38 - Restricción primary key
La restricción "primary key" asegura que los valores sean únicos para cada registro.
Anteriormente, para establecer una clave primaria para una tabla empleábamos la siguiente
sintaxis al crear la tabla, por ejemplo:
create table libros(
codigo int not null,
titulo varchar(30),
autor varchar(30),
editorial varchar(20),
primary key(codigo)
);
Cada vez que establecíamos la clave primaria para la tabla, Oracle creaba automáticamente una
restricción "primary key" para dicha tabla. Dicha restricción, a la cual no le dábamos un nombre,
recibía un nombre dado por Oracle que consta de una serie de letras y números aleatorios.
Podemos agregar una restricción "primary key" a una tabla existente con la sintaxis básica
siguiente:
alter table NOMBRETABLA
add constraint NOMBRECONSTRAINT
primary key (CAMPO,...);
En el siguiente ejemplo definimos una restricción "primary key" para nuestra tabla "libros" para
asegurarnos que cada libro tendrá un código diferente y único:
alter table libros
add constraint PK_libros_codigo
primary key(codigo);
Con esta restricción, si intentamos ingresar un registro con un valor para el campo "codigo" que
ya existe o el valor "null", aparece un mensaje de error, porque no se permiten valores
duplicados ni nulos. Igualmente, si actualizamos.
Por convención, cuando demos el nombre a las restricciones "primary key" seguiremos el
formato "PK_NOMBRETABLA_NOMBRECAMPO".
Cuando agregamos una restricción a una tabla que contiene información, Oracle controla los
datos existentes para confirmar que cumplen las exigencias de la restricción, si no los cumple, la
restricción no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos definir la
restricción "primary key" para "libros" y hay registros con códigos repetidos o con un valor
"null", la restricción no se establece.
Cuando establecíamos una clave primaria al definir la tabla, automáticamente Oracle redefinía el
campo como "not null"; lo mismo sucede al agregar una restricción "primary key", los campos
que se establecen como clave primaria se redefinen automáticamente "not null".
Se permite definir solamente una restricción "primary key" por tabla, que asegura la unicidad de
cada registro de una tabla.
Si consultamos el catálogo "user_constraints", podemos ver las restricciones "primary key" (y
todos los tipos de restricciones) de todas las tablas del usuario actual. El resultado es una tabla
que nos informa el propietario de la restricción (OWNER), el nombre de la restricción
(CONSTRAINT_NAME), el tipo (CONSTRAINT_TYPE, si es "primary key" muestra una "P"),
el nombre de la tabla en la cual se aplica (TABLE_NAME), y otra información que no
analizaremos por el momento.
También podemos consultar el catálogo "user_cons_columns"; nos mostrará el propietario de la
restricción (OWNER), el nombre de la restricción (CONSTRAINT_NAME), la tabla a la cual se
aplica (TABLE_NAME), el campo (COLUMN_NAME) y la posición (POSITION).
38 - Restricción primary key
Primer problema:
Una empresa tiene registrados datos de sus empleados en una tabla llamada "empleados".
1- Elimine la tabla:
drop table empleados;
2- Créela con la siguiente estructura:
create table empleados (
documento char(8),
nombre varchar2(30),
seccion varchar2(20)
);
3- Ingrese algunos registros, dos de ellos con el mismo número de documento:
4- Intente establecer una restricción "primary key" para la tabla para que el documento no se
repita ni admita valores nulos.
No lo permite porque la tabla contiene datos que no cumplen con la restricción, debemos
eliminar (o modificar) el registro que tiene documento duplicado.
5- Establecezca la restricción "primary key" del punto 4
6- Intente actualizar un documento para que se repita.
No lo permite porque va contra la restricción.
7-Intente establecer otra restricción "primary key" con el campo "nombre".
8- Vea las restricciones de la tabla "empleados" consultando el catálogo "user_constraints" (1
restricción "P")
9- Consulte el catálogo "user_cons_columns"
Ver solución
Segundo problema:
Una empresa de remises tiene registrada la información de sus vehículos en una tabla llamada
"remis".
1- Elimine la tabla:
drop table remis;
2- Cree la tabla con la siguiente estructura:
create table remis(
numero number(5),
patente char(6),
marca varchar2(15),
modelo char(4)
);
3- Ingrese algunos registros sin repetir patente y repitiendo número.
4- Ingrese un registro con patente nula.
5- Intente definir una restricción "primary key" para el campo "numero".
6- Intente establecer una restricción "primary key" para el campo "patente".
7- Modifique el valor "null" de la patente.
8- Establezca una restricción "primary key" del punto 6.
9- Vea la información de las restricciones consultando "user_constraints" (1 restricción "P")
10- Consulte el catálogo "user_cons_columns" y analice la información retornada (1 restricción)
Ver solución
39 - Restricción unique
Anteriormente aprendimos la restricción "primary key", otra restricción que asegura valores
únicos para cada registro es "unique".
La restricción "unique" impide la duplicación de claves alternas (no primarias), es decir,
especifica que dos registros no puedan tener el mismo valor en un campo. Se permiten valores
nulos.
Se pueden aplicar varias restricciones de este tipo a una misma tabla, y pueden aplicarse a uno o
varios campos que no sean clave primaria.
Se emplea cuando ya se estableció una clave primaria (como un número de legajo) pero se
necesita asegurar que otros datos también sean únicos y no se repitan (como número de
documento).
La sintaxis general es la siguiente:
alter table NOMBRETABLA
add constraint NOMBRERESTRICCION
unique (CAMPO);
Ejemplo:
alter table alumnos
add constraint UQ_alumnos_documento
unique (documento);
En el ejemplo anterior se agrega una restricción "unique" sobre el campo "documento" de la
tabla "alumnos", esto asegura que no se pueda ingresar un documento si ya existe. Esta
restricción permite valores nulos, asi que si se ingresa el valor "null" para el campo
"documento", se acepta.
Por convención, cuando demos el nombre a las restricciones "unique" seguiremos la misma
estructura:
"UQ_NOMBRETABLA_NOMBRECAMPO". Quizá parezca innecesario colocar el nombre de la tabla, pero
cuando empleemos varias tablas verá que es útil identificar las restricciones por tipo, tabla y campo.
Recuerde que cuando agregamos una restricción a una tabla que contiene información, Oracle
controla los datos existentes para confirmar que cumplen la condición de la restricción, si no los
cumple, la restricción no se aplica y aparece un mensaje de error. En el caso del ejemplo anterior,
si la tabla contiene números de documento duplicados, la restricción no podrá establecerse; si
podrá establecerse si tiene valores nulos.
Oracle controla la entrada de datos en inserciones y actualizaciones evitando que se ingresen
valores duplicados.
Un campo que se estableció como clave primaria no puede definirse como clave única; si una
tabla tiene una clave primaria, puede tener una o varias claves únicas (aplicadas a otros campos
que no sean clave primaria).
Si consultamos el catálogo "user_constraints", podemos ver las restricciones "unique" (y todos
los tipos de restricciones) de todas las tablas del usuario actual. El resultado es una tabla que nos
informa el propietario de la restricción (OWNER), el nombre de la restricción
(CONSTRAINT_NAME), el tipo (CONSTRAINT_TYPE, si es "unique" muestra una "U"), el
nombre de la tabla en la cual se aplica (TABLE_NAME), y otra información que no
analizaremos por el momento.
También podemos consultar el catálogo "user_cons_columns"; nos mostrará el propietario de la
restricción (OWNER), el nombre de la restricción (CONSTRAINT_NAME), la tabla a la cual se
aplica (TABLE_NAME), el campo (COLUMN_NAME) y la posición (POSITION).
39 - Restricción unique
Primer problema:
Una empresa de remises tiene registrada la información de sus vehículos en una tabla llamada
"remis".
1- Elimine la tabla:
drop table remis;
2- Cree la tabla con la siguiente estructura:
create table remis(
numero number(5),
patente char(6),
marca varchar2(15),
modelo char(4)
);
3- Ingrese algunos registros, 2 de ellos con patente repetida y alguno con patente nula.
4- Agregue una restricción "primary key" para el campo "numero".
5- Intente agregar una restricción "unique" para asegurarse que la patente del remis no tomará
valores repetidos.
No se puede porque hay valores duplicados, un mensaje indica que se encontraron claves
duplicadas.
6- Elimine el registro con patente duplicada y establezca la restricción.
Note que hay 1 registro con valor nulo en "patente".
7- Intente ingresar un registro con patente repetida (no lo permite)
8- Ingrese un registro con valor nulo para el campo "patente".
9- Muestre la información de las restricciones consultando "user_constraints" y
"user_cons_columns" y analice la información retornada (2 filas en cada consulta)
Ver solución
40 - Restriccion check
La restricción "check" especifica los valores que acepta un campo, evitando que se ingresen
valores inapropiados.
La sintaxis básica es la siguiente:
alter table NOMBRETABLA
add constraint NOMBRECONSTRAINT
check CONDICION;
Trabajamos con la tabla "libros" de una librería que tiene los siguientes campos: codigo, titulo,
autor, editorial, preciomin (que indica el precio para los minoristas) y preciomay (que indica el
precio para los mayoristas).
Los campos correspondientes a los precios (minorista y mayorista) se definen de tipo
number(5,2), es decir, aceptan valores entre -999.99 y 999.99. Podemos controlar que no se
ingresen valores negativos para dichos campos agregando una restricción "check":
alter table libros
add constraint CK_libros_precio_positivo
check (preciomin>=0 and preciomay>=0);
Este tipo de restricción verifica los datos cada vez que se ejecuta una sentencia "insert" o
"update", es decir, actúa en inserciones y actualizaciones.
Si la tabla contiene registros que no cumplen con la restricción que se va a establecer, la
restricción no se puede establecer, hasta que todos los registros cumplan con dicha restricción.
La condición puede hacer referencia a otros campos de la misma tabla. Por ejemplo, podemos
controlar que el precio mayorista no sea mayor al precio minorista:
alter table libros
add constraint CK_libros_preciominmay
check (preciomay<=preciomin);
Por convención, cuando demos el nombre a las restricciones "check" seguiremos la misma
estructura: comenzamos con "CK", seguido del nombre de la tabla, del campo y alguna palabra
con la cual podamos identificar fácilmente de qué se trata la restricción, por si tenemos varias
restricciones "check" para el mismo campo.
Un campo puede tener varias restricciones "check" y una restricción "check" puede incluir varios
campos.
Las condiciones para restricciones "check" también pueden incluir una lista de valores. Por
ejemplo establecer que cierto campo asuma sólo los valores que se listan:
...
check (CAMPO in ('lunes','miercoles','viernes'));
Si un campo permite valores nulos, "null" es un valor aceptado aunque no esté incluido en la
condición de restricción.
Si intentamos establecer una restricción "check" para un campo que entra en conflicto con otra
restricción "check" establecida al mismo campo, Oracle no lo permite. Pero si establecemos una
restricción "check" para un campo que entra en conflicto con un valor "default" establecido para
el mismo campo, Oracle lo permite; pero al intentar ingresar un registro, aparece un mensaje de
error.
En las condiciones de chequeo no es posible incluir funciones (como "sysdate").
Un campo con una restricción "primary key" o "unique" puede tener una (o varias) restricciones
"check".
En la condición de una restricción "check" se puede establecer que un campo no admita valores
nulos:
alter table libros
add constraint CK_libros_titulo
check (titulo is not null);
40 - Restriccion check
Primer problema:
Una empresa tiene registrados datos de sus empleados en una tabla llamada "empleados".
1- Elimine la tabla:
drop table empleados;
2- Créela con la siguiente estructura:
create table empleados (
documento char(8),
nombre varchar2(30),
cantidadhijos number(2),
seccion varchar2(20),
sueldo number(6,2) default -1
);
3- Agregue una restricción "check" para asegurarse que no se ingresen valores negativos para el
sueldo.
Note que el campo "sueldo" tiene establecido un valor por defecto (el valor -1) que va contra la
restricción; Oracle no controla esto, permite establecer la restricción, pero al intentar ingresar un
registro con el valor por defecto en tal campo, muestra un mensaje de error.
4- Intente ingresar un registro con la palabra clave "default" en el campo "sueldo" (mensaje de
error)
5- Ingrese algunos registros válidos:
insert into empleados values ('22222222','Alberto Lopez',1,'Sistemas',1000);
insert into empleados values ('33333333','Beatriz
Garcia',2,'Administracion',3000);
insert into empleados values ('34444444','Carlos
Caseres',0,'Contaduría',6000);
6- Intente agregar otra restricción "check" al campo sueldo para asegurar que ninguno supere el
valor 5000.
La sentencia no se ejecuta porque hay un sueldo que no cumple la restricción.
7- Elimine el registro infractor y vuelva a crear la restricción
8- Establezca una restricción "check" para "seccion" que permita solamente los valores
"Sistemas", "Administracion" y "Contaduría".
9- Ingrese un registro con valor "null" en el campo "seccion".
10- Establezca una restricción "check" para "cantidadhijos" que permita solamente valores entre
0 y 15.
11- Vea todas las restricciones de la tabla (4 filas)
12- Intente agregar un registro que vaya contra alguna de las restricciones al campo "sueldo".
Mensaje de error porque se infringe la restricción "CK_empleados_sueldo_positivo".
13- Intente modificar un registro colocando en "cantidadhijos" el valor "21".
14- Intente modificar el valor de algún registro en el campo "seccion" cambiándolo por uno que
no esté incluido en la lista de permitidos.
15- Intente agregar una restricción al campo sección para aceptar solamente valores que
comiencen con la letra "B".
Note que NO se puede establecer esta restricción porque va en contra de la establecida
anteriormente para el mismo campo, si lo permitiera, no podríamos ingresar ningún valor para
"seccion".
16- Agregue un registro con documento nulo.
17- Intente agregar una restricción "primary key" para el campo "documento".
No lo permite porque existe un registro con valor nulo en tal campo.
18- Elimine el registro que infringe la restricción y establezca la restricción del punto 17.
19- Consulte "user_constraints", mostrando los campos "constraint_name", "constraint_type" y
"search_condition" de la tabla "empleados" (5 filas)
20- Consulte el catálogo "user_cons_colums" recuperando el nombre de las restricciones
establecidas en el campo sueldo de la tabla "empleados" (2 filas)
Ver solución
Segundo problema:
Una playa de estacionamiento almacena los datos de los vehículos que ingresan en la tabla
llamada "vehiculos".
1- Setee el formato de "date" para que nos muestre día, mes, año, hora y minutos:
alter session set NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI';
2- Elimine la tabla "vehiculos" y créela con la siguiente estructura:
drop table vehiculos;
create table vehiculos(
numero number(5),
patente char(6),
tipo char(4),
fechahoraentrada date,
fechahorasalida date
);
3- Ingrese algunos registros:
insert into vehiculos values(1,'AIC124','auto','17/01/2007 8:05','17/01/2007
12:30');
insert into vehiculos values(2,'CAA258','auto','17/01/2007 8:10',null);
insert into vehiculos values(3,'DSE367','moto','17/01/2007 8:30','17/01/2007
18:00');
4- Agregue una restricción de control que especifique que el campo "tipo" acepte solamente los
valores "auto" y "moto":
alter table vehiculos
add constraint CK_vehiculos_tipo_valores
check (tipo in ('auto','moto'));
5- Intente modificar el valor del campo "tipo" ingresando un valor inexistente en la lista de
valores permitidos por la restricción establecida a dicho campo.
6- Ingrese un registro con valor nulo para "tipo".
7- Agregue una restricción de control al campo "fechahoraentrada" que establezca que sus
valores no sean posteriores a "fechahorasalida".
8- Intente modificar un registro para que la salida sea anterior a la entrada.
9- Vea todas las restricciones para la tabla "vehiculos".
10- Ingrese un registro con valor nulo para "fechahoraentrada".
11- Vea todos los registros.
12- Consulte "user_cons_columns" y analice la información retornada.
Ver solución
41 - Restricciones: validación y estados
(validate - novalidate - enable - disable)
Sabemos que si agregamos una restricción a una tabla que contiene datos, Oracle los controla
para asegurarse que cumplen con la condición de la restricción, si algún registro no la cumple, la
restricción no se establecece.
Es posible deshabilitar esta comprobación estableciendo una restricción sin comprobar los datos
existentes en la tabla.
Podemos hacerlo cuando agregamos la restricción (de cualquier tipo) a una tabla para que Oracle
acepte los valores ya almacenados que infringen la restricción. Para ello debemos incluir la
opción "novalidate" en la instrucción "alter table":
alter table libros
add constraint PK_libros_codigo
primary key (codigo) novalidate;
La restricción no se aplica en los datos existentes, pero si intentamos ingresar un nuevo valor que
no cumpla la restricción (o actualizarlo), Oracle no lo permite.
Para saber si una restricción está validada o no, podemos consultar el catálogo "user_constraints"
y fijarnos lo que informa la columna "validated".
También podemos deshabilitar las restricciones para agregar o actualizar datos sin comprobarla:
alter table libros
add constraint PK_libros_codigo
primary key (codigo) disable;
Entonces, para evitar la comprobación de datos existentes y futuros al crear la restricción, la
sintaxis básica es la siguiente:
alter table TABLA
add constraint NOMBRERESTRICCION
TIPOdeRESTRICCION (CAMPO o CONDICION)--campo si es primary key o unique;
condición si es check
disable novalidate;
Por defecto (si no especificamos) la opción es "validate", es decir, controla los datos existentes y
"enable", es decir, controla futuros ingresos y actualizaciones.
También es posible alterar la restricción luego de haberla creado. Sintaxis:
alter table NOMBRETABLA
ESTADO VALIDACION
constraint NOMBRERESTRICCION;
En el ejemplo siguiente deshabilitamos la restricción "PK_libros_codigo" para poder ingresar un
valor que infrija la restricción:
alter table libros
disable validate
constraint PK_libros_codigo;
Para habilitar una restricción deshabilitada se ejecuta la misma instrucción pero con la cláusula
"enable":
alter table libros
enable validate
constraint PK_libros_codigo;
Para saber si una restricción está habilitada o no, podemos consultar el catálogo
"user_constraints" y fijarnos lo que informa la columna "status".
Los estados "validate" y "novalidate" son relativamente independientes de los estados "enabled"
y "disabled".
Cuando habilitamos una restricción "primary key" o "unique" con "enable", los datos existentes
DEBEN cumplir con la restricción; aunque coloquemos "novalidate" junto a "enable", Oracle no
permite que se habilite la restrición y valida los datos existentes de todas maneras. No sucede lo
mismo con una restricción "check"; podemos habilitar una restricción de control con "enable" y
"novalidate", Oracle habilita la restricción para futuros ingresos y actualizaciones y NO valida
los datos existentes.
Entonces, "enable" o "disable" activa o desactiva la restricción para los nuevos datos ("enable" es
la opción predeterminada si no se especifica); "validate" o "novalidate" es la opción para validar
la restricción en los datos existentes ("validate" es la predetermidada si se omite).
Una restricción puede estar en los siguientes estados:
- validate y enabled: comprueba los valores existentes y los posteriores ingresos y
actualizaciones;
- validate y disable: comprueba los valores existentes pero no las posteriores inserciones y
actualizaciones;
- novalidate y enabled: no comprueba los datos existentes, pero si los posteriores ingresos y
actualizaciones;
- novalidate y disabled: no comprueba los valores existentes ni los posteriores ingresos y
actualizaciones.
41 - Restricciones: validación y estados
(validate - novalidate - enable - disable)
Primer problema:
Una empresa tiene registrados datos de sus empleados en una tabla llamada "empleados".
1- Elimine la tabla:
drop table empleados;
2- Créela con la siguiente estructura e ingrese los registros siguientes:
create table empleados (
codigo number(6),
documento char(8),
nombre varchar2(30),
seccion varchar2(20),
sueldo number(6,2)
);
insert into empleados
values (1,'22222222','Alberto Acosta','Sistemas',-10);
insert into empleados
values (2,'33333333','Beatriz Benitez','Recursos',3000);
insert into empleados
values (3,'34444444','Carlos Caseres','Contaduria',4000);
3- Intente agregar una restricción "check" para asegurarse que no se ingresen valores negativos
para el sueldo sin especificar validación ni estado:
alter table empleados
add constraint CK_empleados_sueldo_positivo
check (sueldo>=0);
No se permite porque hay un valor negativo almacenado y por defecto la opción es "validate".
5- Vuelva a intentarlo agregando la opción "novalidate".
6- Intente ingresar un valor negativo para sueldo.
7- Deshabilite la restricción e ingrese el registro anterior.
8- Intente establecer una restricción "check" para "seccion" que permita solamente los valores
"Sistemas", "Administracion" y "Contaduría" sin especificar validación:
alter table empleados
add constraint CK_empleados_seccion_lista
check (seccion in ('Sistemas','Administracion','Contaduria'));
No lo permite porque existe un valor fuera de la lista.
9- Establezca la restricción anterior evitando que se controlen los datos existentes.
10- Vea si las restricciones de la tabla están o no habilitadas y validadas.
Muestra 2 filas, una por cada restricción; ambas son de control, ninguna valida los datos
existentes, "CK_empleados_sueldo_positivo" está deshabilitada, la otra habilitada.
11- Habilite la restricción deshabilitada.
Note que existe un sueldo que infringe la condición.
12- Intente modificar la sección del empleado "Carlos Caseres" a "Recursos"
No lo permite.
13- Deshabilite la restricción para poder realizar la actualización del punto precedente.
14- Agregue una restricción "primary key" para el campo "codigo" deshabilitada.
15- Ingrese un registro con código existente.
16- Intente habilitar la restricción.
No se permite porque aun cuando se especifica que no lo haga, Oracle verifica los datos
existentes, y existe un código repetido.
17- Modifique el registro con clave primaria repetida.
18- Habilite la restricción "primary key"
19- Agregue una restricción "unique" para el campo "documento"
20- Vea todas las restricciones de la tabla "empleados"
Muestra las 4 restricciones: 2 de control (1 habilitada y la otra no, no validan datos existentes), 1
"primary key" (habilitada y no valida datos existentes) y 1 única (habilitada y valida los datos
anteriores).
21- Deshabilite todas las restricciones de "empleados"
22- Ingrese un registro que viole todas las restricciones.
23- Habilite la restricción "CK_empleados_sueldo_positivo" sin validar los datos existentes.
24- Habilite la restricción "CK_empleados_seccion_lista" sin validar los datos existentes.
25- Intente habilitar la restricción "PK_empleados_codigo" sin validar los datos existentes.
26- Intente habilitar la restricción "UQ_empleados_documento" sin validar los datos existentes.
27- Elimine el registro que infringe con las restricciones "primary key" y "unique".
28- Habilite las restricciones "PK_empleados_codigo" y "UQ_empleados_documento" sin
validar los datos existentes.
29- Consulte el catálogo "user_constraints" y analice la información.
Ver solución
42 - Restricciones: información
(user_constraints - user_cons_columns)
El catálogo "user_constraints" muestra la información referente a todas las restricciones
establecidas en las tablas del usuario actual, devuelve varias columnas, explicaremos algunas de
ellas:
- owner: propietario de la restricción;
- constraints_name: el nombre de la restricción;
- constraint_type: tipo de restricción. Si es una restricción de control muestra el caracter "C", si
es "primary key" muestra "P", si es "unique" el caracter "U".
- table_name: nombre de la tabla en la cual se estableció la restricción;
- search_condition: solamente es aplicable a restricciones de control; indica la condición de
chequeo a cumplirse.
- status: indica si está habilitada (enabled) para futuras inserciones y actualizaciones o
deshabilitada (disabled)
- validated: indica si valida los datos existentes en la tabla (validated) o no (no validate)
El catálogo "user_cons_columns" muestra la información referente a todas las restricciones
establecidas en las tablas del usuario actual, devuelve las siguientes columnas:
- owner: propietario d la restricción;
- constraints_name: el nombre de la restricción;
- table_name: nombre de la tabla en la cual se estableció;
- column_name: muestra cada campo en el cual la restricción fue aplicada.
- position: solamente es aplicable a restricciones "primary key" y "unique"; indica el orden en
que fueron definidos los campos que componen la clave (primaria o única).
43 - Restricciones: eliminación (alter table -
drop constraint)
Para eliminar una restricción, la sintaxis básica es la siguiente:
alter table NOMBRETABLA
drop constraint NOMBRERESTRICCION;
Para eliminar la restricción "PK_libros_codigo" de la tabla libros tipeamos:
alter table libros
drop constraint PK_LIBROS_CODIGO;
Recuerde colocar el nombre de la restricción en mayúsculas, sino Oracle no la reconocerá.
Cuando eliminamos una tabla, todas las restricciones que fueron establecidas en ella, se eliminan
también.
La condición de control que debe cumplir una restricción de control no puede modificarse, hay
que eliminar la restricción y volver a crearla; igualmente con las restricciones "primary key" y
"unique", no pueden modificarse los campos.
43 - Restricciones: eliminación (alter table -
drop constraint)
Primer problema:
Una playa de estacionamiento almacena cada día los datos de los vehículos que ingresan en la
tabla llamada "vehiculos".
1- Setee el formato de "date" para que nos muestre hora y minutos:
ALTER SESSION SET NLS_DATE_FORMAT = 'HH24:MI';
2- Elimine la tabla y créela con la siguiente estructura:
drop table vehiculos;
create table vehiculos(
patente char(6) not null,
tipo char(1),--'a'=auto, 'm'=moto
horallegada date not null,
horasalida date
);
3- Establezca una restricción "check" que admita solamente los valores "a" y "m" para el campo
"tipo":
alter table vehiculos
add constraint CK_vehiculos_tipo
check (tipo in ('a','m'));
4- Agregue una restricción "primary key" que incluya los campos "patente" y "horallegada"
5- Ingrese un vehículo.
6- Intente ingresar un registro repitiendo la clave primaria.
7- Ingrese un registro repitiendo la patente pero no la hora de llegada.
8- Ingrese un registro repitiendo la hora de llegada pero no la patente.
9- Vea todas las restricciones para la tabla "vehiculos"
aparecen 4 filas, 3 correspondientes a restricciones "check" y 1 a "primary key". Dos de las
restricciones de control tienen nombres dados por Oracle.
12- Elimine la restricción "primary key"
13- Vea si se ha eliminado.
Ahora aparecen 3 restricciones.
14- Elimine la restricción de control que establece que el campo "patente" no sea nulo (busque el
nombre consultando "user_constraints").
15- Vea si se han eliminado.
16- Vuelva a establecer la restricción "primary key" eliminada.
17- La playa quiere incluir, para el campo "tipo", además de los valores permitidos "a" (auto) y
"m" (moto), el caracter "c" (camión). No puede modificar la restricción, debe eliminarla y luego
redefinirla con los 3 valores.
18- Consulte "user_constraints" para ver si la condición de chequeo de la restricción
"CK_vehiculos_tipo" se ha modificado.
Ver solución
44 - Indices.
Otros objetos de base de datos son los índices.
Los índices sirven para acceder a los registros de una tabla rápidamente, acelerando la
localización de la información.
Los índices se emplean para facilitar la obtención de información de una tabla. El indice de una
tabla desempeña la misma función que el índice de un libro: permite encontrar datos
rápidamente; en el caso de las tablas, localiza registros.
Oracle accede a los datos de dos maneras:
1) recorriendo las tablas; comenzando el principio y extrayendo los registros que cumplen las
condiciones de la consulta; lo cual implica posicionar las cabezas lectoras, leer el dato, controlar
si coincide con lo que se busca (como si pasáramos una a una las páginas de un libro buscando
un tema específico).
2) empleando índices; recorriendo la estructura de árbol del índice para localizar los registros y
extrayendo los que cumplen las condiciones de la consulta (comparando con un libro, diremos
que es como leer el índice y luego de encontrar el tema buscado, ir directamente a la página
indicada).
Un índice posibilita el acceso directo y rápido haciendo más eficiente las búsquedas. Sin índice,
Oracle debe recorrer secuencialmente toda la tabla para encontrar un registro.
Los índices son estructuras asociadas a tablas, una tabla que almacena los campos indexados y se
crean para acelerar las consultas.
Entonces, el objetivo de un indice es acelerar la recuperación de información. La indexación es
una técnica que optimiza el acceso a los datos, mejora el rendimiento acelerando las consultas y
otras operaciones. Es útil cuando la tabla contiene miles de registros, cuando se realizan
operaciones de ordenamiento y agrupamiento y cuando se combinan varias tablas (tema que
veremos más adelante).
La desventaja es que consume espacio en el disco en disco y genera costo de mantenimiento
(tiempo y recursos).
Es importante identificar el o los campos por los que sería útil crear un índice, aquellos campos
por los cuales se realizan búsquedas con frecuencia: claves primarias, claves externas o campos
que combinan tablas.
No se recomienda crear índices sobre campos que no se usan con frecuencia en consultas o en
tablas muy pequeñas.
Los cambios sobre la tabla, como inserción, actualización o eliminación de registros, son
incorporados automáticamente.
Cuando creamos una restricción "primary key" o "unique" a una tabla, Oracle automáticamente
crea un índice sobre el campo (o los campos) de la restricción y le da el mismo nombre que la
restricción. En caso que la tabla ya tenga un índice, Oracle lo usa, no crea otro.
Oracle permite crear distintos tipos de índices. "Normal" es el standard de Oracle, son índices
tipo árbol binario; contiene una entrada por cada valor de clave que almacena la dirección donde
se encuentra el dato. Es el tipo predeterminado y el más común (el único que estudiaremos).
45 - Indices (Crear - Información)
Dijimos que el objetivo de un indice es acelerar la recuperación de información y que es útil
cuando la tabla contiene miles de registros, cuando se realizan operaciones de ordenamiento y
agrupamiento, etc.
Es importante identificar el o los campos por los que sería útil crear un índice, aquellos campos
por los cuales se realizan búsquedas con frecuencia: claves primarias, claves externas o campos
que combinan tablas.
No se recomienda crear índices sobre campos que no se usan con frecuencia en consultas o en
tablas muy pequeñas.
Para crear índices empleamos la instrucción "create index".
La sintaxis básica es la siguiente:
create TIPOdeINDICE index NOMBREINDICE
on NOMBRETABLA(CAMPOS);
Los índices pueden ser: no únicos (los valores pueden estar repetidos) o únicos (los valores no
pueden duplicarse). De modo predeterminado, si no se especifica el tipo de índice, se crea uno no
único.
En el siguiente ejemplo creamos un índice único sobre el campo "documento" de la tabla
"empleados":
create unique index I_empleados_documento
on empleados(documento);
Para identificar los índices fácilmente, podemos agregar un prefijo al nombre del índice, por
ejemplo "I" y luego el nombre de la tabla y/o campo.
Si se intenta crear un índice único para un campo que tiene valores duplicados, Oracle no lo
permite.
Los campos de tipo "long" y "long raw" no pueden indexarse.
Una tabla puede indexarse por un campo (o varios).
Creamos un índice compuesto para los campos "apellido" y "nombre":
create index I_empleados_apellidonombre
on empleado(apellido,nombre);
Cuando creamos una restricción "primary key" o "unique" sobre una tabla, Oracle
automáticamente crea un índice sobre el campo (o los campos) de la restricción y le da el mismo
nombre que la restricción. En caso que la tabla ya tenga un índice, Oracle lo usa, no crea otro.
Para obtener información sobre los índices podemos consultar varios diccionarios.
1) "user_indexes": nos muestra las siguientes columnas (entre otras que no analizaremos):
- INDEX_NAME (nombre del índice),
- INDEX_TYPE (tipo de índice, nosotros crearemos el stardart normal),
- TABLE_NAME (nombre de la tabla),
- UNIQUENESS (si es único o no).
2) "user_ind_columns": nos muestra las siguientes columnas (entre otras que no analizaremos):
- INDEX_NAME (nombre del índice),
- TABLE_NAME (nombre de la tabla),
- COLUMN_NAME (nombre del campo),
- COLUMN_POSITION (posición del campo),
3) "user_objects": en la columna "OBJECT_TYPE" muestra "index" si es un índice.
4) "user_constraints": si la restricción tiene un índice asociado, aparece su nombre en la columna
"INDEX_NAME".
45 - Indices (Crear - Información)
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada "alumnos".
1- Elimine la tabla y créela con la siguiente estructura:
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
nombre varchar2(30),
curso char(1),
materia varchar2(30),
notafinal number(4,2)
);
2- Ingresamos algunos registros:
insert into alumnos values ('A123','22222222','Perez
Patricia','5','Matematica',9);
insert into alumnos values ('A234','23333333','Lopez
Ana','5','Matematica',9);
insert into alumnos values ('A345','24444444','Garcia
Carlos','6','Matematica',8.5);
insert into alumnos values ('A348','25555555','Perez
Patricia','6','Lengua',7.85);
insert into alumnos values ('A457','26666666','Perez
Fabian','6','Lengua',3.2);
3- Intente crear un índice único para el campo "nombre".
No lo permite porque hay valores duplicados.
4- Cree un índice no único, para el campo "nombre".
5- Cree un índice único, para el campo "lejago".
6- Establezca una restricción "primary key" sobre el campo "legajo".
7- Verifique que Oracle no creó un índice al agregar la restricción, utilizó el índice
"I_alumnos_legajo" existente.
8- Agregue una restricción única sobre el campo "documento".
9- Verifique que Oracle creó un índice al agregar la restricción y le dio el nombre de la
restricción.
10- Intente crear un índice único para la tabla "alumnos" sobre el campo "notafinal"
11- Indexe la tabla "alumnos" por el campo "notafinal" (índice no único)
12- Indexe la tabla "alumnos" por los campos "curso" y "materia" (índice no único)
13- Intente crear un índice único sobre "materia" (error pues hay datos duplicados)
14- Vea los indices de "alumnos"
15- Consulte el diccionario "user_ind_columns" y analice la información retornada.
16- Vea todos los índices de la base de datos activa que contengan en su nombre el patrón
"%EMPLEADOS%" (5 filas retornadas)
Ver solución
46 - Indices (eliminar)
Los índices se eliminan con "drop index"; la siguiente es la sintaxis básica:
drop index NOMBREINDICE;
Eliminamos el índice "I_empleados_documento":
drop index I_empleados_documento;
Los índices usados por las restricciones "primary key" y "unique" no pueden eliminarse con
"drop index", se eliminan automáticamente cuando quitamos la restricción.
Si eliminamos una tabla, todos los índices asociados a ella se eliminan.
46 - Indices (eliminar)
Primer problema:
Un profesor guarda algunos datos de sus alumnos en una tabla llamada "alumnos".
1- Elimine la tabla y créela con la siguiente estructura:
drop table alumnos;
create table alumnos(
legajo char(5) not null,
documento char(8) not null,
nombre varchar2(30),
curso char(1) not null,
materia varchar2(20) not null,
notafinal number(4,2)
);
2- Cree un índice no único para el campo "nombre".
3- Establezca una restricción "primary key" para el campo "legajo"
4- Verifique que se creó un índice con el nombre de la restricción.
5- Verifique que se creó un índice único con el nombre de la restricción consultando el
diccionario de índices.
6- Intente eliminar el índice "PK_alumnos_legajo" con "drop index".
7- Cree un índice único para el campo "documento".
8- Agregue a la tabla una restricción única sobre el campo "documento" y verifique que no se
creó un índice, Oracle emplea el índice creado en el punto anterior.
9- Intente eliminar el índice "I_alumnos_documento" (no se puede porque una restricción lo está
utilizando)
10- Elimine la restricción única establecida sobre "documento".
11- Verifique que el índice "I_alumnos_documento" aún existe.
12- Elimine el índice "I_alumnos_documento", ahora puede hacerlo porque no hay restricción
que lo utilice.
13-Elimine el índice "I_alumnos_nombre".
14- Elimine la restricción "primary key"/
15- Verifique que el índice "PK_alumnos_legajo" fue eliminado (porque fue creado por Oracle al
establecerse la restricción)
16- Cree un índice compuesto por los campos "curso" y "materia", no único.
17- Verifique su existencia.
18- Elimine la tabla "alumnos" y verifique que todos los índices han sido eliminados junto con
ella.
Ver solución
47 - Varias tablas (join)
Hasta el momento hemos trabajado con una sola tabla, pero generalmente, se trabaja con más de
una.
Para evitar la repetición de datos y ocupar menos espacio, se separa la información en varias
tablas. Cada tabla almacena parte de la información que necesitamos registrar.
Por ejemplo, los datos de nuestra tabla "libros" podrían separarse en 2 tablas, una llamada
"libros" y otra "editoriales" que guardará la información de las editoriales. En nuestra tabla
"libros" haremos referencia a la editorial colocando un código que la identifique. Veamos:
create table libros(
codigo number(4),
titulo varchar2(40) not null,
autor varchar2(30),
codigoeditorial number(3) not null,
precio number(5,2),
primary key (codigo)
);
create table editoriales(
codigo number(3),
nombre varchar2(20) not null,
primary key(codigo)
);
De esta manera, evitamos almacenar tantas veces los nombres de las editoriales en la tabla
"libros" y guardamos el nombre en la tabla "editoriales"; para indicar la editorial de cada libro
agregamos un campo que hace referencia al código de la editorial en la tabla "libros" y en
"editoriales".
Al recuperar los datos de los libros con la siguiente instrucción:
select* from libros;
vemos que en el campo "editorial" aparece el código, pero no sabemos el nombre de la editorial.
Para obtener los datos de cada libro, incluyendo el nombre de la editorial, necesitamos consultar
ambas tablas, traer información de las dos.
Cuando obtenemos información de más de una tabla decimos que hacemos un "join"
(combinación).
Veamos un ejemplo:
select *from libros
join editoriales
on [Link]=[Link];
Resumiendo: si distribuimos la información en varias tablas evitamos la redundancia de datos y
ocupamos menos espacio físico en el disco. Un join es una operación que relaciona dos o más
tablas para obtener un resultado que incluya datos (campos y registros) de ambas; las tablas
participantes se combinan según los campos comunes a ambas tablas.
Hay tres tipos de combinaciones. En los siguientes capítulos explicamos cada una de ellas.
48 - Combinación interna (join)
Un join es una operación que relaciona dos o más tablas para obtener un resultado que incluya
datos (campos y registros) de ambas; las tablas participantes se combinan según los campos
comunes a ambas tablas.
Hay tres tipos de combinaciones:
1) combinaciones internas (inner join o join),
2) combinaciones externas y
3) combinaciones cruzadas.
También es posible emplear varias combinaciones en una consulta "select", incluso puede
combinarse una tabla consigo misma.
La combinación interna emplea "join", que es la forma abreviada de "inner join". Se emplea para
obtener información de dos tablas y combinar dicha información en una salida.
La sintaxis básica es la siguiente:
select CAMPOS
from TABLA1
join TABLA2
on CONDICIONdeCOMBINACION;
Ejemplo:
select *from libros
join editoriales
on codigoeditorial=[Link];
Analicemos la consulta anterior.
- especificamos los campos que aparecerán en el resultado en la lista de selección;
- indicamos el nombre de la tabla luego del "from" ("libros");
- combinamos esa tabla con "join" y el nombre de la otra tabla ("editoriales"); se especifica qué
tablas se van a combinar y cómo;
- cuando se combina información de varias tablas, es necesario especificar qué registro de una
tabla se combinará con qué registro de la otra tabla, con "on". Se debe especificar la condición
para enlazarlas, es decir, el campo por el cual se combinarán, que tienen en común. "on" hace
coincidir registros de ambas tablas basándose en el valor de tal campo, en el ejemplo, el campo
"codigoeditorial" de "libros" y el campo "codigo" de "editoriales" son los que enlazarán ambas
tablas. Se emplean campos comunes, que deben tener tipos de datos iguales o similares.
La condicion de combinación, es decir, el o los campos por los que se van a combinar (parte
"on"), se especifica según las claves primarias y externas.
Note que en la consulta, al nombrar el campo usamos el nombre de la tabla también. Cuando las
tablas referenciadas tienen campos con igual nombre, esto es necesario para evitar confusiones y
ambiguedades al momento de referenciar un campo. En el ejemplo, si no especificamos
"[Link]" y solamente tipeamos "codigo", Oracle no sabrá si nos referimos al campo
"codigo" de "libros" o de "editoriales" y mostrará un mensaje de error indicando que "codigo" es
ambiguo.
Entonces, si las tablas que combinamos tienen nombres de campos iguales, DEBE especificarse
a qué tabla pertenece anteponiendo el nombre de la tabla al nombre del campo, separado por un
punto (.).
Si una de las tablas tiene clave primaria compuesta, al combinarla con la otra, en la cláusula "on"
se debe hacer referencia a la clave completa, es decir, la condición referenciará a todos los
campos clave que identifican al registro.
Se puede incluir en la consulta join la cláusula "where" para restringir los registros que retorna el
resultado; también "order by", "distinct", etc..
Se emplea este tipo de combinación para encontrar registros de la primera tabla que se
correspondan con los registros de la otra, es decir, que cumplan la condición del "on". Si un valor
de la primera tabla no se encuentra en la segunda tabla, el registro no aparece; si en la primera
tabla el valor es nulo, tampoco aparece.
Para simplificar la sentencia podemos usar un alias para cada tabla:
select [Link],titulo,autor,nombre
from libros l
join editoriales e
on [Link]=[Link];
En algunos casos (como en este ejemplo) el uso de alias es para fines de simplificación y hace
más legible la consulta si es larga y compleja, pero en algunas consultas es absolutamente
necesario.
48 - Combinación interna (join)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias":
drop table clientes;
drop table provincias;
2- Créelas con las siguientes estructuras:
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(2)
);
create table provincias(
codigo number(2),
nombre varchar2(20)
);
3- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Corrientes');
insert into provincias values(null,'La Pampa');
insert into clientes values (1,'Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes values (2,'Perez Ana','San Martin 222','Cruz del
Eje',1);
insert into clientes values (3,'Garcia Juan','Rivadavia 333','Villa
Maria',null);
insert into clientes values (4,'Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values (5,'Pereyra Lucas','San Martin 555','Cruz del
Eje',1);
insert into clientes values (6,'Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values (7,'Torres Fabiola','Alem 777','Ibera',3);
insert into clientes values (8,'Garcia Paco','Avellaneda 888','Rawson',5);
4- Obtenga los datos de ambas tablas, usando alias.
Note que los registros de "clientes" cuyo valor de "codigoprovincia" que NO encuentran
coincidencia con "codigo" de "provincias" no aparecen en el resultado de la consulta; caso de
"Garcia Juan", que código de provincia nulo y "Garcia Paco", que tiene un código de provincia
que no está presente en "provincias".
5- Obtenga la misma información anterior pero ordenada por nombre de provincia (join y order
by)
6- Recupere todos los datos de los clientes de la provincia "Santa Fe" (join con where) (2
registros devueltos)
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes. Almacena la información en una tabla llamada
"inscriptos" que incluye el documento, el nombre, el deporte y si la matricula esta paga o no y
una tabla llamada "inasistencias" que incluye el documento, el deporte y la fecha de la
inasistencia.
1- Elimine las tablas y créelas:
drop table inscriptos;
drop table inasistencias;
create table inscriptos(
nombre varchar2(30),
documento char(8),
deporte varchar2(15),
matricula char(1), --'s'=paga; 'n'=impaga
primary key(documento,deporte)
);
create table inasistencias(
documento char(8),
deporte varchar2(15),
fecha date
);
2- Ingrese algunos registros para ambas tablas:
insert into inscriptos values('Juan Perez','22222222','tenis','s');
insert into inscriptos values('Maria Lopez','23333333','tenis','s');
insert into inscriptos values('Agustin Juarez','24444444','tenis','n');
insert into inscriptos values('Marta Garcia','25555555','natacion','s');
insert into inscriptos values('Juan Perez','22222222','natacion','s');
insert into inscriptos values('Maria Lopez','23333333','natacion','n');
insert into inasistencias values('22222222','tenis','01/12/2006');
insert into inasistencias values('22222222','tenis','08/12/2006');
insert into inasistencias values('23333333','tenis','01/12/2006');
insert into inasistencias values('24444444','tenis','08/12/2006');
insert into inasistencias values('22222222','natacion','02/12/2006');
insert into inasistencias values('23333333','natacion','02/12/2006');
3- Muestre el nombre, el deporte y las fechas de inasistencias, ordenado por nombre y deporte.
Note que la condición es compuesta porque para identificar los registros de la tabla
"inasistencias" necesitamos ambos campos.
Note que la persona con documento '25555555' no aparece en la consulta porque no está presente
en "inasistencias".
4- Obtenga el nombre, deporte y las fechas de inasistencias de un determinado inscripto en un
determinado deporte (3 registros).
5- Obtenga el nombre, deporte y las fechas de inasistencias de todos los inscriptos que pagaron la
matrícula (4 registros)
Ver solución
49 - Combinación externa izquierda (left
join)
Vimos que una combinación interna (join) encuentra registros de la primera tabla que se
correspondan con los registros de la segunda, es decir, que cumplan la condición del "on" y si un
valor de la primera tabla no se encuentra en la segunda tabla, el registro no aparece.
Si queremos saber qué registros de una tabla NO encuentran correspondencia en la otra, es decir,
no existe valor coincidente en la segunda, necesitamos otro tipo de combinación, "outer join"
(combinación externa).
Las combinaciones externas combinan registros de dos tablas que cumplen la condición, más los
registros de la segunda tabla que no la cumplen; es decir, muestran todos los registros de las
tablas relacionadas, aún cuando no haya valores coincidentes entre ellas.
Este tipo de combinación se emplea cuando se necesita una lista completa de los datos de una de
las tablas y la información que cumple con la condición. Las combinaciones externas se realizan
solamente entre 2 tablas.
Hay tres tipos de combinaciones externas: "left outer join", "right outer join" y "full outer join";
se pueden abreviar con "left join", "right join" y "full join" respectivamente.
Vamos a estudiar las primeras.
Se emplea una combinación externa izquierda para mostrar todos los registros de la tabla de la
izquierda. Si no encuentra coincidencia con la tabla de la derecha, el registro muestra los campos
de la segunda tabla seteados a "null".
En el siguiente ejemplo solicitamos el título y nombre de la editorial de los libros:
select titulo,nombre
from editoriales e
left join libros l
on codigoeditorial = [Link];
El resultado mostrará el título y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo código de editorial no está presente en "libros" aparece en el resultado, pero con el
valor "null" en el campo "titulo".
Es importante la posición en que se colocan las tablas en un "left join", la tabla de la izquierda es
la que se usa para localizar registros en la tabla de la derecha.
Entonces, un "left join" se usa para hacer coincidir registros en una tabla (izquierda) con otra
tabla (derecha); si un valor de la tabla de la izquierda no encuentra coincidencia en la tabla de la
derecha, se genera una fila extra (una por cada valor no encontrado) con todos los campos
correspondientes a la tabla derecha seteados a "null". La sintaxis básica es la siguiente:
select CAMPOS
from TABLAIZQUIERDA
left join TABLADERECHA
on CONDICION;
En el siguiente ejemplo solicitamos el título y el nombre la editorial, la sentencia es similar a la
anterior, la diferencia está en el orden de las tablas:
select titulo,nombre
from libros l
left join editoriales e
on codigoeditorial = [Link];
El resultado mostrará el título del libro y el nombre de la editorial; los títulos cuyo código de
editorial no está presente en "editoriales" aparecen en el resultado, pero con el valor "null" en el
campo "nombre".
Un "left join" puede tener clausula "where" que restringa el resultado de la consulta
considerando solamente los registros que encuentran coincidencia en la tabla de la derecha, es
decir, cuyo valor de código está presente en "libros":
select titulo,nombre
from editoriales e
left join libros l
on [Link]=codigoeditorial
where codigoeditorial is not null;
También podemos mostrar las editoriales que NO están presentes en "libros", es decir, que NO
encuentran coincidencia en la tabla de la derecha:
select titulo,nombre
from editoriales e
left join libros l
on [Link]=codigoeditorial
where codigoeditorial is null;
49 - Combinación externa izquierda (left
join)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias", créelas y agregue restricciones únicas para los
campos "codigo" de ambas tablas:
drop table clientes;
drop table provincias;
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(3)
);
create table provincias(
codigo number(3),
nombre varchar2(20)
);
alter table clientes
add constraints UQ_clientes_codigo
unique (codigo);
alter table provincias
add constraints UQ_provincias_codigo
unique (codigo);
2- Ingrese algunos registros para ambas tablas. Incluya valores nulos para el campo "codigo" de
"provincias" y valores nulos para el campo "codigoprovincia" de "clientes". Incluya en "clientes"
un código de provincia que no exista en "provincias":
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Corrientes');
insert into provincias values(4,'Santa Cruz');
insert into provincias values(null,'Salta');
insert into provincias values(null,'Jujuy');
insert into clientes values (100,'Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes values (200,'Perez Ana','San Martin 222','Cruz del
Eje',1);
insert into clientes values (300,'Garcia Juan','Rivadavia 333','Villa
Maria',null);
insert into clientes values (400,'Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values (500,'Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values (600,'Torres Fabiola','Alem 777','La Plata',5);
insert into clientes values (700,'Garcia Luis','Sucre 475','Santa
Rosa',null);
3- Muestre todos los datos de los clientes, incluido el nombre de la provincia
Note que los clientes de "Santa Rosa", "Villa Maria" y "La Plata" se muestran seteados a null en
la columna corespondiente al nombre de la provincia porque tienen valores nulos o inexistentes.
4- Realice la misma consulta anterior pero alterando el orden de las tablas.
5- Muestre solamente los clientes de las provincias que existen en "provincias" (4 registros)
Note que los clientes de "Jujuy", "Salta", "Santa Cruz" y "Corrientes" se muestran seteados a null
en los campos pertenecientes a la tabla "clientes" porque tienen valores nulos o inexistentes en
dicha tabla.
6- Muestre todos los clientes cuyo código de provincia NO existe en "provincias" ordenados por
nombre del cliente (3 registros)
7- Obtenga todos los datos de los clientes de "Cordoba" (2 registros)
Ver solución
50 - Combinación externa derecha (right
join)
Vimos que una combinación externa izquierda (left join) encuentra registros de la tabla izquierda
que se correspondan con los registros de la tabla derecha y si un valor de la tabla izquierda no se
encuentra en la tabla derecha, el registro muestra los campos correspondientes a la tabla de la
derecha seteados a "null".
Una combinación externa derecha ("right outer join" o "right join") opera del mismo modo sólo
que la tabla derecha es la que localiza los registros en la tabla izquierda.
En el siguiente ejemplo solicitamos el título y nombre de la editorial de los libros empleando un
"right join":
select titulo,nombre as editorial
from libros l
right join editoriales e
on codigoeditorial = [Link];
El resultado mostrará el título y nombre de la editorial; las editoriales de las cuales no hay libros,
es decir, cuyo código de editorial no está presente en "libros" aparece en el resultado, pero con el
valor "null" en el campo "titulo".
Es FUNDAMENTAL tener en cuenta la posición en que se colocan las tablas en los "outer join".
En un "left join" la primera tabla (izquierda) es la que busca coincidencias en la segunda tabla
(derecha); en el "right join" la segunda tabla (derecha) es la que busca coincidencias en la
primera tabla (izquierda).
En la siguiente consulta empleamos un "left join" para conseguir el mismo resultado que el "right
join" anterior":
select titulo,nombre
from editoriales e
left join libros l
on codigoeditorial = [Link];
Note que la tabla que busca coincidencias ("editoriales") está en primer lugar porque es un "left
join"; en el "right join" precedente, estaba en segundo lugar.
Un "right join" hace coincidir registros en una tabla (derecha) con otra tabla (izquierda); si un
valor de la tabla de la derecha no encuentra coincidencia en la tabla izquierda, se genera una fila
extra (una por cada valor no encontrado) con todos los campos correspondientes a la tabla
izquierda seteados a "null". La sintaxis básica es la siguiente:
select CAMPOS
from TABLAIZQUIERDA
right join TABLADERECHA
on CONDICION;
Un "right join" también puede tener cláusula "where" que restringa el resultado de la consulta
considerando solamente los registros que encuentran coincidencia en la tabla izquierda:
select titulo,nombre
from libros l
right join editoriales e
on [Link]=codigoeditorial
where codigoeditorial is not null;
Mostramos las editoriales que NO están presentes en "libros", es decir, que NO encuentran
coincidencia en la tabla de la derecha empleando un "right join":
select titulo,nombre
from libros l
right join editoriales e
on [Link]=codigoeditorial
where codigoeditorial is null;
50 - Combinación externa derecha (right
join)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias" y créelas:
drop table clientes;
drop table provincias;
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(2),
primary key(codigo)
);
create table provincias(
codigo number(2),
nombre varchar2(20),
primary key (codigo)
);
2- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Corrientes');
insert into clientes values (101,'Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes values (102,'Perez Ana','San Martin 222','Cruz del
Eje',1);
insert into clientes values (103,'Garcia Juan','Rivadavia 333','Villa
Maria',1);
insert into clientes values (104,'Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values (105,'Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values (106,'Torres Fabiola','Alem 777','La Plata',4);
insert into clientes values (107,'Garcia Luis','Sucre 475','Santa Rosa',5);
3- Muestre todos los datos de los clientes, incluido el nombre de la provincia empleando un
"right join".
4- Obtenga la misma salida que la consulta anterior pero empleando un "left join".
5- Empleando un "right join", muestre solamente los clientes de las provincias que existen en
"provincias" (5 registros)
6- Muestre todos los clientes cuyo código de provincia NO existe en "provincias" ordenados por
ciudad (2 registros)
Ver solución
51 - Combinación externa completa (full join)
Vimos que un "left join" encuentra registros de la tabla izquierda que se correspondan con los
registros de la tabla derecha y si un valor de la tabla izquierda no se encuentra en la tabla
derecha, el registro muestra los campos correspondientes a la tabla de la derecha seteados a
"null". Aprendimos también que un "right join" opera del mismo modo sólo que la tabla derecha
es la que localiza los registros en la tabla izquierda.
Una combinación externa completa ("full outer join" o "full join") retorna todos los registros de
ambas tablas. Si un registro de una tabla izquierda no encuentra coincidencia en la tabla derecha,
las columnas correspondientes a campos de la tabla derecha aparecen seteadas a "null", y si la
tabla de la derecha no encuentra correspondencia en la tabla izquierda, los campos de esta última
aparecen conteniendo "null".
Veamos un ejemplo:
select titulo,nombre
from editoriales e
full join libros l
on codigoeditorial = [Link];
La salida del "full join" precedente muestra todos los registros de ambas tablas, incluyendo los
libros cuyo código de editorial no existe en la tabla "editoriales" y las editoriales de las cuales no
hay correspondencia en "libros".
51 - Combinación externa completa (full
join)
Primer problema:
Un club dicta clases de distintos deportes. Almacena la información en una tabla llamada
"deportes" en la cual incluye el nombre del deporte y el nombre del profesor y en otra tabla
llamada "inscriptos" que incluye el documento del socio que se inscribe, el deporte y si la
matricula está paga o no.
1- Elimine las tablas, créelas y agregue dos restricciones, una "primary key" sobre el campo
"codigo" de "deportes" y otra compuesta por "documento" y "codigodeporte" de "inscriptos":
drop table deportes;
drop table inscriptos;
create table deportes(
codigo number(2),
nombre varchar2(30),
profesor varchar2(30)
);
create table inscriptos(
documento char(8),
codigodeporte number(2),
matricula char(1) --'s'=paga; 'n'=impaga
);
alter table deportes
add constraint PK_deportes
primary key(codigo);
alter table inscriptos
add constraint PK_inscriptos
primary key(documento,codigodeporte);
2- Ingrese algunos registros para ambas tablas:
insert into deportes values(1,'tenis','Marcelo Roca');
insert into deportes values(2,'natacion','Marta Torres');
insert into deportes values(3,'basquet','Luis Garcia');
insert into deportes values(4,'futbol','Marcelo Roca');
insert into inscriptos values('22222222',3,'s');
insert into inscriptos values('23333333',3,'s');
insert into inscriptos values('24444444',3,'n');
insert into inscriptos values('22222222',2,'s');
insert into inscriptos values('23333333',2,'s');
insert into inscriptos values('22222222',4,'n');
insert into inscriptos values('22222222',5,'n');
3- Muestre todos la información de la tabla "inscriptos", y consulte la tabla "deportes" para
obtener el nombre de cada deporte (6 registros)
Note que uno de los registros tiene seteado a null la columna "deporte".
4- Empleando un "left join" con "deportes" obtenga todos los datos de los inscriptos (7 registros)
5- Obtenga la misma salida anterior empleando un "rigth join"
Note que se cambia el orden de las tablas y "right" por "left".
6- Muestre los deportes para los cuales no hay inscriptos, empleando un "left join" (1 registro)
7- Muestre los documentos de los inscriptos a deportes que no existen en la tabla "deportes" (1
registro)
8- Emplee un "full join" para obtener todos los datos de ambas tablas, incluyendo las
inscripciones a deportes inexistentes en "deportes" y los deportes que no tienen inscriptos (8
registros)
Note que uno de los registros con documento "22222222" tiene seteado a "null" los campos
correspondientes a "deportes" porque el código "5" no está presente en "deportes"; otro registro,
que muestra "tenis" y "Marcelo Roca", tiene valores nulos en los campos correspondientes a la
tabla "inscriptos", ya que, para el deporte con código 1, no hay inscriptos.
Ver solución
52 - Combinaciones cruzadas (cross)
Vimos que hay tres tipos de combinaciones: 1) combinaciones internas (join), 2) combinaciones
externas (left, outer y full join) y 3) combinaciones cruzadas.
Las combinaciones cruzadas (cross join) muestran todas las combinaciones de todos los registros
de las tablas combinadas. Para este tipo de join no se incluye una condición de enlace. Se genera
el producto cartesiano en el que el número de filas del resultado es igual al número de registros
de la primera tabla multiplicado por el número de registros de la segunda tabla, es decir, si hay 3
registros en una tabla y 4 en la otra, retorna 12 filas.
La sintaxis básica es ésta:
select CAMPOS
from TABLA1
cross join TABLA2;
Veamos un ejemplo. Un pequeño restaurante almacena los nombres y precios de sus comidas en
una tabla llamada "comidas" y en una tabla denominada "postres" los mismos datos de sus
postres.
Si necesitamos conocer todas las combinaciones posibles para un menú, cada comida con cada
postre, empleamos un "cross join":
select [Link] as "plato principal", [Link] as "postre"
from comidas c
cross join postres p;
La salida muestra cada plato combinado con cada uno de los postres.
Como cualquier tipo de "join", puede emplearse una cláusula "where" que condicione la salida.
Este tipo de join no es muy utilizado.
52 - Combinaciones cruzadas (cross)
Primer problema:
Una agencia matrimonial almacena la información de sus clientes de sexo femenino en una tabla
llamada "mujeres" y en otra la de sus clientes de sexo masculino llamada "varones".
1- Elimine las tablas y créelas con las siguientes estructuras:
drop table mujeres;
drop table varones;
create table mujeres(
nombre varchar2(30),
domicilio varchar2(30),
edad number(2)
);
create table varones(
nombre varchar2(30),
domicilio varchar2(30),
edad number(2)
);
2- Ingrese los siguientes registros:
insert into mujeres values('Maria Lopez','Colon 123',45);
insert into mujeres values('Liliana Garcia','Sucre 456',35);
insert into mujeres values('Susana Lopez','Avellaneda 98',41);
insert into varones values('Juan Torres','Sarmiento 755',44);
insert into varones values('Marcelo Oliva','San Martin 874',56);
insert into varones values('Federico Pereyra','Colon 234',38);
insert into varones values('Juan Garcia','Peru 333',50);
3- La agencia necesita la combinación de todas las personas de sexo femenino con las de sexo
masculino. Use un "cross join" (12 filas)
4- Realice la misma combinación pero considerando solamente las personas mayores de 40 años
(6 filas)
5- Forme las parejas pero teniendo en cuenta que no tengan una diferencia superior a 10 años (8
filas)
Ver solución
Segundo problema:
Una empresa de seguridad almacena los datos de sus guardias de seguridad en una tabla llamada
"guardias". también almacena los distintos sitios que solicitaron sus servicios en una tabla
llamada "tareas".
1- Elimine las tablas "guardias" y "tareas":
drop table guardias;
drop table tareas;
2- Cree las tablas:
create table guardias(
documento char(8),
nombre varchar2(30),
sexo char(1), /* 'f' o 'm' */
domicilio varchar2(30),
primary key (documento)
);
create table tareas(
codigo number(2),
domicilio varchar2(30),
descripcion varchar2(30),
horario char(2), /* 'AM' o 'PM'*/
primary key (codigo)
);
3- Ingrese los siguientes registros:
insert into guardias values('22333444','Juan Perez','m','Colon 123');
insert into guardias values('24333444','Alberto Torres','m','San Martin
567');
insert into guardias values('25333444','Luis Ferreyra','m','Chacabuco 235');
insert into guardias values('23333444','Lorena Viale','f','Sarmiento 988');
insert into guardias values('26333444','Irma Gonzalez','f','Mariano Moreno
111');
insert into tareas values(1,'Colon 1111','vigilancia exterior','AM');
insert into tareas values(2,'Urquiza 234','vigilancia exterior','PM');
insert into tareas values(3,'Peru 345','vigilancia interior','AM');
insert into tareas values(4,'Avellaneda 890','vigilancia interior','PM');
4- La empresa quiere que todos sus empleados realicen todas las tareas. Realice un "cross join"
(20 filas)
5- En este caso, la empresa quiere que todos los guardias de sexo femenino realicen las tareas de
"vigilancia interior" y los de sexo masculino de "vigilancia exterior". Realice una "cross join"
con un "where" que controle tal requisito (10 filas)
Ver solución
53 - Autocombinación
Dijimos que es posible combinar una tabla consigo misma.
Un pequeño restaurante tiene almacenadas sus comidas en una tabla llamada "comidas" que
consta de los siguientes campos:
- nombre varchar(20),
- precio decimal (4,2) y
- rubro char(6)-- que indica con 'plato' si es un plato principal y 'postre'
si es postre.
Podemos obtener la combinación de todos los platos empleando un "cross join" con una sola
tabla:
select [Link],
[Link],
[Link]+[Link] as total
from comidas c1
cross join comidas c2;
En la consulta anterior aparecerán filas duplicadas, para evitarlo debemos emplear un "where":
select [Link] as "plato principal",
[Link] as postre,
[Link]+[Link] as total
from comidas c1
cross join comidas c2
where [Link]='plato' and
[Link]='postre';
En la consulta anterior se empleó un "where" que especifica que se combine "plato" con "postre".
En una autocombinación se combina una tabla con una copia de si misma. Para ello debemos
utilizar 2 alias para la tabla. Para evitar que aparezcan filas duplicadas, debemos emplear un
"where".
También se puede realizar una autocombinación con "join":
select [Link] as "plato principal",
[Link] as postre,
[Link]+[Link] as total
from comidas c1
join comidas c2
on [Link]<>[Link]
where [Link]='plato' and
[Link]='postre';
Para que no aparezcan filas duplicadas se agrega un "where".
53 - Autocombinación
Primer problema:
Una agencia matrimonial almacena la información de sus clientes en una tabla llamada
"clientes".
1- Elimine la tabla y créela:
drop table clientes;
create table clientes(
nombre varchar2(30),
sexo char(1),--'f'=femenino, 'm'=masculino
edad number(2),
domicilio varchar2(30)
);
2- Ingrese los siguientes registros:
insert into clientes values('Maria Lopez','f',45,'Colon 123');
insert into clientes values('Liliana Garcia','f',35,'Sucre 456');
insert into clientes values('Susana Lopez','f',41,'Avellaneda 98');
insert into clientes values('Juan Torres','m',44,'Sarmiento 755');
insert into clientes values('Marcelo Oliva','m',56,'San Martin 874');
insert into clientes values('Federico Pereyra','m',38,'Colon 234');
insert into clientes values('Juan Garcia','m',50,'Peru 333');
3- La agencia necesita la combinación de todas las personas de sexo femenino con las de sexo
masculino. Use un "cross join" (12 filas)
4- Obtenga la misma salida anterior pero realizando un "join"
5- Realice la misma autocombinación que el punto 3 pero agregue la condición que las parejas
no tengan una diferencia superior a 5 años (5 filas)
Ver solución
Segundo problema:
Varios clubes de barrio se organizaron para realizar campeonatos entre ellos. La tabla llamada
"equipos" guarda la información de los distintos equipos que jugarán.
1- Elimine la tabla y créela nuevamente:
drop table equipos;
create table equipos(
nombre varchar2(30),
barrio varchar2(20),
domicilio varchar2(30),
entrenador varchar2(30)
);
2- Ingrese los siguientes registros:
insert into equipos values('Los tigres','Gral. Paz','Sarmiento 234','Juan
Lopez');
insert into equipos values('Los leones','Centro','Colon 123','Gustavo
Fuentes');
insert into equipos values('Campeones','Pueyrredon','Guemes 346','Carlos
Moreno');
insert into equipos values('Cebollitas','Alberdi','Colon 1234','Luis
Duarte');
4- Cada equipo jugará con todos los demás 2 veces, una vez en cada sede. Realice un "cross join"
para combinar los equipos teniendo en cuenta que un equipo no juega consigo mismo (12 filas)
5- Obtenga el mismo resultado empleando un "join".
6- Realice un "cross join" para combinar los equipos para que cada equipo juegue con cada uno
de los otros una sola vez (6 filas)
Ver solución
54 - Combinaciones y funciones de
agrupamiento
Podemos usar "group by" y las funciones de agrupamiento con combinaciones de tablas.
Para ver la cantidad de libros de cada editorial consultando la tabla "libros" y "editoriales",
tipeamos:
select nombre as editorial,
count(*) as cantidad
from editoriales e
join libros l
on codigoeditorial=[Link]
group by [Link];
Las editoriales que no tienen libros no aparecen en la salida porque empleamos un "join".
Empleamos otra función de agrupamiento con "left join". Para conocer el mayor precio de los
libros de cada editorial usamos la función "max()", hacemos un "left join" y agrupamos por
nombre de la editorial:
select nombre as editorial,
max(precio) as "mayor precio"
from editoriales e
left join libros l
on codigoeditorial=[Link]
group by nombre;
En la sentencia anterior, mostrará, para la editorial de la cual no haya libros, el valor "null" en la
columna calculada.
54 - Combinaciones y funciones de
agrupamiento
Primer problema:
Un comercio que tiene un stand en una feria registra en una tabla llamada "visitantes" algunos
datos de las personas que visitan o compran en su stand para luego enviarle publicidad de sus
productos y en otra tabla llamada "ciudades" los nombres de las ciudades.
1- Elimine las tablas:
drop table visitantes;
drop table ciudades;
2- Cree las tablas:
create table visitantes(
nombre varchar2(30),
edad number(2),
sexo char(1) default 'f',
domicilio varchar2(30),
codigociudad number(2),
mail varchar(30),
montocompra decimal (6,2)
);
create table ciudades(
codigo number(2),
nombre varchar(20)
);
3- Ingrese algunos registros:
insert into ciudades values(1,'Cordoba');
insert into ciudades values(2,'Carlos Paz');
insert into ciudades values(3,'La Falda');
insert into ciudades values(4,'Cruz del Eje');
insert into visitantes values ('Susana Molina', 35,'f','Colon 123', 1,
null,59.80);
insert into visitantes values ('Marcos Torres', 29,'m','Sucre 56', 1,
'marcostorres@[Link]',150.50);
insert into visitantes values ('Mariana Juarez', 45,'f','San Martin
111',2,null,23.90);
insert into visitantes values ('Fabian Perez',36,'m','Avellaneda
213',3,'fabianperez@[Link]',0);
insert into visitantes values ('Alejandra Garcia',28,'f',null,2,null,280.50);
insert into visitantes values ('Gaston
Perez',29,'m',null,5,'gastonperez1@[Link]',95.40);
insert into visitantes values ('Mariana Juarez',33,'f',null,2,null,90);
4- Cuente la cantidad de visitas por ciudad mostrando el nombre de la ciudad (3 filas)
5- Muestre el promedio de gastos de las visitas agrupados por ciudad y sexo (4 filas)
6- Muestre la cantidad de visitantes con mail, agrupados por ciudad (3 filas)
7- Obtenga el monto de compra más alto de cada ciudad (3 filas)
8- Realice la misma consulta anterior pero con "left join" (4 filas)
Note que aparece el monto "95,4" con valor nulo en el campo correspondiente a la ciudad, ya que
ese registro tiene un valor inexistente en "ciudades".
Ver solución
55 - Combinar más de 2 tablas
Podemos hacer un "join" con más de dos tablas.
La librería almacena los datos de sus libros en tres tablas: libros, editoriales y autores.
En la tabla "libros" un campo "codigoautor" hace referencia al autor y un campo
"codigoeditorial" referencia la editorial.
Para recuperar todos los datos de los libros empleamos la siguiente consulta:
select titulo,[Link],[Link]
from autores a
join libros l
on codigoautor=[Link]
join editoriales e
on codigoeditorial=[Link];
Analicemos la consulta anterior. Indicamos el nombre de la tabla luego del "from" ("autores"),
combinamos esa tabla con la tabla "libros" especificando con "on" el campo por el cual se
combinarán; luego debemos hacer coincidir los valores para el enlace con la tabla "editoriales"
enlazándolas por los campos correspondientes. Utilizamos alias para una sentencia más sencilla
y comprensible.
Note que especificamos a qué tabla pertenecen los campos cuyo nombre se repiten en las tablas,
esto es necesario para evitar confusiones y ambiguedades al momento de referenciar un campo.
Los libros cuyo código de autor no se encuentra en "autores" y cuya editorial no existe en
"editoriales", no aparecen porque realizamos una combinación interna.
Podemos combinar varios tipos de join en una misma sentencia:
select titulo,[Link],[Link]
from autores a
right join libros l
on codigoautor=[Link]
left join editoriales e
on codigoeditorial=[Link];
En la consulta anterior solicitamos el título, autor y editorial de todos los libros que encuentren o
no coincidencia con "autores" ("right join") y a ese resultado lo combinamos con "editoriales",
encuentren o no coincidencia.
Es posible realizar varias combinaciones para obtener información de varias tablas. Las tablas
deben tener claves externas relacionadas con las tablas a combinar.
En consultas en las cuales empleamos varios "join" es importante tener en cuenta el orden de las
tablas y los tipos de "join".
55 - Combinar más de 2 tablas
Primer problema:
Un club dicta clases de distintos deportes. En una tabla llamada "socios" guarda los datos de los
socios, en una tabla llamada "deportes" la información referente a los diferentes deportes que se
dictan y en una tabla denominada "inscriptos", las inscripciones de los socios a los distintos
deportes.
Un socio puede inscribirse en varios deportes el mismo año. Un socio no puede inscribirse en el
mismo deporte el mismo año. Distintos socios se inscriben en un mismo deporte en el mismo
año.
1- Elimine las tablas:
drop table socios;
drop table deportes;
drop table inscriptos;
2- Cree las tablas con las siguientes estructuras:
create table socios(
documento char(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
primary key(documento)
);
create table deportes(
codigo number(2),
nombre varchar2(20),
profesor varchar2(15),
primary key(codigo)
);
create table inscriptos(
documento char(8) not null,
codigodeporte number(2) not null,
año char(4),
matricula char(1),--'s'=paga, 'n'=impaga
primary key(documento,codigodeporte,año)
);
3- Ingrese algunos registros en "socios":
insert into socios values('22222222','Ana Acosta','Avellaneda 111');
insert into socios values('23333333','Betina Bustos','Bulnes 222');
insert into socios values('24444444','Carlos Castro','Caseros 333');
insert into socios values('25555555','Daniel Duarte','Dinamarca 44');
4- Ingrese algunos registros en "deportes":
insert into deportes values(1,'basquet','Juan Juarez');
insert into deportes values(2,'futbol','Pedro Perez');
insert into deportes values(3,'natacion','Marina Morales');
insert into deportes values(4,'tenis','Marina Morales');
5- Inscriba a varios socios en el mismo deporte en el mismo año:
insert into inscriptos values ('22222222',3,'2006','s');
insert into inscriptos values ('23333333',3,'2006','s');
insert into inscriptos values ('24444444',3,'2006','n');
6- Inscriba a un mismo socio en el mismo deporte en distintos años:
insert into inscriptos values ('22222222',3,'2005','s');
insert into inscriptos values ('22222222',3,'2007','n');
7- Inscriba a un mismo socio en distintos deportes el mismo año:
insert into inscriptos values ('24444444',1,'2006','s');
insert into inscriptos values ('24444444',2,'2006','s');
8- Ingrese una inscripción con un código de deporte inexistente y un documento de socio que no
exista en "socios":
insert into inscriptos values ('26666666',0,'2006','s');
9- Muestre el nombre del socio, el nombre del deporte en que se inscribió y el año empleando
diferentes tipos de join (8 filas):
10- Muestre todos los datos de las inscripciones (excepto los códigos) incluyendo aquellas
inscripciones cuyo código de deporte no existe en "deportes" y cuyo documento de socio no se
encuentra en "socios" (10 filas)
11- Muestre todas las inscripciones del socio con documento "22222222" (3 filas)
Ver solución
56 - Otros tipos de combinaciones
Hemos aprendido que existen varios tipos de combinaciones en Oracle:
1) combinaciones internas (inner join o simplemente join),
2) combinaciones externas (left join, right join y full join)
3) combinaciones cruzadas (cross join).
También vimos que es posible emplear varios tipos de combinaciones en una consulta, incluso
puede combinarse una tabla consigo misma.
Existen otros tipos de "join" en Oracle, que veremos rápidamente, ya que se resuelven con los
que vimos anteriormente, básicamente lo que cambia es la sintaxis.
1) combinación natural: realiza un join entre dos tablas cuando los campos por los cuales se
enlazan tienen el mismo nombre. Involucra claves primarias y foráneas.
Sintaxis:
select CAMPOS
from TABLA1
natural join TABLA2;
Ejemplo:
select titulo,nombre as editorial
from libros
natural join
editoriales;
En el ejemplo anterior la tabla "libros" combina su campo "codigoeditorial" con el campo
"codigoeditorial" de "editoriales". La cláusula "on" no aparece, este "join" no necesita condición
de enlace porque Oracle busca los campos con nombres iguales de ambas tablas (ambas tablas
deben tener un único campo con idéntico nombre, si tiene más de un campo con igual nombre,
Oracle no podrá realizar el enlace y mostrará un mensaje de error).
2) combinación empleando la cláusula "using": permite especificar el campo (o los campos) por
el cual se enlazarán las tablas; los campos de ambas tablas DEBEN tener el mismo nombre y ser
de tipos compatibles.
Sintaxis:
select CAMPOS
from TABLA1
join TABLA2
using (CAMPOenCOMUN);
Ejemplo:
select titulo,nombre as editorial
from libros
join editoriales
using (codigoeditorial);
En el ejemplo anterior la tabla "libros" combina su campo "codigoeditorial" con el campo
"codigoeditorial" de "editoriales". La cláusula "on" no aparece, es reemplazada por "using"
seguido del nombre del campo en común por el cual se enlazan.
3) combinación izquierda empleando "join" y el operador o modificador "(+)": Podemos obtener
el mismo resultado que un "left join" empleando "join" y el modificador "(+)", con lo cual se
indica que se consideran los registros con valor nulo. La sintaxis es la siguiente:
select CAMPOS
from TABLA1
join TABLA2
on CAMPOTABLA1=CAMPOTABLA2(+);
Es decir, se coloca el modificador "(+)" luego del campo de la tabla de la derecha para indicar
que se incluyan los que tienen valor nulo.
Las siguientes consultas retornan el mismo resultado. Una de ellas emplea "left join" y la otra un
"join" con el modificador "(+)":
select titulo,nombre as editorial
from libros l
left join editoriales l
on [Link] = [Link];
select titulo,nombre as editorial
from libros l
join editoriales e
on [Link] = [Link](+);
Ambas mostrarán el título y nombre de la editorial; los libros cuyo código de editorial no esté
presente en "editoriales" aparecerán con el valor "null" en la columna "editorial".
4) combinación derecha empleando "join" y el modificador "(+)": de modo similar al anterior,
podemos obtener el mismo resultado que un "right join" empleando "join" y el modificador
"(+)", con lo cual se indica que se consideren los registros con valor nulo. La sintaxis es la
siguiente:
select CAMPOS
from TABLA1
join TABLA2
on CAMPOTABLA1(+)=CAMPOTABLA2;
Entonces, se coloca el modificador "(+)" luego del campo de la tabla de la izquierda para indicar
que se incluyan los que tienen valor nulo.
Las siguientes consultas retornan el mismo resultado. Una de ellas emplea "right join"· y la otra
un "join" con el modificador "(+)":
select titulo,nombre as editorial
from editoriales e
right join libros l
on [Link] = [Link];
select titulo,nombre as editorial
from editoriales e
join libros l
on [Link](+) = [Link];
Ambas mostrarán el título y nombre de la editorial; las editoriales que no encuentran
coincidencia en "libros", aparecen con el valor "null" en la columna "titulo".
Si la condición de combinación es compuesta (más de un campo), DEBE colocarse el
modificador "(+)" en todos los campos que forman parte del enlace.
No se puede colocar el modificador en campos de distintas tablas. La siguiente combinación
producirá un mensaje de error:
select titulo,nombre as editorial
from libros l
join editoriales e
on [Link](+)= [Link](+);
56 - Otros tipos de combinaciones
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias" y créelas:
drop table clientes;
drop table provincias;
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(2)
);
create table provincias(
codigoprovincia number(2),
nombre varchar2(20)
);
2- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Corrientes');
insert into provincias values(null,'Salta');
insert into clientes values (100,'Lopez Marcos','Colon 111','Córdoba',1);
insert into clientes values (101,'Perez Ana','San Martin 222','Cruz del
Eje',1);
insert into clientes values (102,'Garcia Juan','Rivadavia 333','Villa
Maria',1);
insert into clientes values (103,'Perez Luis','Sarmiento 444','Rosario',2);
insert into clientes values (104,'Gomez Ines','San Martin 666','Santa Fe',2);
insert into clientes values (105,'Torres Fabiola','Alem 777','La Plata',4);
insert into clientes values (106,'Garcia Luis','Sucre 475','Santa
Rosa',null);
3- Muestre todos los datos de los clientes, incluido el nombre de la provincia empleando un "left
join" (7 filas)
4- Obtenga la misma salida que la consulta anterior pero empleando un "join" con el modificador
(+)
Note que en los puntos 3 y 4, los registros "Garcia Luis" y "Torres Fabiola" aparecen aunque no
encuentran coincidencia en "provincias", mostrando "null" en la columna "provincia".
5- Muestre todos los datos de los clientes, incluido el nombre de la provincia empleando un
"right join" para que las provincias de las cuales no hay clientes también aparezcan en la consulta
(7 filas)
6- Obtenga la misma salida que la consulta anterior pero empleando un "join" con el modificador
(+)
Note que en los puntos 5 y 6, las provincias "Salta" y "Corrientes" aparecen aunque no
encuentran coincidencia en "clientes", mostrando "null" en todos los campos de tal tabla.
7- Intente colocar en una consulta "join", el modificador "(+)" en ambos campos del enlace
(mensaje de error)
8- Intente realizar un natural join entre ambas tablas mostrando el nombre del cliente, la ciudad y
nombre de la provincia (las tablas tienen 2 campos con igual nombre "codigoprovincia" y
"nombre"; mensaje de error)
9- Realice una combinación entre ambas tablas empleando la cláusula "using" (5 filas)
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes. Almacena la información en una tabla llamada
"inscriptos" que incluye el documento, el nombre, el deporte y si la matricula esta paga o no y
una tabla llamada "inasistencias" que incluye el documento, el deporte y la fecha de la
inasistencia.
1- Elimine las tablas y créelas:
drop table inscriptos;
drop table inasistencias;
create table inscriptos(
nombre varchar2(30),
documento char(8),
deporte varchar2(15),
matricula char(1), --'s'=paga; 'n'=impaga
primary key(documento,deporte)
);
create table inasistencias(
documento char(8),
deporte varchar2(15),
fecha date
);
2- Ingrese algunos registros para ambas tablas:
insert into inscriptos values('Juan Perez','22222222','tenis','s');
insert into inscriptos values('Maria Lopez','23333333','tenis','s');
insert into inscriptos values('Agustin Juarez','24444444','tenis','n');
insert into inscriptos values('Marta Garcia','25555555','natacion','s');
insert into inscriptos values('Juan Perez','22222222','natacion','s');
insert into inscriptos values('Maria Lopez','23333333','natacion','n');
insert into inasistencias values('22222222','tenis','01/12/2006');
insert into inasistencias values('22222222','tenis','08/12/2006');
insert into inasistencias values('23333333','tenis','01/12/2006');
insert into inasistencias values('24444444','tenis','08/12/2006');
insert into inasistencias values('22222222','natacion','02/12/2006');
insert into inasistencias values('23333333','natacion','02/12/2006');
3- Muestre toda la información de "inscriptos", realizando una combinación con "inasistencias".
Realice un "left join" para incluir todos los "inscriptos" aunque no se encuentren en
"inasistencias" (7 filas)
Note que la condición es compuesta porque para identificar los registros necesitamos ambos
campos. Note que la persona con documento '25555555' aparece en la consulta aún cuando no
está presente en "inasistencias".
4- Obtenga el mismo resultado anterior empleando un "join" y el modificador "(+)" (7 filas)
Note que se coloca el modificador en ambos campos. Si se omite en alguno de ellos, el resultado
será diferente (6 filas)
5- Intente realizar un natural join entre ambas tablas mostrando el nombre del inscripto, el
deporte y la fecha de inasistencia (mensaje de error porque hay 2 campos con igual nombre)
6- Realice una combinación entre ambas tablas mostrando toda la información y empleando la
cláusula "using" (6 filas)
Ver solución
57 - Clave foránea
Un campo que no es clave primaria en una tabla y sirve para enlazar sus valores con otra tabla en
la cual es clave primaria se denomina clave foránea, externa o ajena.
En el ejemplo de la librería en que utilizamos las tablas "libros" y "editoriales" con estos campos:
libros: codigo (clave primaria), titulo, autor, codigoeditorial, precio y
editoriales: codigo (clave primaria), nombre.
el campo "codigoeditorial" de "libros" es una clave foránea, se emplea para enlazar la tabla
"libros" con "editoriales" y es clave primaria en "editoriales" con el nombre "codigo".
Las claves foráneas y las claves primarias deben ser del mismo tipo para poder enlazarse. Si
modificamos una, debemos modificar la otra para que los valores se correspondan.
Cuando alteramos una tabla, debemos tener cuidado con las claves foráneas. Si modificamos el
tipo, longitud o atributos de una clave foránea, ésta puede quedar inhabilitada para hacer los
enlaces.
Entonces, una clave foránea es un campo (o varios) empleados para enlazar datos de 2 tablas,
para establecer un "join" con otra tabla en la cual es clave primaria.
58 - Restricciones (foreign key)
Hemos visto que una de las alternativas que Oracle ofrece para asegurar la integridad de datos es
el uso de restricciones (constraints). Aprendimos que las restricciones se establecen en tablas y
campos asegurando que los datos sean válidos y que las relaciones entre las tablas se mantengan.
Vimos tres tipos de restricciones:
primary key, unique y check. Ahora veremos "foreign key".
Con la restricción "foreign key" se define un campo (o varios) cuyos valores coinciden con la
clave primaria de la misma tabla o de otra, es decir, se define una referencia a un campo con una
restricción "primary key" o "unique" de la misma tabla o de otra.
La integridad referencial asegura que se mantengan las referencias entre las claves primarias y
las externas. Por ejemplo, controla que si se agrega un código de editorial en la tabla "libros", tal
código exista en la tabla "editoriales".
También controla que no pueda eliminarse un registro de una tabla ni modificar la clave primaria
si una clave externa hace referencia al registro. Por ejemplo, que no se pueda eliminar o
modificar un código de "editoriales" si existen libros con dicho código.
La siguiente es la sintaxis parcial general para agregar una restricción "foreign key":
alter table NOMBRETABLA1
add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA);
Analicémosla:
- NOMBRETABLA1 referencia el nombre de la tabla a la cual le aplicamos la restricción,
- NOMBRERESTRICCION es el nombre que le damos a la misma,
- luego de "foreign key", entre paréntesis se coloca el campo de la tabla a la que le aplicamos la
restricción que será establecida como clave foránea,
- luego de "references" indicamos el nombre de la tabla referenciada y el campo que es clave
primaria en la misma, a la cual hace referencia la clave foránea. El campo de la tabla
referenciada debe tener definida una restricción "primary key" o "unique"; si no la tiene, aparece
un mensaje de error.
Para agregar una restricción "foreign key" al campo "codigoeditorial" de "libros", tipeamos:
alter table libros
add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo);
En el ejemplo implementamos una restricción "foreign key" para asegurarnos que el código de la
editorial de la de la tabla "libros" ("codigoeditorial") esté asociada con un código válido en la
tabla "editoriales" ("codigo").
Cuando agregamos cualquier restricción a una tabla que contiene información, Oracle controla
los datos existentes para confirmar que cumplen con la restricción, si no los cumple, la
restricción no se aplica y aparece un mensaje de error. Por ejemplo, si intentamos agregar una
restricción "foreign key" a la tabla "libros" y existe un libro con un valor de código para editorial
que no existe en la tabla "editoriales", la restricción no se agrega.
Actúa en inserciones. Si intentamos ingresar un registro (un libro) con un valor de clave foránea
(codigoeditorial) que no existe en la tabla referenciada (editoriales), Oracle muestra un mensaje
de error. Si al ingresar un registro (un libro), no colocamos el valor para el campo clave foránea
(codigoeditorial), almacenará "null", porque esta restricción permite valores nulos (a menos que
se haya especificado lo contrario al definir el campo).
Actúa en eliminaciones y actualizaciones. Si intentamos eliminar un registro o modificar un
valor de clave primaria de una tabla si una clave foránea hace referencia a dicho registro, Oracle
no lo permite (excepto si se permite la acción en cascada, tema que veremos posteriormente). Por
ejemplo, si intentamos eliminar una editorial a la que se hace referencia en "libros", aparece un
mensaje de error.
Esta restricción (a diferencia de "primary key" y "unique") no crea índice automáticamente.
La cantidad y tipo de datos de los campos especificados luego de "foreign key" DEBEN
coincidir con la cantidad y tipo de datos de los campos de la cláusula "references".
Esta restricción se puede definir dentro de la misma tabla (lo veremos más adelante) o entre
distintas tablas.
Una tabla puede tener varias restricciones "foreign key".
No se puede eliminar una tabla referenciada en una restricción "foreign key", aparece un mensaje
de error.
Una restriccion "foreign key" no puede modificarse, debe eliminarse (con "alter table" y "drop
constraint") y volverse a crear.
Las restricciones "foreign key" se eliminan automáticamente al eliminar la tabla en la que fueron
definidas.
Para ver información acerca de esta restricción podemos consultar los diccionarios
"user_constraints" y "user_cons_columns".
58 - Restricciones (foreign key)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias" y créelas:
drop table clientes;
drop table provincias;
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(2)
);
create table provincias(
codigo number(2),
nombre varchar2(20)
);
En este ejemplo, el campo "codigoprovincia" de "clientes" es una clave foránea, se emplea para
enlazar la tabla "clientes" con "provincias".
2- Intente agregar una restricción "foreign key" a la tabla "clientes" que haga referencia al campo
"codigo" de "provincias"
No se puede porque "provincias" no tiene restricción "primary key" ni "unique".
3- Establezca una restricción "unique" al campo "codigo" de "provincias"
4- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');
insert into clientes values(100,'Perez Juan','San Martin 123','Carlos
Paz',1);
insert into clientes values(101,'Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values(102,'Acosta Ana','Avellaneda 333','Posadas',3);
insert into clientes values(103,'Luisa Lopez','Juarez 555','La Plata',6);
5- Intente agregar la restricción "foreign key" del punto 2 a la tabla "clientes"
No se puede porque hay un registro en "clientes" cuyo valor de "codigoprovincia" no existe en
"provincias".
6- Elimine el registro de "clientes" que no cumple con la restricción y establezca la restricción
nuevamente.
7- Intente agregar un cliente con un código de provincia inexistente en "provincias"
8- Intente eliminar el registro con código 3, de "provincias".
No se puede porque hay registros en "clientes" al cual hace referencia.
9- Elimine el registro con código "4" de "provincias"
Se permite porque en "clientes" ningún registro hace referencia a él.
10- Intente modificar el registro con código 1, de "provincias"
No se puede porque hay registros en "clientes" al cual hace referencia.
11- Vea las restricciones de "clientes" consultando "user_constraints"
12- Vea las restricciones de "provincias"
13- Intente eliminar la tabla "provincias" (mensaje de error)
14- Elimine la restricción "foreign key" de "clientes" y luego elimine la tabla "provincias"
Ver solución
59 - Restricciones foreign key en la misma
tabla
La restricción "foreign key", que define una referencia a un campo con una restricción "primary
key" o "unique" se puede definir entre distintas tablas (como hemos aprendido) o dentro de la
misma tabla.
Veamos un ejemplo en el cual definimos esta restricción dentro de la misma tabla.
Una mutual almacena los datos de sus afiliados en una tabla llamada "afiliados". Algunos
afiliados inscriben a sus familiares. La tabla contiene un campo que hace referencia al afiliado
que lo incorporó a la mutual, del cual dependen.
La estructura de la tabla es la siguiente:
create table afiliados(
numero number(5),
documento char(8) not null,
nombre varchar2(30),
afiliadotitular number(5),
primary key (documento),
unique (numero)
);
En caso que un afiliado no haya sido incorporado a la mutual por otro afiliado, el campo
"afiliadotitular" almacenará "null".
Establecemos una restricción "foreign key" para asegurarnos que el número de afiliado que se
ingrese en el campo "afiliadotitular" exista en la tabla "afiliados":
alter table afiliados
add constraint FK_afiliados_afiliadotitular
foreign key (afiliadotitular)
references afiliados (numero);
La sintaxis es la misma, excepto que la tabla se autoreferencia.
Luego de aplicar esta restricción, cada vez que se ingrese un valor en el campo "afiliadotitular",
Oracle controlará que dicho número exista en la tabla, si no existe, mostrará un mensaje de error.
Si intentamos eliminar un afiliado que es titular de otros afiliados, no se podrá hacer, a menos
que se haya especificado la acción en cascada (próximo tema).
Si intentamos modificar un afiliado que es titular de otros afiliados, no se podrá hacer, a menos
que se haya especificado la acción en cascada para actualizaciones (próximo tema).
59 - Restricciones foreign key en la misma
tabla
Primer problema:
Una empresa registra los datos de sus clientes en una tabla llamada "clientes". Dicha tabla
contiene un campo que hace referencia al cliente que lo recomendó denominado
"referenciadopor". Si un cliente no ha sido referenciado por ningún otro cliente, tal campo
almacena "null".
1- Elimine la tabla y créela:
drop table clientes;
create table clientes(
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
referenciadopor number(5),
primary key(codigo)
);
2- Ingresamos algunos registros:
insert into clientes values (50,'Juan Perez','Sucre 123','Cordoba',null);
insert into clientes values(90,'Marta Juarez','Colon 345','Carlos Paz',null);
insert into clientes values(110,'Fabian Torres','San Martin
987','Cordoba',50);
insert into clientes values(125,'Susana Garcia','Colon 122','Carlos Paz',90);
insert into clientes values(140,'Ana Herrero','Colon 890','Carlos Paz',9);
3- Intente agregar una restricción "foreign key" para evitar que en el campo "referenciadopor" se
ingrese un valor de código de cliente que no exista.
No se permite porque existe un registro que no cumple con la restricción que se intenta
establecer.
4- Cambie el valor inválido de "referenciadopor" del registro que viola la restricción por uno
válido:
update clientes set referenciadopor=90 where referenciadopor=9;
5- Agregue la restricción "foreign key" que intentó agregar en el punto 3
6- Vea la información referente a las restricciones de la tabla "clientes"
La tabla tiene 2 restricciones.
7- Intente agregar un registro que infrinja la restricción.
8- Intente modificar el código de un cliente que está referenciado en "referenciadopor"
9- Intente eliminar un cliente que sea referenciado por otro en "referenciadopor"
10- Cambie el valor de código de un cliente que no referenció a nadie.
11- Elimine un cliente que no haya referenciado a otros.
Ver solución
60 - Restricciones foreign key (eliminación)
Podemos eliminar una restricción "foreign key" con "alter table". La sintaxis básica es la misma
que para cualquier otra restricción:
alter table TABLA
drop constraint NOMBRERESTRICCION;
Eliminamos la restricción "foreign key" de "libros":
alter table libros
drop constraint FK_libros_codigoeditorial;
No se puede eliminar una tabla si una restricción "foreign key" hace referencia a ella.
Cuando eliminamos una tabla que tiene una restricción "foreign key", la restricción también se
elimina.
61 - Restricciones foreign key deshabilitar y
validar
Aprendimos (cuando vimos los otros tipos de restricciones) que si agregamos una restricción a
una tabla que contiene datos, Oracle los controla para asegurarse que cumplen con la restricción
y que es posible deshabilitar esta comprobación. Lo hacemos incluyendo la opción "novalidate"
en la instrucción "alter table"; en tal caso, La restricción no se aplica en los datos existentes, pero
si intentamos ingresar un nuevo valor que no cumpla la restricción (o actualizarlo), Oracle no lo
permite.
En el siguiente ejemplo agregamos una restricción "foreign key" sobre el campo
"codigoeditorial" de "libros" especificando que no valide los datos existentes:
alter table libros
add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales novalidate;
La restricción no se aplica en los datos existentes, pero si intentamos ingresar un nuevo registro
en "libros" cuyo código de editorial no exista en "editoriales", Oracle no lo permitirá.
Para saber si una restricción está validada o no, podemos consultar el catálogo "user_constraints"
y fijarnos lo que informa la columna "validated".
También aprendimos que podemos deshabilitar las restricciones para agregar o actualizar datos
sin comprobarla. Para evitar la comprobación de datos en inserciones y actualizaciones
agregamos "disable" en la instrucción "alter table".
En el ejemplo siguiente deshabilitamos la restricción "FK_libros_codigoeditorial" para poder
ingresar un valor que infrija la restricción:
alter table libros
disable validate
constraint FK_libros_codigoeditorial;
Para habilitar una restricción "foreign key" deshabilitada se ejecuta la misma instrucción pero
con la cláusula "enable".
Por defecto (si no se especifica) las opciones son "validate" (es decir, controla los datos
existentes) y "enable" (controla futuros ingresos y actualizaciones).
Para saber si una restricción está habilitada o no, podemos consultar el catálogo
"user_constraints" y fijarnos lo que informa la columna "status".
Podemos habilitar una restricción "foreign key" con "enable" y "novalidate", en tal caso Oracle
habilita la restricción para futuros ingresos y actualizaciones y NO valida los datos existentes.
Entonces, "enable" o "disable" activa o desactiva la restricción para los nuevos datos ("enable" es
la opción predeterminada si no se especifica); "validate" o "novalidate" es la opción para validar
la restricción en los datos existentes ("validate" es la predeterminada si se omite).
La sintaxis básica al agregar la restriccción "foreign key" es la siguiente:
alter table NOMBRETABLA1
add constraint NOMBRECONSTRAINT
foreign key (CAMPOCLAVEFORANEA)
references NOMBRETABLA2 (CAMPOCLAVEPRIMARIA)
ESTADO VALIDACION;
La sintaxis para modificar una restricción es:
alter table NOMBRETABLA
ESTADO VALIDACION
constraint NOMBRERESTRICCION;
61 - Restricciones foreign key deshabilitar y
validar
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias":
drop table clientes;
drop table provincias;
2- Créelas con las siguientes estructuras:
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(2),
primary key(codigo)
);
create table provincias(
codigo number(2),
nombre varchar2(20),
primary key (codigo)
);
3- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');
insert into clientes values(100,'Perez Juan','San Martin 123','Carlos
Paz',1);
insert into clientes values(101,'Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values(102,'Garcia Juan','Sucre 345','Cordoba',1);
insert into clientes values(103,'Lopez Susana','Caseros 998','Posadas',3);
insert into clientes values(104,'Marcelo Moreno','Peru 876','Viedma',4);
insert into clientes values(105,'Lopez Sergio','Avellaneda 333','La
Plata',5);
4- Intente agregar una restricción "foreign key" para que los códigos de provincia de "clientes"
existan en "provincias" sin especificar la opción de comprobación de datos
No se puede porque al no especificar opción para la comprobación de datos, por defecto es
"validate" y hay un registro que no cumple con la restricción.
5- Agregue la restricción anterior pero deshabilitando la comprobación de datos existentes
6- Vea las restricciones de "clientes"
7- Deshabilite la restricción "foreign key" de "clientes"
8- Vea las restricciones de "clientes"
9- Agregue un registro que no cumpla la restricción "foreign key"
Se permite porque la restricción está deshabilitada.
10- Modifique el código de provincia del cliente código 104 por 9
Oracle lo permite porque la restricción está deshabilitada.
11-Habilite la restricción "foreign key"
12- Intente modificar un código de provincia existente por uno inexistente.
13- Intente alterar la restricción "foreign key" para que valide los datos existentes
14- Elimine los registros que no cumplen la restricción y modifique la restricción a "enable" y
"validate"
15- Obtenga información sobre la restricción "foreign key" de "clientes"
Ver solución
62 - Restricciones foreign key (acciones)
Continuamos con la restricción "foreign key". Si intentamos eliminar un registro de la tabla
referenciada por una restricción "foreign key" cuyo valor de clave primaria existe referenciada en
la tabla que tiene dicha restricción, la acción no se ejecuta y aparece un mensaje de error. Esto
sucede porque, por defecto, para eliminaciones, la opción de la restricción "foreign key" es "no
action".
La restricción "foreign key" tiene la cláusula "on delete", que son opcionales. Esta cláusula
especifica cómo debe actuar Oracle frente a eliminaciones en las tablas referenciadas en la
restricción.
Las opciones para estas cláusulas son las siguientes:
- "set null": indica que si eliminamos un registro de la tabla referenciada (TABLA2) cuyo valor
existe en la tabla principal (TABLA1), dicho registro se elimine y los valores coincidentes en la
tabla principal se seteen a "null".
- "cascade": indica que si eliminamos un registro de la tabla referenciada en una "foreign key"
(TABLA2), los registros coincidentes en la tabla principal (TABLA1), también se eliminen; es
decir, si eliminamos un registro al cual una clave foránea referencia, dicha eliminación se
extiende a la otra tabla (integridad referencial en cascada).
- "no action": es la predeterminada; indica que si se intenta eliminar un registro de la tabla
referenciada por una "foreign key", Oracle no lo permita y muestre un mensaje de error. Se
establece omitiendo la cláusula "on delete" al establecer la restricción.
La sintaxis completa paar agregar esta restricción a una tabla es la siguiente:
alter table TABLA1
add constraint NOMBRERESTRICCION
foreign key (CAMPOCLAVEFORANEA)
references TABLA2(CAMPOCLAVEPRIMARIA)
on delete OPCION;
Veamos un ejemplo. Definimos una restricción "foreign key" a la tabla "libros" estableciendo el
campo "codigoeditorial" como clave foránea que referencia al campo "codigo" de la tabla
"editoriales". La tabla "editoriales" tiene como clave primaria el campo "codigo". Especificamos
la acción en cascada para las eliminaciones:
alter table libros
add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo)
on delete cascade;
Si luego de establecer la restricción anterior, eliminamos una editorial de "editoriales" cuyo valor
de código está presente en "libros", se elimina dicha editorial y todos los libros de tal editorial.
Si consultamos "user_constraints", en la columna "delete_rule" mostrará "cascade".
Para definir una restricción "foreign key" sobre la tabla "libros" estableciendo el campo
"codigoeditorial" como clave foránea que referencia al campo "codigo" de la tabla "editoriales"
especificando la acción de seteo a "null" tipeamos:
alter table libros
add constraint FK_libros_codigoeditorial
foreign key (codigoeditorial)
references editoriales(codigo)
on delete set null;
Si luego de establecer la restricción anterior, eliminamos una editorial de "editoriales" cuyo valor
de código está presente en "libros", se elimina dicha editorial y todos los valores de libros que
coinciden con tal editorial se setean a null. Si consultamos "user_constraints", en la columna
"delete_rule" mostrará "set null".
Sintetizando, si al agregar una restricción "foreign key":
- no se especifica acción para eliminaciones, y se intenta eliminar un registro de la tabla
referenciada en la "foreign key" (editoriales) cuyo valor de clave primaria (codigo) existe en la
tabla principal (libros), la acción no se realiza.
- se especifica "cascade" para eliminaciones ("on delete cascade") y elimina un registro de la
tabla referenciada (editoriales) cuyo valor de clave primaria (codigo) existe en la tabla
principal(libros), la eliminación de la tabla referenciada (editoriales) se realiza y se eliminan de
la tabla principal (libros) todos los registros cuyo valor coincide con el registro eliminado de la
tabla referenciada (editoriales).
- se especifica acción para eliminaciones ("on delete set null") y se elimina un registro de la tabla
referenciada en la "foreign key" (editoriales) cuyo valor de clave primaria (codigo) existe en la
tabla principal (libros), la acción se realiza y se setean a "null" todos los valores coincidentes en
la tabla principal (libros).
La restricción "foreign key" NO tiene una cláusula para especificar acciones para
actualizaciones.
Si intentamos actualizar un registro de la tabla referenciada por una restricción "foreign key"
cuyo valor de clave primaria existe referenciada en la tabla que tiene dicha restricción, la acción
no se ejecuta y aparece un mensaje de error. Esto sucede porque, por defecto (y como única
opción), para actualizaciones existe "no action".
62 - Restricciones foreign key (acciones)
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "provincias" donde registra los nombres de las provincias.
1- Elimine las tablas "clientes" y "provincias":
drop table clientes;
drop table provincias;
2- Créelas con las siguientes estructuras:
create table clientes (
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
ciudad varchar2(20),
codigoprovincia number(2),
primary key(codigo)
);
create table provincias(
codigo number(2),
nombre varchar2(20),
primary key (codigo)
);
3- Ingrese algunos registros para ambas tablas:
insert into provincias values(1,'Cordoba');
insert into provincias values(2,'Santa Fe');
insert into provincias values(3,'Misiones');
insert into provincias values(4,'Rio Negro');
insert into clientes values(100,'Perez Juan','San Martin 123','Carlos
Paz',1);
insert into clientes values(101,'Moreno Marcos','Colon 234','Rosario',2);
insert into clientes values(102,'Acosta Ana','Avellaneda 333','Posadas',3);
4- Establezca una restricción "foreign key" especificando la acción "set null" para eliminaciones.
5- Elimine el registro con código 3, de "provincias" y consulte "clientes" para ver qué cambios
ha realizado Oracle en los registros coincidentes
Todos los registros con "codigoprovincia" 3 han sido seteados a null.
6- Consulte el diccionario "user_constraints" para ver qué acción se ha establecido para las
eliminaciones
7- Intente modificar el registro con código 2, de "provincias"
8- Elimine la restricción "foreign key" establecida sobre "clientes"
9- Establezca una restricción "foreign key" sobre "codigoprovincia" de "clientes" especificando
la acción "cascade" para eliminaciones
10- Consulte el diccionario "user_constraints" para ver qué acción se ha establecido para las
eliminaciones sobre las restricciones "foreign key" de la tabla "clientes"
11- Elimine el registro con código 2, de "provincias"
12- Verifique que el cambio se realizó en cascada, es decir, que se eliminó en la tabla
"provincias" y todos los clientes de la provincia eliminada
13- Elimine la restricción "foreign key"
14- Establezca una restricción "foreign key" sin especificar acción para eliminaciones
15- Intente eliminar un registro de la tabla "provincias" cuyo código exista en "clientes"
16- Consulte el diccionario "user_constraints" para ver qué acción se ha establecido para las
eliminaciones sobre la restricción "FK_CLIENTES_CODIGOPROVINCIA"
17- Intente elimimar la tabla "provincias"
18- Elimine la restricción "foreign key"
19- Elimine la tabla "provincias"
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes. En una tabla llamada "deportes" guarda la información
de los distintos deportes que se enseñan; en una tabla "socios", los datos de los socios y en una
tabla "inscripciones" almacena la información necesaria para las inscripciones de los distintos
socios a los distintos deportes.
1- Elimine las tablas:
drop table inscripciones;
drop table deportes;
drop table socios;
2- Cree las tablas:
create table deportes(
codigo number(2),
nombre varchar2(20),
primary key(codigo)
);
create table socios(
documento char(8),
nombre varchar2(30),
primary key(documento)
);
create table inscripciones(
documento char(8),
codigodeporte number(2),
matricula char(1),-- 's' si está paga, 'n' si no está paga
primary key(documento,codigodeporte)
);
3- Establezca una restricción "foreign key" para "inscripciones" que haga referencia al campo
"codigo" de "deportes" indicando la acción "cascade" para eliminaciones
4- Establezca una restricción "foreign key" para "inscripciones" que haga referencia al campo
"documento" de "socios" que permita la eliminación "set null" (Recuerde que se pueden
establecer varias restricciones "foreign key" sobre una misma tabla)
5- Ingrese algunos registros en las tablas:
insert into deportes values(1,'basquet');
insert into deportes values(2,'futbol');
insert into deportes values(3,'natacion');
insert into deportes values(4,'tenis');
insert into socios values('30000111','Juan Lopez');
insert into socios values('31111222','Ana Garcia');
insert into socios values('32222333','Mario Molina');
insert into socios values('33333444','Julieta Herrero');
insert into inscripciones values ('30000111',1,'s');
insert into inscripciones values ('30000111',2,'s');
insert into inscripciones values ('31111222',1,'s');
insert into inscripciones values ('32222333',3,'n');
6- Intente ingresar una inscripción con un código de deporte inexistente:
Mensaje de error.
7- Intente ingresar una inscripción con un documento inexistente en "socios"
8- Elimine un registro de "deportes" que no tenga inscriptos.
Se elimina porque no hay inscriptos en dicho deporte.
9- Consulte "inscripciones", "deportes" y "socios" (realizando un join)
10-Elimine un deporte para los cuales haya inscriptos
Se elimina el deporte "natacion" de "deportes" y de "inscripciones", todos los registros con el
valor correspondiente a "natacion" en "codigodeporte".
11- Verifique que se han eliminado los registros de "inscripciones" cuyo código de deporte
correspondía a "natacion"
12- Intente eliminar el socio que esté inscripto en algún deporte.
Mensaje de error, porque la restricción "FK_inscripciones_documento" fue especificada "set
null", pero el campo clave foránea "documento" en "inscripciones" no admite valores nulos
(forma parte de la clave primaria).
13- Elimine la restricción "FK_inscripciones_documento" y créela nuevamente especificando la
acción "cascade" para borrado
14- Elimine un socio que esté inscripto en algún deporte
15- Verifique que el socio fue eliminado de "socios" y de "inscripciones"
16- Consulte el diccionario "user_constraints" especificando las tres tablas y analice la
información
Nos retorna la siguiente información:
TABLE_NAME CONSTRAINT_NAME CONSTRAINT_TYPE
DELETE_RULE
------------------------------------------------------------------------------
------
DEPORTES SYS_C004914 P
INSCRIPCIONES SYS_C004916 P
INSCRIPCIONES FK_INSCRIPCIONES_CODIGODEPORTE R
CASCADE
INSCRIPCIONES FK_INSCRIPCIONES_DOCUMENTO R
CASCADE
SOCIOS SYS_C004915 P
17- Intente eliminar la tabla "deportes"
16- Elimine la restricción "foreign key" establecida sobre el campo "codigodeporte" de
"inscripciones" y luego la tabla "deportes"
Ver solución
63 - Información de user_constraints
El diccionario "user_constraints" devuelve mucha información referente a las restricciones, las
que estudiamos son las siguientes columnas:
- owner: propietario de la restricción;
- constraint_name: nombre de la restricción;
- constraint_type: tipo de restricción. Si es una restricción "primary key" aparece "P", si es de
control, "C", si es única, "U", si es una "foreign key" "R";
- table_name: nombre de la tabla sobre la cual está aplicada la restricción;
- search_condition: solamente es aplicable a restricciones de control; indica la condición de
chequeo a cumplirse.
- delete_rule: solamente aplicable a restricciones "foreign key". Puede contener 3 valores: 1) "set
null": indica que si eliminamos un registro de la tabla referenciada (TABLA2) cuyo valor existe
en la tabla principal (TABLA1), dicho registro se elimina y los valores coincidentes en la tabla
principal se seteen a "null"; 2) "cascade": indica que si eliminamos un registro de la tabla
referenciada en una "foreign key" (TABLA2), los registros coincidentes en la tabla principal
(TABLA1), también se eliminan; 3) "no action": indica que si se intenta eliminar un registro de
la tabla referenciada por una "foreign key", Oracle no lo permite.
- status: indica si está habilitada (enabled) para futuras inserciones y actualizaciones o
deshabilitada (disabled)
- validated: indica si valida los datos existentes en la tabla (validated) o no (no validate).
64 - Restricciones al crear la tabla
Hasta el momento hemos agregado restricciones a tablas existentes con "alter table"; también
pueden establecerse al momento de crear una tabla (en la instrucción "create table").
En el siguiente ejemplo creamos la tabla "libros" con varias restricciones:
create table libros(
codigo number(5),
titulo varchar2(40),
codigoautor number(4),
codigoeditorial number(3),
precio number(5,2) default 0,
constraint PK_libros_codigo
primary key (codigo),
constraint UQ_libros_tituloautor
unique (titulo,codigoautor),
constraint CK_libros_codigoeditorial
check (codigoeditorial is not null),
constraint FK_libros_editorial
foreign key (codigoeditorial)
references editoriales(codigo)
on delete cascade,
constraint FK_libros_autores
foreign key (codigoautor)
references autores(codigo)
on delete set null,
constraint CK_libros_preciononulo
check (precio is not null) disable,
constraint CK_precio_positivo
check (precio>=0)
);
En el ejemplo definimos las siguientes restricciones:
- "primary key" sobre el campo "codigo";
- "unique" para los campos "titulo" y "codigoautor";
- de control sobre "codigoeditorial" que no permite valores nulos;
- "foreign key" para establecer el campo "codigoeditorial" como clave externa que haga
referencia al campo "codigo" de "editoriales y permita eliminaciones en cascada;
- "foreign key" para establecer el campo "codigoautor" como clave externa que haga referencia
al campo "codigo" de "autores" y permita eliminaciones "set null";
- de control sobre "precio" para que no admita valores nulos, deshabilitada;
- "check" para el campo "precio" que no admita valores negativos.
Las restricciones se agregan a la tabla, separadas por comas; colocando "constraint" seguido del
nombre de la restricción, el tipo y los campos (si es una "primary key", "unique" o "foreign key")
o la condición (si es de control); también puede especificarse el estado y la validación de datos
(por defecto es "enable" y "validate"); y en el caso de las "foreign key", la opción para
eliminaciones.
Si definimos una restricción "foreign key" al crear una tabla, la tabla referenciada debe existir y
debe tener definida la clave primaria o única a la cual hace referencia la "foreign key".
64 - Restricciones al crear la tabla
Primer problema:
Un club de barrio tiene en su sistema 4 tablas:
- "socios": en la cual almacena documento, número, nombre y domicilio de cada socio;
- "deportes": que guarda un código, nombre del deporte, día de la semana que se dicta y
documento del profesor instructor;
- "profesores": donde se guarda el documento, nombre y domicilio de los profesores e
- "inscriptos": que almacena el número de socio, el código de deporte y si la matricula está paga
o no.
1- Elimine las tablas:
drop table inscriptos;
drop table socios;
drop table deportes;
drop table profesores;
2- Considere que:
- un socio puede inscribirse en varios deportes, pero no dos veces en el mismo.
- un socio tiene un documento único y un número de socio único.
- un deporte debe tener asignado un profesor que exista en "profesores" o "null" si aún no tiene
un instructor definido.
- el campo "dia" de "deportes" puede ser: lunes, martes, miercoles, jueves, viernes o sabado.
- el campo "dia" de "deportes" por defecto debe almacenar 'sabado'.
- un profesor puede ser instructor de varios deportes o puede no dictar ningún deporte.
- un profesor no puede estar repetido en "profesores".
- un inscripto debe ser socio, un socio puede no estar inscripto en ningún deporte.
- una inscripción debe tener un valor en socio existente en "socios" y un deporte que exista en
"deportes".
- el campo "matricula" de "inscriptos" debe aceptar solamente los caracteres 's' o'n'.
- si se elimina un profesor de "profesores", el "documentoprofesor" coincidente en "deportes"
debe quedar seteado a null.
- no se puede eliminar un deporte de "deportes" si existen inscriptos para tal deporte en
"inscriptos".
- si se elimina un socio de "socios", el registro con "numerosocio" coincidente en "inscriptos"
debe eliminarse.
3- Cree las tablas con las restricciones necesarias:
create table profesores(
documento char(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
constraint PK_profesores_documento
primary key (documento)
);
create table deportes(
codigo number(2),
nombre varchar2(20) not null,
dia varchar2(9) default 'sabado',
documentoprofesor char(8),
constraint CK_deportes_dia_lista
check (dia in ('lunes','martes','miercoles','jueves','viernes','sabado')),
constraint PK_deportes_codigo
primary key (codigo),
constraint FK_deportes_profesor
foreign key (documentoprofesor)
references profesores(documento)
on delete set null
);
create table socios(
numero number(4),
documento char(8),
nombre varchar2(30),
domicilio varchar2(30),
constraint PK_socios_numero
primary key (numero),
constraint UQ_socios_documento
unique (documento)
);
create table inscriptos(
numerosocio number(4),
codigodeporte number(2),
matricula char(1),
constraint PK_inscriptos_numerodeporte
primary key (numerosocio,codigodeporte),
constraint FK_inscriptos_deporte
foreign key (codigodeporte)
references deportes(codigo),
constraint FK_inscriptos_socios
foreign key (numerosocio)
references socios(numero)
on delete cascade,
constraint CK_matricula_valores
check (matricula in ('s','n'))
);
4- Ingrese registros en "profesores":
insert into profesores values('21111111','Andres Acosta','Avellaneda 111');
insert into profesores values('22222222','Betina Bustos','Bulnes 222');
insert into profesores values('23333333','Carlos Caseros','Colon 333');
5- Ingrese registros en "deportes". Ingrese el mismo día para distintos deportes, un deporte sin
día confirmado, un deporte sin profesor definido:
insert into deportes values(1,'basquet','lunes',null);
insert into deportes values(2,'futbol','lunes','23333333');
insert into deportes values(3,'natacion',null,'22222222');
insert into deportes values(4,'padle',default,'23333333');
insert into deportes values(5,'tenis','jueves',null);
6- Ingrese registros en "socios":
insert into socios values(100,'30111111','Martina Moreno','America 111');
insert into socios values(200,'30222222','Natalia Norte','Bolivia 222');
insert into socios values(300,'30333333','Oscar Oviedo','Caseros 333');
insert into socios values(400,'30444444','Pedro Perez','Dinamarca 444');
7- Ingrese registros en "inscriptos". Inscriba a un socio en distintos deportes, inscriba varios
socios en el mismo deporte.
insert into inscriptos values(100,3,'s');
insert into inscriptos values(100,5,'s');
insert into inscriptos values(200,1,'s');
insert into inscriptos values(400,1,'n');
insert into inscriptos values(400,4,'s');
8- Realice un "join" (del tipo que sea necesario) para mostrar todos los datos del socio junto con
el nombre de los deportes en los cuales está inscripto, el día que tiene que asistir y el nombre del
profesor que lo instruirá (5 registros)
9- Realice la misma consulta anterior pero incluya los socios que no están inscriptos en ningún
deporte (6 registros)
10- Muestre todos los datos de los profesores, incluido el deporte que dicta y el día, incluyendo
los profesores que no tienen asignado ningún deporte, ordenados por documento (4 registros)
11- Muestre todos los deportes y la cantidad de inscriptos en cada uno de ellos, incluyendo
aquellos deportes para los cuales no hay inscriptos, ordenados por nombre de deporte (5
registros)
12- Muestre las restricciones de "socios"
13- Muestre las restricciones de "deportes"
14- Obtenga información sobre la restricción "foreign key" de "deportes"
15- Muestre las restricciones de "profesores"
16- Muestre las restricciones de "inscriptos"
17- Consulte "user_cons_columns" y analice la información retornada sobre las restricciones de
"inscriptos"
18- Elimine un profesor al cual haga referencia algún registro de "deportes"
19- Vea qué sucedió con los registros de "deportes" cuyo "documentoprofesor" existía en
"profesores"
Fue seteado a null porque la restricción "foreign key" sobre "documentoprofesor" de "deportes"
fue definida "on delete set null".
20- Elimine un socio que esté inscripto
21- Vea qué sucedió con los registros de "inscriptos" cuyo "numerosocio" existía en "socios"
Fue eliminado porque la restricción "foreign key" sobre "numerosocio" de "inscriptos" fue
definida "on delete cascade".
22- Intente eliminar un deporte para el cual haya inscriptos
Mensaje de error porque la restricción "foreign key sobre "codigodeporte" de "inscriptos" fue
establecida "no action".
23- Intente eliminar la tabla "socios"
No puede eliminarse, mensaje de error, una "foreign key" sobre "inscriptos" hace referencia a
esta tabla.
24- Elimine la tabla "inscriptos"
25- Elimine la tabla "socios"
26- Intente eliminar la tabla "profesores"
No puede eliminarse, mensaje de error, una "foreign key" sobre "deportes" hace referencia a esta
tabla.
27- Elimine la tabla "deportes"
28- Elimine la tabla "profesores"
Ver solución
65 - Unión
Las operaciones de conjuntos combinan los resultados de dos o más consultas "select" en un
único resultado.
Se usan cuando los datos que se quieren obtener pertenecen a distintas tablas y no se puede
acceder a ellos con una sola consulta.
Es necesario que las tablas referenciadas tengan tipos de datos similares, la misma cantidad de
campos y el mismo orden de campos en la lista de selección de cada consulta.
Hay tres operadores de conjuntos: union, intersect y minus. Veremos en primer lugar "union".
La sintaxis para unir dos consultas con el operador "union" es la siguiente:
CONSULTA1
union
CONSULTA2;
Recuerde que las consultas DEBEN tener el mismo numero de valores retornados y los valores
deben ser del mismo tipo.
Veamos un ejemplo. Una academia de enseñanza de idiomas da clases de inglés y frances;
almacena los datos de los alumnos que estudian inglés en una tabla llamada "ingles" y los que
están inscriptos en "francés" en una tabla denominada "frances".
La academia necesita el nombre y domicilio de todos los alumnos, de todos los cursos para
enviarles una tarjeta de felicitación para el día del alumno.
Para obtener los datos necesarios de ambas tablas en una sola consulta necesitamos realizar una
unión:
select nombre, domicilio from ingles
union
select nombre, domicilio from frances;
El primer "select" devuelve el nombre y domicilio de todos los alumnos de "ingles"; el segundo,
el nombre y domicilio de todos los alumnos de "frances". Esta sentencia de unión retornará la
combinacion de los resultados de ambas consultas "select", mostrando el nombre y domicilio de
los registros de ambas tablas.
Los encabezados del resultado de una unión son los que se especifican en el primer "select". El
operador de conjunto "union" no retorna duplicados; es decir, si un registro de la primer consulta
es igual a otro registro de la segunda consulta, tal registro aparece una sola vez. Si queremos que
se incluyan TODOS los registros, aún duplicados, debemos emplear "union all":
select nombre,domicilio from ingles
union all
select nombre,domicilio from frances;
En el ejemplo anterior, si un registro de la primer consulta es igual a otro registro de la segunda
consulta, tal registro aparece dos veces; es decir, si un alumno está cursando ambos idiomas,
aparecerá dos veces en el resultado.
"union" puede combinarse con la cláusula "order by".
65 - Unión
Primer problema:
Una clínica almacena los datos de los médicos en una tabla llamada "medicos" y los datos de los
pacientes en otra denominada "pacientes".
1- Eliminamos ambas tablas:
drop table medicos;
drop table pacientes;
2- Creamos las tablas:
create table medicos(
legajo number(3),
documento varchar2(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
especialidad varchar2(30),
primary key(legajo)
);
create table pacientes(
documento varchar2(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
obrasocial varchar2(20),
primary key(documento)
);
3- Ingresamos algunos registros:
insert into medicos values(1,'20111222','Ana Acosta','Avellaneda
111','clinica');
insert into medicos values(2,'21222333','Betina Bustos','Bulnes
222','clinica');
insert into medicos values(3,'22333444','Carlos Caseros','Colon
333','pediatria');
insert into medicos values(4,'23444555','Daniel Duarte','Duarte Quiros
444','oculista');
insert into medicos values(5,'24555666','Estela Esper','Esmeralda
555','alergia');
insert into pacientes values('24555666','Estela Esper','Esmeralda
555','IPAM');
insert into pacientes values('23444555','Daniel Duarte','Duarte Quiros
444','OSDOP');
insert into pacientes values('30111222','Fabiana Fuentes','Famatina
666','PAMI');
insert into pacientes values('31222333','Gaston Gonzalez','Guemes
777','PAMI');
4- La clínica necesita el nombre y domicilio de médicos y pacientes para enviarles una tarjeta de
invitación a la inauguración de un nuevo establecimiento. Emplee el operador "union" para
obtener dicha información de ambas tablas (7 registros)
Note que existen dos médicos que también están presentes en la tabla "pacientes"; tales registros
aparecen una sola vez en el resultado de "union".
5- Realice la misma consulta anterior pero esta vez, incluya los registros duplicados. Emplee
"union all" (9 registros)
6- Realice la misma consulta anterior y esta vez ordene el resultado por nombre (9 registros)
7- Agregue una columna extra a la consulta con el encabezado "condicion" en la que aparezca el
literal "médico" o "paciente" según si la persona es uno u otro (9 registros)
Ver solución
Segundo problema:
Un supermercado almacena en una tabla denominada "proveedores" los datos de las compañías
que le proveen de mercaderías; en una tabla llamada "clientes", los datos de los comercios que le
compran y en otra tabla "empleados" los datos de los empleados.
1- Elimine las tablas:
drop table clientes;
drop table proveedores;
drop table empleados;
2- Cree las tablas:
create table proveedores(
codigo number(3) not null,
nombre varchar2(30),
domicilio varchar2(30),
primary key(codigo)
);
create table clientes(
codigo number(4),
nombre varchar2(30),
domicilio varchar2(30),
primary key(codigo)
);
create table empleados(
documento char(8) not null,
nombre varchar2(20),
apellido varchar2(20),
domicilio varchar2(30),
primary key(documento)
);
3- Ingrese algunos registros:
insert into proveedores values(1,'Golosinas Dulce','Colon 123');
insert into proveedores values(2,'Carnes Unica','Caseros 222');
insert into proveedores values(3,'Lacteos Blanca','San Martin 987');
insert into proveedores values(4,'Luis Luque','San Martin 1234');
insert into clientes values(100,'Supermercado Lopez','Avellaneda 34');
insert into clientes values(101,'Almacen Anita','Colon 987');
insert into clientes values(102,'Juan Garcia','Sucre 345');
insert into clientes values(103,'Luis Luque','San Martin 1234');
insert into empleados values('23333333','Federico','Lopez','Colon 987');
insert into empleados values('28888888','Ana','Marquez','Sucre 333');
insert into empleados values('30111111','Pedro','Perez','Caseros 956');
insert into empleados values('31222333','Juan','Garcia','Sucre 345');
4- El supermercado quiere enviar una tarjeta de salutación a todos los proveedores, clientes y
empleados y necesita el nombre y domicilio de todos ellos. Emplee el operador "union" para
obtener dicha información de las tres tablas. Ordene la información por nombre. La consulta a la
tabla "empleados" debe incluir el nombre y el apellido (10 registros)
5- Realice la misma operación de unión anterior, pero ahora incluya los registros duplicados y
ordénelos por nombre (12 registros)
Note que "Luis Luque" es proveedor y cliente y que "Juan Garcia" es cliente y empleado; por lo
tanto ambos aparecen 2 veces.
6- Realice la misma consulta anterior y agregue una columna con un literal para indicar si es un
proveedor, un cliente o un empleado(12 registros)
Ver solución
66 - Intersección
Continuamos aprendiendo las operaciones de conjuntos. Aprendimos "union" y "union all",
ahora veremos "intersect".
Como cualquier otra operación de conjuntos, "intersect" se emplea cuando los datos que se
quieren obtener pertenecen a distintas tablas y no se puede acceder a ellos con una sola consulta.
Del mismo modo, las tablas referenciadas DEBEN tener tipos de datos similares, la misma
cantidad de campos y el mismo orden de campos en la lista de selección de cada consulta que
intervenga en la intersección.
"intersect" devuelve la intersección de las consultas involucradas; es decir, el resultado retornará
los registros que se encuentran en la primera y segunda consulta (y demás si las hubiere), o sea,
los registros que todas las consultas tienen en común.
Sintaxis:
SENTENCIASELECT1
intersect
SENTENCIASELECT2;
No olvide que las consultas DEBEN tener el mismo numero de valores retornados y los valores
deben ser del mismo tipo.
Una academia de enseñanza de idiomas da clases de inglés, frances y portugues; almacena los
datos de los alumnos que estudian inglés en una tabla llamada "ingles", los que están inscriptos
en "francés" en una tabla denominada "frances" y los que aprenden portugues en la tabla
"portugues".
La academia necesita el nombre y domicilio de todos los alumnos que cursan los tres idiomas
para enviarles una tarjeta de descuento.
Para obtener los datos necesarios de las tres tablas en una sola consulta necesitamos realizar una
intresección:
select nombre, domicilio from ingles
intersect
select nombre, domicilio from frances
intersect
select nombre, domicilio from portugues;
El primer "select" devuelve el nombre y domicilio de todos los estudiantes de inglés; el segundo,
el nombre y domicilio de todos los inscriptos a francés y la tercera los mismos campos de los
alumnos de "portugues". Esta sentencia de intersección retornará los registros que coinciden en
las tres consultas "select".
"intersect" puede combinarse con la cláusula "order by".
66 - Intersección
Primer problema:
Una clínica almacena los datos de los médicos en una tabla llamada "medicos" y los datos de los
pacientes en otra denominada "pacientes".
1- Eliminamos ambas tablas:
drop table medicos;
drop table pacientes;
2- Creamos las tablas:
create table medicos(
legajo number(3),
documento varchar2(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
especialidad varchar2(30),
primary key(legajo)
);
create table pacientes(
documento varchar2(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
obrasocial varchar2(20),
primary key(documento)
);
3- Ingresamos algunos registros:
insert into medicos values(1,'20111222','Ana Acosta','Avellaneda
111','clinica');
insert into medicos values(2,'21222333','Betina Bustos','Bulnes
222','clinica');
insert into medicos values(3,'22333444','Carlos Caseros','Colon
333','pediatria');
insert into medicos values(4,'23444555','Daniel Duarte','Duarte Quiros
444','oculista');
insert into medicos values(5,'24555666','Estela Esper','Esmeralda
555','alergia');
insert into pacientes values('24555666','Estela Esper','Esmeralda
555','IPAM');
insert into pacientes values('23444555','Daniel Duarte','Duarte Quiros
444','OSDOP');
insert into pacientes values('30111222','Fabiana Fuentes','Famatina
666','PAMI');
insert into pacientes values('30111222','Gaston Gonzalez','Guemes
777','PAMI');
4- La clínica necesita el nombre y domicilio de médicos y pacientes para enviarles una tarjeta de
invitación a la inauguración de un nuevo establecimiento. Emplee el operador "union" para
obtener dicha información de ambas tablas (7 registros)
Note que existen dos médicos que también están presentes en la tabla "pacientes"; tales registros
aparecen una sola vez en el resultado de "union".
5- La clínica necesita el nombre y domicilio de los pacientes que también son médicos para
enviarles una tarjeta de descuento para ciertas prácticas. Emplee el operador "intersect" para
obtener dicha información de ambas tablas
Ver solución
Segundo problema:
Un supermercado almacena en una tabla denominada "proveedores" los datos de las compañías
que le proveen de mercaderías; en una tabla llamada "clientes", los datos de los comercios que le
compran y en otra tabla "empleados" los datos de los empleados.
1- Elimine las tablas:
drop table clientes;
drop table proveedores;
drop table empleados;
2- Cree las tablas:
create table proveedores(
codigo number(3) not null,
nombre varchar2(30),
domicilio varchar2(30),
primary key(codigo)
);
create table clientes(
codigo number(4),
nombre varchar2(30),
domicilio varchar2(30),
primary key(codigo)
);
create table empleados(
documento char(8) not null,
nombre varchar2(20),
apellido varchar2(20),
domicilio varchar2(30),
primary key(documento)
);
3- Ingrese algunos registros:
insert into proveedores values(1,'Valeria Vazquez','Colon 123');
insert into proveedores values(2,'Carnes Unica','Caseros 222');
insert into proveedores values(3,'Blanca Bustos','San Martin 987');
insert into proveedores values(4,'Luis Luque','San Martin 1234');
insert into clientes values(100,'Supermercado Lopez','Avellaneda 34');
insert into clientes values(101,'Almacen Anita','Colon 987');
insert into clientes values(102,'Juan Garcia','Sucre 345');
insert into clientes values(103,'Luis Luque','San Martin 1234');
insert into clientes values(104,'Valeria Vazquez','Colon 123');
insert into clientes values(105,'Federico Ferreyra','Colon 987');
insert into empleados values('23333333','Federico','Ferreyra','Colon 987');
insert into empleados values('28888888','Ana','Marquez','Sucre 333');
insert into empleados values('30111111','Pedro','Perez','Caseros 956');
insert into empleados values('31222333','Juan','Garcia','Sucre 345');
insert into empleados values('32333444','Luis','Luque','San Martin 1234');
insert into empleados values('33444555','Valeria','Vazquez','Colon 123');
insert into empleados values('34555666','Blanca','Bustos','San Martin 987');
4- El supermercado quiere enviar un bono de descuento a todos los empleados que son clientes.
Realice una combinación de intersección entre las tablas "clientes" y "empleados" (4 registros)
5- Se necesitan los nombres de aquellos proveedores que son clientes y también empleados del
supermercado (presentes en las tres tablas). Realice las operaciones necesarias (2 registros)
Ver solución
67 - Minus
Continuamos aprendiendo las operaciones de conjuntos. Aprendimos "union", "union all",
"intersect", nos resta ver "minus" (resta, diferencia).
Como cualquier otra operación de conjuntos, "minus" se emplea cuando los datos que se quieren
obtener pertenecen a distintas tablas y no se puede acceder a ellos con una sola consulta. Del
mismo modo, las tablas referenciadas DEBEN tener tipos de datos similares, la misma cantidad
de campos y el mismo orden de campos en la lista de selección de cada consulta que intervenga
en la operación de resta.
"minus" (diferencia) devuelve los registros de la primera consulta que no se encuentran en
segunda consulta, es decir, aquellos registros que no coinciden. Es el equivalente a "except" en
SQL.
Sintaxis:
SENTENCIASELECT1
minus
SENTENCIASELECT2;
No olvide que las consultas DEBEN tener el mismo numero de valores retornados y los valores
deben ser del mismo tipo.
Una academia de enseñanza de idiomas da clases de inglés y frances; almacena los datos de los
alumnos que estudian inglés en una tabla llamada "ingles" y los que están inscriptos en "francés"
en una tabla denominada "frances".
La academia necesita el nombre y domicilio de todos los alumnos que cursan solamente inglés
(no presentes en la tabla "frances") para enviarles publicidad referente al curso de francés.
Empleamos el operador "minus" para obtener dicha información:
select nombre, domicilio from ingles
minus
select nombre,domicilio from frances;
Obtenemos los registros de la primer consulta que NO coinciden con ningún registro de la
segunda consulta.
"minus" puede combinarse con la cláusula "order by".
Se pueden combinar más de dos sentencias con "minus".
67 - Minus
Primer problema:
Una clínica almacena los datos de los médicos en una tabla llamada "medicos" y los datos de los
pacientes en otra denominada "pacientes".
1- Eliminamos ambas tablas:
drop table medicos;
drop table pacientes;
2- Creamos las tablas:
create table medicos(
legajo number(3),
documento varchar2(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
especialidad varchar2(30),
primary key(legajo)
);
create table pacientes(
documento varchar2(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
obrasocial varchar2(20),
primary key(documento)
);
3- Ingresamos algunos registros:
insert into medicos values(1,'20111222','Ana Acosta','Avellaneda
111','clinica');
insert into medicos values(2,'21222333','Betina Bustos','Bulnes
222','clinica');
insert into medicos values(3,'22333444','Carlos Caseros','Colon
333','pediatria');
insert into medicos values(4,'23444555','Daniel Duarte','Duarte Quiros
444','oculista');
insert into medicos values(5,'24555666','Estela Esper','Esmeralda
555','alergia');
insert into pacientes values('24555666','Estela Esper','Esmeralda
555','IPAM');
insert into pacientes values('23444555','Daniel Duarte','Duarte Quiros
444','OSDOP');
insert into pacientes values('30111222','Fabiana Fuentes','Famatina
666','PAMI');
insert into pacientes values('30111222','Gaston Gonzalez','Guemes
777','PAMI');
4- La clínica necesita el nombre y domicilio de médicos y pacientes para enviarles una tarjeta de
invitación a la inauguración de un nuevo establecimiento. Emplee el operador "union" para
obtener dicha información de ambas tablas (7 registros)
5- Se necesitan los nombres de los médicos que también son pacientes de la clínica. Realice una
intersección entre las tablas.
6- La clínica necesita los nombres de los pacientes que no son médicos. Realice una operación de
resta.
7- Se necesitan los registros que no coinciden en ambas tablas. Realice la operación necesaria.
Ver solución
Segundo problema:
Un colegio guarda los datos de los alumnos que están cursando primer año en una tabla
denominada "primero", los datos de los alumnos que están cursando segundo año en una tabla
llamada "segundo" y en la tabla "inscriptos2" los datos de los alumnos inscriptos para segundo
año para el siguiente año.
1- Elimine las tablas:
drop table primero;
drop table segundo;
drop table inscriptos2;
2- Cree las tablas:
create table primero(
documento char(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
primary key(documento)
);
create table segundo(
documento char(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
primary key(documento)
);
create table inscriptos2(
documento char(8) not null,
nombre varchar2(30),
domicilio varchar2(30),
primary key(documento)
);
3- Ingrese algunos registros:
insert into primero values('40111222','Alicia Acosta','Avellaneda 111');
insert into primero values('41222333','Bernardo Bustos','Bulnes 222');
insert into primero values('41555666','Carlos Caseres','Colon 333');
insert into primero values('41888999','Diana Duarte','Dinamarca 444');
insert into primero values('42333444','Eduardo Esper','San Martin 555');
insert into segundo values('43444555','Federico Fuentes','Francia 666');
insert into segundo values('43666777','Gabriela Gomez','Garzon 777');
insert into segundo values('44555666','Hector Huerta','Colon 888');
insert into segundo values('44999000','Ines Irala','Inglaterra 999');
insert into segundo values('45111444','Juan Juarez','Jamaica 111');
insert into inscriptos2 values('41555666','Carlos Caseres','Colon 333');
insert into inscriptos2 values('41888999','Diana Duarte','Dinamarca 444');
insert into inscriptos2 values('42333444','Eduardo Esper','San Martin 555');
insert into inscriptos2 values('43444555','Federico Fuentes','Francia 666');
insert into inscriptos2 values('46777888','Luis Lopez','Lules 222');
insert into inscriptos2 values('47888999','Marina Moreno','Martin Garcia
333');
insert into inscriptos2 values('48999000','Nora Nores','Natividad 333');
Tenga en cuenta algunas consideraciones:
- algunos alumnos de primero, se han inscripto en el mismo colegio para cursar segundo año;
- algunos alumnos de primero no están inscriptos en segundo porque repetirán el próximo año o
se cambiarán de colegio;
- algunos alumnos que están cursando segundo están inscriptos nuevamente en segundo porque
repetirán el curso;
- algunos inscriptos para el año próximo en segundo, no están cursando primero en este colegio.
4- El colegio quiere saber los nombres de los inscriptos a segundo del año próximo que repiten
segundo (presentes en "segundo" y en "inscriptos2") (1 registro):
5- El colegio quiere saber los nombres de los alumnos que están cursando primero y están
inscriptos para segundo el próximo año (presentes en "inscriptos2" y en "primero") (3 registros)
6- El colegio quiere saber los nombres y domicilios de los alumnos inscriptos para segundo que
no están cursando este año en este colegio (presentes en "inscriptos2" y ausentes en "primero" y
"segundo") para enviarles una nota con la fecha para una reunión informativa (3 registros)
7- El colegios quiere saber los nombres de los alumnos inscriptos para segundo el próximo año,
que están cursando primero o segundo este año (presentes en "inscriptos2" y en "primero" o
"segundo). Realice las operaciones necesarias. (4 registros)
8- El colegio necesita los nombres de los alumnos que están cursando primero y no están
inscriptos el próximo año en segundo para enviarles un mail preguntando la razón por la cual no
se han anotado aún (2 registros)
Ver solución
68 - Agregar campos (alter table- add)
"alter table" permite modificar la estructura de una tabla. Podemos utilizarla para agregar,
modificar y eliminar campos de una tabla.
Para agregar un nuevo campo a una tabla empleamos la siguiente sintaxis básica:
alter table NOMBRETABLA
add NOMBRENUEVOCAMPO DEFINICION;
En el siguiente ejemplo agregamos el campo "cantidad" a la tabla "libros", de tipo number(4),
con el valor por defecto cero y que NO acepta valores nulos:
alter table libros
add cantidad number(4) default 0 not null;
Puede verificarse la alteración de la estructura de la tabla tipeando:
describe libros;
Para agregar un campo "not null", la tabla debe estar vacía o debe especificarse un valor por
defecto. Esto es sencillo de entender, ya que si la tabla tiene registros, el nuevo campo se llenaría
con valores nulos; si no los admite, debe tener un valor por defecto para llenar tal campo en los
registros existentes.
68 - Agregar campos (alter table- add)
Primer problema:
Trabaje con una tabla llamada "empleados".
1- Elimine la tabla y créela:
drop table empleados;
create table empleados(
apellido varchar2(20),
nombre varchar2(20) not null,
domicilio varchar2(30)
);
2- Agregue un campo "fechaingreso" de tipo date que acepte valores nulos
3- Verifique que la estructura de la tabla ha cambiado
4- Agregue un campo "seccion" de tipo caracter que no permita valores nulos y verifique que el
nuevo campo existe
5- Ingrese algunos registros:
insert into empleados values('Lopez','Juan','Colon
123','10/10/1980','Contaduria');
insert into empleados values('Gonzalez','Juana','Avellaneda
222','01/05/1990','Sistemas');
insert into empleados values('Perez','Luis','Caseros
987','12/09/2000','Secretaria');
6- Intente agregar un campo "sueldo" que no admita valores nulos.
7- Agregue el campo "sueldo" no nulo y con el valor 0 por defecto.
8- Verifique que la estructura de la tabla ha cambiado.
Ver solución
69 - Modificar campos (alter table- modify)
"alter table" permite modificar la estructura de una tabla. Hemos aprendido a agregar campos,
también podemos modificarlos.
Para modificar un campo empleamos la siguiente sintaxis:
alter table NOMBRETABLA
modify NOMBRECAMPO NUEVADEFINICION;
En el siguiente ejemplo modificamos el campo "precio" de la tabla "libros" para que tome
valores de 6 dígitos incluyendo 2 decimales y no acepte valores nulos:
alter table libros
modify precio number(6,2) not null;
Puede verificarse la alteración de la estructura de la tabla tipeando:
describe libros;
Podemos modificar de un campo: el tipo de dato, la escala y/o precisión, la longitud, la
aceptación de valores nulos, el valor por defecto.
Se pueden modificar todos los atributos o algunos; los que no se especifican, no cambian.
Algunas consideraciones para tener en cuenta al modificar los campos de una tabla:
a) si se cambia el tipo de dato de un campo, la tabla debe estar vacía. Por ejemplo, de number a
caracteres o viceversa.
b) no puede modificarse el tipo de dato de un campo "foreign key" o referenciado por una
"foreign key", a menos que el cambio no afecte la restricción.
c) no se puede cambiar el tipo de dato de un campo que es "foreign key" o que es referenciado
por una "foreign key".
d) para modificar un campo disminuyendo la longitud (precisión o escala) del tipo de dato, la
tabla DEBE estar vacía, los registros DEBEN tener valores nulos en tal campo o los datos
existentes deben ser inferiores o iguales a la nueva longitud. Para alterar la longitud (escala o
precisión) aumentándola, no es necesario que la tabla esté vacía.
e) se puede modificar un campo definido "null" a "not null", siempre que la tabla esté vacía o no
contenga valores nulos.
f) no puede redefinirse como "not null" un campo que es clave primaria.
g) si un campo tiene un valor por defecto y se modifica el tipo de dato de tal campo, Oracle
analiza que el valor por defecto pueda convertirse al nuevo tipo de dato cuando sea necesario
insertarlo; si el valor por defecto no se puede convertir al nuevo tipo de dato que se intenta
modificar, la modificación del campo no se realiza. Por ejemplo, si un campo definido char(8)
tiene un valor por defecto '00000000' y se modifica tal campo a tipo number(8), Oracle permite
el cambio ya que al insertar el valor por defecto, lo convierte a número (0) automáticamente; si el
valor por defecto no se puede convertir (por ejemplo 'a000000') a valor numérico, la
modificación del campo no se realiza.
69 - Modificar campos (alter table- modify)
Primer problema:
Trabaje con una tabla llamada "empleados" y "secciones".
1- Elimine las tablas y créelas:
drop table empleados;
drop table secciones;
create table secciones(
codigo number(2),
nombre varchar(20),
primary key (codigo)
);
create table empleados(
apellido varchar2(20) not null,
nombre varchar2(20),
domicilio varchar2(30),
seccion number(2),
fechaingreso date,
telefono number(7),
constraint FK_empleados_seccion
foreign key (seccion)
references secciones(codigo)
on delete set null
);
2- Modifique el tipo de dato del campo "telefono" a varchar(11)
Oracle lo permite porque la tabla está vacía; si no lo estuviese, no lo permitiría.
3- Ingrese algunos registros en ambas tablas
insert into secciones values(8,'Secretaria');
insert into secciones values(9,'Contaduria');
insert into secciones values(10,'Sistemas');
insert into empleados values('Lopez','Luciano','Colon
123',8,'10/10/1980','4819977');
insert into empleados values('Gonzalez',null,'Avellaneda
222',9,'01/05/1990','4515566');
4- Modifique el campo "nombre" de "empleados" para que permita cadenas variables de 10
caracteres (menor longitud) y luego verifique el cambio.
Oracle lo permite, porque los valores en tal campo son menores a 10.
5- Intente modificar el campo "nombre" de "empleados" para que permita cadenas variables de 6
caracteres (menor longitud)
Oracle no lo permite, porque un valor en tal campo consta de 7 caracteres.
6- Elimine el registro correspondiente a "Lopez Luciano"
7- Modifique el campo "nombre" de "empleados" para que permita cadenas variables de 6
caracteres
Oracle lo permite, la tabla no está vacía pero los registros contienen valor nulo en el campo
"nombre".
8- Intente cambiar el tipo de dato del campo "codigo" de "secciones" a char(2)
Oracle no lo permite porque tal campo es referenciado por una clave externa.
9- Cambie la longitud del campo "codigo" de "secciones" a 3.
Oracle lo permite porque el cambio no afecta la restricción "foreign key" que referencia el campo
"codigo".
10- Intente modificar el campo "nombre" de "empleados" para que no admita valores nulos.
Mensaje de error, la tabla contiene valores nulos en tal campo.
11- Modifique el valor nulo por uno válido del campo "nombre" de "empleados" y luego realice
la modificación del punto anterior.
12- Verifique que "nombre" ya no admite valores nulos.
Ver solución
70 - Eliminar campos (alter table- drop)
Vimos que "alter table" permite modificar la estructura de una tabla, agregando, modificando y
eliminando campos.
Para eliminar campos de una tabla la sintaxis básica es la siguiente:
alter table NOMBRETABLA
drop column NOMBRECAMPO;
En el siguiente ejemplo eliminamos el campo "precio" de la tabla "libros":
alter table libros
drop column precio;
No pueden eliminarse los campos a los cuales hace referencia una restricción "foreign key".
Si eliminamos un campo que tiene una restricción "primary key", "unique", "check" o "foreign
key", la restricción también se elimina.
Si eliminamos un campo indexado, el índice también se elimina.
NO puede eliminarse un campo si es el único en la tabla.
Puede verificarse la alteración de la estructura de la tabla tipeando:
describe libros;
70 - Eliminar campos (alter table- drop)
Primer problema:
Trabaje con una tabla llamada "empleados" y "secciones".
1- Elimine las tablas y créelas:
drop table empleados;
drop table secciones;
create table secciones(
codigo number(2),
nombre varchar(20),
primary key (codigo)
);
create table empleados(
apellido varchar2(20),
nombre varchar2(20) not null,
domicilio varchar2(30),
seccion number(2),
sueldo number(8,2),
constraint CK_empleados_sueldo
check (sueldo>=0) disable,
fechaingreso date,
constraint FK_empleados_seccion
foreign key (seccion)
references secciones(codigo)
on delete set null
);
2- Ingrese algunos registros en ambas tablas:
insert into secciones values(8,'Secretaria');
insert into secciones values(9,'Contaduria');
insert into secciones values(10,'Sistemas');
insert into empleados values('Lopez','Juan','Colon
123',8,505.50,'10/10/1980');
insert into empleados values('Gonzalez','Juana','Avellaneda
222',9,600,'01/05/1990');
insert into empleados values('Perez','Luis','Caseros
987',10,800,'12/09/2000');
3- Elimine el campo "domicilio" y luego verifique la eliminación
4- Vea las restricciones de "empleados" (1 restricción "foreign key" y 2 "check")
5- Intente eliminar el campo "codigo" de "secciones"
6- Elimine la restricción "foreign key" de "empleados", luego elimine el campo "codigo" de
"secciones" y verifique la eliminación
7- Verifique que al eliminar el campo "codigo" de "secciones" se ha eliminado la "primary key"
de "secciones"
8- Elimine el campo "sueldo" y verifique que la restricción sobre tal campo se ha eliminado
9- Cree un índice no único por el campo "apellido" y verifique su existencia consultando
"user_indexes"
10- Elimine el campo "apellido" y verifique que el índice se ha eliminado
11- Elimine 2 campos de "empleados" y vea la estructura de la tabla
12- Intente eliminar el único campo de "empleados"
Ver solución
71 - Agregar campos y restricciones (alter
table)
Podemos agregar un campo a una tabla y en el mismo momento aplicarle una restricción.
Para agregar un campo y establecer una restricción, la sintaxis básica es la siguiente:
alter table TABLA
add CAMPO DEFINICION
constraint NOMBRERESTRICCION TIPO;
Agregamos a la tabla "libros", el campo "titulo" de tipo varchar2(30) y una restricción "unique":
alter table libros
add titulo varchar2(30)
constraint UQ_libros_autor unique;
Agregamos a la tabla "libros", el campo "codigo" de tipo number(4) not null y una restricción
"primary key":
alter table libros
add codigo number(4) not null
constraint PK_libros_codigo primary key;
Agregamos a la tabla "libros", el campo "precio" de tipo number(6,2) y una restricción "check":
alter table libros
add precio number(6,2)
constraint CK_libros_precio check (precio>=0);
71 - Agregar campos y restricciones (alter
table)
Primer problema:
Trabaje con una tabla llamada "empleados".
1- Elimine la tabla y créela:
drop table empleados;
create table empleados(
documento char(8) not null,
nombre varchar2(10),
domicilio varchar2(30),
ciudad varchar2(20) default 'Buenos Aires'
);
2- Agregue el campo "legajo" de tipo number(3) y una restricción "primary key"
3- Vea si la estructura cambió y si se agregó la restricción
4- Agregue el campo "hijos" de tipo number(2) y en la misma sentencia una restricción "check"
que no permita valores superiores a 30
5- Ingrese algunos registros:
insert into empleados values('22222222','Juan Lopez','Colon
123','Cordoba',100,2);
insert into empleados values('23333333','Ana Garcia','Sucre
435','Cordoba',200,3);
6- Intente agregar el campo "sueldo" de tipo number(6,2) no nulo y una restricción "check" que
no permita valores negativos para dicho campo.
No lo permite porque no damos un valor por defecto para dicho campo no nulo y los registros
existentes necesitan cargar un valor.
7- Agregue el campo "sueldo" de tipo number(6,2) no nulo, con el valor por defecto 0 y una
restricción "check" que no permita valores negativos para dicho campo
8- Recupere los registros
select *from empleados;
9- Vea la nueva estructura de la tabla
10- Vea las restricciones
Ver solución
72 - Subconsultas
Una subconsulta (subquery) es una sentencia "select" anidada en otra sentencia "select", "insert",
"update" o "delete" (o en otra subconsulta).
Las subconsultas se emplean cuando una consulta es muy compleja, entonces se la divide en
varios pasos lógicos y se obtiene el resultado con una única instrucción y cuando la consulta
depende de los resultados de otra consulta.
Generalmente, una subconsulta se puede reemplazar por combinaciones y estas últimas son más
eficientes.
Las subconsultas generalmente se incluyen entre paréntesis.
Puede haber subconsultas dentro de subconsultas.
Generalmente las subconsultas se colocan en la cláusula "where".
Una subconsulta puede retornar:
- un solo valor,
- una lista de valores de una sola columna,
- un conjunto de registros de varios campos.
Podemos averiguar si un valor de la consulta externa pertenece o no al conjunto devuelto por una
subconsulta ("in", "not in"), si es mayor, menor o igual a todos ("all") o a algunos valores
("some", "any") del conjunto devuelto.
Se pueden emplear subconsultas:
- en lugar de una expresión, siempre que devuelvan un solo valor o una lista de valores.
- que retornen un conjunto de registros de varios campos en lugar de una tabla o para obtener el
mismo resultado que una combinación (join).
Hay varios tipos básicos de subconsultas:
- las que retornan un solo valor escalar que se utiliza con un operador de comparación o en lugar
de una expresión.
- las que retornan una lista de valores, se combinan con "in", o los operadores "any", "some" y
"all".
- los que testean la existencia con "exists".
73 - Subconsultas como expresion
Una subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver un valor
escalar (o una lista de valores de un campo).
Las subconsultas que retornan un solo valor escalar se utiliza con un operador de comparación o
en lugar de una expresión:
select CAMPOS
from TABLA
where CAMPO OPERADOR (SUBCONSULTA);
select CAMPO OPERADOR (SUBCONSULTA)
from TABLA;
Si queremos saber el precio de un determinado libro y la diferencia con el precio del libro más
costoso, anteriormente debíamos averiguar en una consulta el precio del libro más costoso y
luego, en otra consulta, calcular la diferencia con el valor del libro que solicitamos. Podemos
conseguirlo en una sola sentencia combinando dos consultas:
select titulo,precio,
precio-(select max(precio) from libros) as diferencia
from libros
where titulo='Uno';
En el ejemplo anterior se muestra el título, el precio de un libro y la diferencia entre el precio del
libro y el máximo valor de precio.
Queremos saber el título, autor y precio del libro más costoso:
select titulo,autor, precio
from libros
where precio=
(select max(precio) from libros);
Note que el campo del "where" de la consulta exterior es compatible con el valor retornado por la
expresión de la subconsulta.
Se pueden emplear en "select", "insert", "update" y "delete".
Para actualizar un registro empleando subconsulta la sintaxis básica es la siguiente:
update TABLA set CAMPO=NUEVOVALOR
where CAMPO= (SUBCONSULTA);
Para eliminar registros empleando subconsulta empleamos la siguiente sintaxis básica:
delete from TABLA
where CAMPO=(SUBCONSULTA);
73 - Subconsultas como expresion
Primer problema:
Un profesor almacena el documento, nombre y la nota final de cada alumno de su clase en una
tabla llamada "alumnos".
1- Elimine la tabla:
drop table alumnos;
2- Créela con los campos necesarios. Agregue una restricción "primary key" para el campo
"documento" y una "check" para validar que el campo "nota" se encuentre entre los valores 0 y
10:
create table alumnos(
documento char(8),
nombre varchar2(30),
nota number(4,2),
primary key(documento),
constraint CK_alumnos_nota_valores check (nota>=0 and nota <=10)
);
3-Ingrese algunos registros:
insert into alumnos values('30111111','Ana Algarbe',5.1);
insert into alumnos values('30222222','Bernardo Bustamante',3.2);
insert into alumnos values('30333333','Carolina Conte',4.5);
insert into alumnos values('30444444','Diana Dominguez',9.7);
insert into alumnos values('30555555','Fabian Fuentes',8.5);
insert into alumnos values('30666666','Gaston Gonzalez',9.70);
4- Obtenga todos los datos de los alumnos con la nota más alta, empleando subconsulta
5- Realice la misma consulta anterior pero intente que la consulta interna retorne, además del
máximo valor de nota, el nombre del alumno.
Mensaje de error, porque la lista de selección de una subconsulta que va luego de un operador de
comparación puede incluir sólo un campo o expresión (excepto si se emplea "exists" o "in").
6- Muestre los alumnos que tienen una nota menor al promedio, su nota, y la diferencia con el
promedio.
7- Cambie la nota del alumno que tiene la menor nota por 4.
8- Elimine los alumnos cuya nota es menor al promedio.
Ver solución
74 - Subconsultas con in
Vimos que una subconsulta puede reemplazar una expresión. Dicha subconsulta debe devolver
un valor escalar o una lista de valores de un campo; las subconsultas que retornan una lista de
valores reemplazan a una expresión en una cláusula "where" que contiene la palabra clave "in".
El resultado de una subconsulta con "in" (o "not in") es una lista. Luego que la subconsulta
retorna resultados, la consulta exterior los usa.
Podemos averiguar si un valor de la consulta externa pertenece o no al conjunto devuelto por una
subconsulta empleando "in" y "not in".
La sintaxis básica es la siguiente:
...where EXPRESION in (SUBCONSULTA);
Este ejemplo muestra los nombres de las editoriales que ha publicado libros de un determinado
autor:
select nombre
from editoriales
where codigo in
(select codigoeditorial
from libros
where autor='Richard Bach');
La subconsulta (consulta interna) retorna una lista de valores de un solo campo (codigoeditorial)
que la consulta exterior luego emplea al recuperar los datos.
Se averigua si el código devuelto por la consulta externa se encuentra dentro del conjunto de
valores retornados por la consulta interna.
Podemos reemplazar por un "join" la consulta anterior:
select distinct nombre
from editoriales e
join libros
on codigoeditorial=[Link]
where autor='Richard Bach';
Una combinación (join) siempre puede ser expresada como una subconsulta; pero una
subconsulta no siempre puede reemplazarse por una combinación que retorne el mismo
resultado. Si es posible, es aconsejable emplear combinaciones en lugar de subconsultas, son más
eficientes.
Se recomienda probar las subconsultas antes de incluirlas en una consulta exterior, así puede
verificar que retorna lo necesario, porque a veces resulta difícil verlo en consultas anidadas.
También podemos buscar valores No coincidentes con una lista de valores que retorna una
subconsulta; por ejemplo, las editoriales que no han publicado libros de un autor específico:
select nombre
from editoriales
where codigo not in
(select codigoeditorial
from libros
where autor='Richard Bach');
74 - Subconsultas con in
Primer problema:
Una empresa tiene registrados sus clientes en una tabla llamada "clientes", también tiene una
tabla "ciudades" donde registra los nombres de las ciudades.
1- Elimine las tablas "clientes" y "ciudades":
drop table clientes;
drop table ciudades;
2- Cree la tabla "clientes" (codigo, nombre, domicilio, ciudad, codigociudad) y "ciudades"
(codigo, nombre). Agregue una restricción "primary key" para el campo "codigo" de ambas
tablas y una "foreing key" para validar que el campo "codigociudad" exista en "ciudades" con
eliminación en cascada:
create table ciudades(
codigo number(2),
nombre varchar2(20),
primary key (codigo)
);
create table clientes (
codigo number(4),
nombre varchar2(30),
domicilio varchar2(30),
codigociudad number(2) not null,
primary key(codigo),
constraint FK_clientes_ciudad
foreign key (codigociudad)
references ciudades(codigo)
on delete cascade
);
3- Ingrese algunos registros para ambas tablas:
insert into ciudades values(1,'Cordoba');
insert into ciudades values(2,'Cruz del Eje');
insert into ciudades values(3,'Carlos Paz');
insert into ciudades values(4,'La Falda');
insert into ciudades values(5,'Villa Maria');
insert into clientes values (100,'Lopez Marcos','Colon 111',1);
insert into clientes values (101,'Lopez Hector','San Martin 222',1);
insert into clientes values (105,'Perez Ana','San Martin 333',2);
insert into clientes values (106,'Garcia Juan','Rivadavia 444',3);
insert into clientes values (107,'Perez Luis','Sarmiento 555',3);
insert into clientes values (110,'Gomez Ines','San Martin 666',4);
insert into clientes values (111,'Torres Fabiola','Alem 777',5);
insert into clientes values (112,'Garcia Luis','Sucre 888',5);
4- Necesitamos conocer los nombres de las ciudades de aquellos clientes cuyo domicilio es en
calle "San Martin", empleando subconsulta.
5- Obtenga la misma salida anterior pero empleando join.
6- Obtenga los nombre de las ciudades de los clientes cuyo apellido no comienza con una letra
específica (letra "G"), empleando subconsulta.
7- Pruebe la subconsulta del punto 6 separada de la consulta exterior para verificar que retorna
una lista de valores de un solo campo.
Ver solución
75 - Subconsultas any- some- all
"any" y "some" son sinónimos. Chequean si alguna fila de la lista resultado de una subconsulta
se encuentra el valor especificado en la condición.
Compara un valor escalar con los valores de un campo y devuelven "true" si la comparación con
cada valor de la lista de la subconsulta es verdadera, sino "false".
El tipo de datos que se comparan deben ser compatibles.
La sintaxis básica es:
...VALORESCALAR OPERADORDECOMPARACION
any (SUBCONSULTA);
Queremos saber los títulos de los libros de "Borges" que pertenecen a editoriales que han
publicado también libros de "Richard Bach", es decir, si los libros de "Borges" coinciden con
ALGUNA de las editoriales que publicó libros de "Richard Bach":
select titulo
from libros
where autor='Borges' and
codigoeditorial = any
(select [Link]
from editoriales e
join libros l
on codigoeditorial=[Link]
where [Link]='Richard Bach');
La consulta interna (subconsulta) retorna una lista de valores de un solo campo (puede ejecutar la
subconsulta como una consulta para probarla), luego, la consulta externa compara cada valor de
"codigoeditorial" con cada valor de la lista devolviendo los títulos de "Borges" que coinciden.
"all" también compara un valor escalar con una serie de valores. Chequea si TODOS los valores
de la lista de la consulta externa se encuentran en la lista de valores devuelta por la consulta
interna.
Sintaxis:
VALORESCALAR OPERADORDECOMPARACION all (SUBCONSULTA);
Queremos saber si TODAS las editoriales que publicaron libros de "Borges" coinciden con
TODAS las editoriales que publicaron libros de "Richard Bach":
select titulo
from libros
where autor='Borges' and
codigoeditorial = all
(select [Link]
from editoriales e
join libros l
on codigoeditorial=[Link]
where [Link]='Richard Bach');
La consulta interna (subconsulta) retorna una lista de valores de un solo campo (puede ejecutar la
subconsulta como una consulta para probarla), luego, la consulta externa compara cada valor de
"codigoeditorial" con cada valor de la lista, si TODOS coinciden, devuelve los títulos.
Veamos otro ejemplo con un operador de comparación diferente:
Queremos saber si ALGUN precio de los libros de "Borges" es mayor a ALGUN precio de los
libros de "Richard Bach":
select titulo,precio
from libros
where autor='Borges' and
precio > any
(select precio
from libros
where autor='Bach');
El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornada
por la subconsulta; si ALGUNO cumple la condición, es decir, es mayor a ALGUN precio de
"Richard Bach", se lista.
Veamos la diferencia si empleamos "all" en lugar de "any":
select titulo,precio
from libros
where autor='borges' and
precio > all
(select precio
from libros
where autor='bach');
El precio de cada libro de "Borges" es comparado con cada valor de la lista de valores retornada
por la subconsulta; si cumple la condición, es decir, si es mayor a TODOS los precios de
"Richard Bach" (o al mayor), se lista.
Emplear "= any" es lo mismo que emplear "in".
Emplear "<> all" es lo mismo que emplear "not in".
75 - Subconsultas any- some- all
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Elimine las tablas:
drop table inscriptos;
drop table socios;
2- Cree las tablas:
create table socios(
numero number(5),
documento char(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key (numero)
);
create table inscriptos (
numerosocio number(5),
deporte varchar2(20) not null,
cuotas number(2) default 0,
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10),
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on delete cascade
);
3- Ingrese algunos registros:
insert into socios values(1,'23333333','Alberto Paredes','Colon 111');
insert into socios values(2,'24444444','Carlos Conte','Sarmiento 755');
insert into socios values(3,'25555555','Fabian Fuentes','Caseros 987');
insert into socios values(4,'26666666','Hector Lopez','Sucre 344');
insert into inscriptos values(1,'tenis',1);
insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);
4- Muestre el número de socio, el nombre del socio y el deporte en que está inscripto con un join
de ambas tablas
5- Muestre los socios que se serán compañeros en tenis y también en natación (empleando
subconsulta)
6- Vea si el socio 1 se ha inscripto en algún deporte en el cual se haya inscripto el socio 2
7- Realice la misma consulta anterior pero empleando "in" en lugar de "=any"
8- Obtenga el mismo resultado anterior pero empleando join
9- Muestre los deportes en los cuales el socio 2 pagó más cuotas que ALGUN deporte en los que
se inscribió el socio 1
select deporte from inscriptos i where numerosocio=2 and cuotas>any (select cuotas from inscriptos
where numerosocio=1);
10- Realice la misma consulta anterior pero empleando "some" en lugar de "any"
11- Muestre los deportes en los cuales el socio 2 pagó más cuotas que TODOS los deportes en
que se inscribió el socio 1
12- Cuando un socio no ha pagado la matrícula de alguno de los deportes en que se ha inscripto,
se lo borra de la inscripción de todos los deportes. Elimine todos los socios que no pagaron
ninguna cuota en algún deporte (cuota=0)
Ver solución
76 - Subconsultas correlacionadas
Un almacén almacena la información de sus ventas en una tabla llamada "facturas" en la cual
guarda el número de factura, la fecha y el nombre del cliente y una tabla denominada "detalles"
en la cual se almacenan los distintos items correspondientes a cada factura: el nombre del
artículo, el precio (unitario) y la cantidad.
Se necesita una lista de todas las facturas que incluya el número, la fecha, el cliente, la cantidad
de artículos comprados y el total:
select f.*,
(select count([Link])
from Detalles d
where [Link]=[Link]) as cantidad,
(select sum([Link]*cantidad)
from Detalles d
where [Link]=[Link]) as total
from facturas f;
El segundo "select" retorna una lista de valores de una sola columna con la cantidad de items por
factura (el número de factura lo toma del "select" exterior); el tercer "select" retorna una lista de
valores de una sola columna con el total por factura (el número de factura lo toma del "select"
exterior); el primer "select" (externo) devuelve todos los datos de cada factura.
A este tipo de subconsulta se la denomina consulta correlacionada. La consulta interna se evalúa
tantas veces como registros tiene la consulta externa, se realiza la subconsulta para cada registro
de la consulta externa. El campo de la tabla dentro de la subconsulta ([Link]) se compara con
el campo de la tabla externa.
En este caso, específicamente, la consulta externa pasa un valor de "numero" a la consulta
interna. La consulta interna toma ese valor y determina si existe en "detalles", si existe, la
consulta interna devuelve la suma. El proceso se repite para el registro de la consulta externa, la
consulta externa pasa otro "numero" a la consulta interna y Oracle repite la evaluación.
76 - Subconsultas correlacionadas
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Elimine las tablas:
drop table inscriptos;
drop table socios;
2- Cree las tablas:
create table socios(
numero number(4),
documento char(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key (numero)
);
create table inscriptos (
numerosocio number(4) not null,
deporte varchar(20) not null,
cuotas number(2) default 0,
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10),
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on delete cascade
);
3- Ingrese algunos registros:
insert into socios values(1,'23333333','Alberto Paredes','Colon 111');
insert into socios values(2,'24444444','Carlos Conte','Sarmiento 755');
insert into socios values(3,'25555555','Fabian Fuentes','Caseros 987');
insert into socios values(4,'26666666','Hector Lopez','Sucre 344');
insert into inscriptos values(1,'tenis',1);
insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);
4- Se necesita un listado de todos los socios que incluya nombre y domicilio, la cantidad de
deportes a los cuales se ha inscripto, empleando subconsulta.
5- Se necesita el nombre de todos los socios, el total de cuotas que debe pagar (10 por cada
deporte) y el total de cuotas pagas, empleando subconsulta.
6- Obtenga la misma salida anterior empleando join.
Ver solución
77 - Exists y No Exists
Los operadores "exists" y "not exists" se emplean para determinar si hay o no datos en una lista
de valores.
Estos operadores pueden emplearse con subconsultas correlacionadas para restringir el resultado
de una consulta exterior a los registros que cumplen la subconsulta (consulta interior). Estos
operadores retornan "true" (si las subconsultas retornan registros) o "false" (si las subconsultas
no retornan registros).
Cuando se coloca en una subconsulta el operador "exists", Oracle analiza si hay datos que
coinciden con la subconsulta, no se devuelve ningún registro, es como un test de existencia;
Oracle termina la recuperación de registros cuando por lo menos un registro cumple la condición
"where" de la subconsulta.
La sintaxis básica es la siguiente:
... where exists (SUBCONSULTA);
En este ejemplo se usa una subconsulta correlacionada con un operador "exists" en la cláusula
"where" para devolver una lista de clientes que compraron el artículo "lapiz":
select cliente,numero
from facturas f
where exists
(select *from Detalles d
where [Link]=[Link]
and [Link]='lapiz');
Puede obtener el mismo resultado empleando una combinación.
Podemos buscar los clientes que no han adquirido el artículo "lapiz" empleando "if not exists":
select cliente,numero
from facturas f
where not exists
(select *from Detalles d
where [Link]=[Link]
and [Link]='lapiz');
77 - Exists y No Exists
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte en el cual se inscribe
y la cantidad de cuotas pagas (desde 0 hasta 10 que es el total por todo el año), y una tabla
denominada "socios" en la que guarda los datos personales de cada socio.
1- Elimine las tablas:
drop table inscriptos;
drop table socios;
2- Cree las tablas:
create table socios(
numero number(4),
documento char(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key (numero)
);
create table inscriptos (
numerosocio number(4) not null,
deporte varchar2(20) not null,
cuotas number(2) default 0,
constraint CK_inscriptos_cuotas
check (cuotas>=0 and cuotas<=10),
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
on delete cascade
);
3- Ingrese algunos registros:
insert into socios values(1,'23333333','Alberto Paredes','Colon 111');
insert into socios values(2,'24444444','Carlos Conte','Sarmiento 755');
insert into socios values(3,'25555555','Fabian Fuentes','Caseros 987');
insert into socios values(4,'26666666','Hector Lopez','Sucre 344');
insert into inscriptos values(1,'tenis',1);
insert into inscriptos values(1,'basquet',2);
insert into inscriptos values(1,'natacion',1);
insert into inscriptos values(2,'tenis',9);
insert into inscriptos values(2,'natacion',1);
insert into inscriptos values(2,'basquet',default);
insert into inscriptos values(2,'futbol',2);
insert into inscriptos values(3,'tenis',8);
insert into inscriptos values(3,'basquet',9);
insert into inscriptos values(3,'natacion',0);
insert into inscriptos values(4,'basquet',10);
4- Emplee una subconsulta con el operador "exists" para devolver la lista de socios que se
inscribieron en un determinado deporte.
5- Busque los socios que NO se han inscripto en un deporte determinado empleando "not exists".
6- Muestre todos los datos de los socios que han pagado todas las cuotas.
7- Obtenga el mismo resultado de la consulta anterior pero esta vez emplee una combinación.
Ver solución
78 - Subconsulta simil autocombinacion
Algunas sentencias en las cuales la consulta interna y la externa emplean la misma tabla pueden
reemplazarse por una autocombinación.
Por ejemplo, queremos una lista de los libros que han sido publicados por distintas editoriales.
select distinct [Link]
from libros l1
where [Link] in
(select [Link]
from libros l2
where [Link] <> [Link]);
En el ejemplo anterior empleamos una subconsulta correlacionada y las consultas interna y
externa emplean la misma tabla. La subconsulta devuelve una lista de valores por ello se emplea
"in" y sustituye una expresión en una cláusula "where".
Con el siguiente "join" se obtiene el mismo resultado:
select distinct [Link]
from libros l1
join libros l2
on [Link]=[Link] and
[Link]=[Link]
where [Link]<>[Link];
Otro ejemplo: Buscamos todos los libros que tienen el mismo precio que "El aleph" empleando
subconsulta:
select titulo
from libros
where titulo<>'El aleph' and
precio =
(select precio
from libros
where titulo='El aleph');
La subconsulta retorna un solo valor. Podemos obtener la misma salida empleando "join".
Buscamos los libros cuyo precio supere el precio promedio de los libros por editorial:
select [Link],[Link],[Link]
from libros l1
where [Link] >
(select avg([Link])
from libros l2
where [Link]= [Link]);
Por cada valor de l1, se evalúa la subconsulta, si el precio es mayor que el promedio.
Se puede conseguir el mismo resultado empleando un "join" con "having".
78 - Subconsulta simil autocombinacion
Primer problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada "deportes"
en la cual almacena el nombre del deporte, el nombre del profesor que lo dicta, el día de la
semana que se dicta y el costo de la cuota mensual.
1- Elimine la tabla:
drop table deportes;
2- Cree la tabla:
create table deportes(
nombre varchar2(15),
profesor varchar2(30),
dia varchar2(10),
cuota number(5,2)
);
3- Ingrese algunos registros. Incluya profesores que dicten más de un curso:
insert into deportes values('tenis','Ana Lopez','lunes',20);
insert into deportes values('natacion','Ana Lopez','martes',15);
insert into deportes values('futbol','Carlos Fuentes','miercoles',10);
insert into deportes values('basquet','Gaston Garcia','jueves',15);
insert into deportes values('padle','Juan Huerta','lunes',15);
insert into deportes values('handball','Juan Huerta','martes',10);
4- Muestre los nombres de los profesores que dictan más de un deporte empleando subconsulta
(2 registros)
5- Obtenga el mismo resultado empleando join
6- Buscamos todos los deportes que se dictan el mismo día que un determinado deporte
(natacion) empleando subconsulta (1 registro)
7- Obtenga la misma salida empleando "join"
Ver solución
79 - Subconsulta con update y delete
Dijimos que podemos emplear subconsultas en sentencias "insert", "update", "delete", además de
"select".
La sintaxis básica para realizar actualizaciones con subconsulta es la siguiente:
update TABLA set CAMPO=NUEVOVALOR
where CAMPO= (SUBCONSULTA);
Actualizamos el precio de todos los libros de editorial "Emece":
update libros set precio=precio+(precio*0.1)
where codigoeditorial=
(select codigo
from editoriales
where nombre='Emece');
La subconsulta retorna un único valor. También podemos hacerlo con un join.
La sintaxis básica para realizar eliminaciones con subconsulta es la siguiente:
delete from TABLA
where CAMPO OPERADOR (SUBCONSULTA);
Eliminamos todos los libros de las editoriales que tiene publicados libros de "Juan Perez":
delete from libros
where codigoeditorial in
(select [Link]
from editoriales e
join libros
on codigoeditorial=[Link]
where autor='Juan Perez');
La subconsulta es una combinación que retorna una lista de valores que la consulta externa
emplea al seleccionar los registros para la eliminación.
79 - Subconsulta con update y delete
Primer problema:
Un supermercado almacena los datos de sus empleados en una tabla denominada "empleados" y
en una tabla llamada "sucursales" los códigos y ciudades de las diferentes sucursales.
1- Elimine las tablas "empleados" y "sucursales":
drop table empleados;
drop table sucursales;
2- Cree la tabla "sucursales":
create table sucursales(
codigo number(2),
ciudad varchar2(30) not null,
provincia varchar2(30),
primary key(codigo)
);
3- Cree la tabla "empleados":
create table empleados(
documento char(8) not null,
nombre varchar2(30) not null,
codigosucursal number(2),
sueldo number(6,2),
primary key(documento),
constraint FK_empleados_sucursal
foreign key (codigosucursal)
references sucursales(codigo)
);
4- Ingrese algunos registros para ambas tablas:
insert into sucursales values(1,'Cordoba','Cordoba');
insert into sucursales values(2,'Tucuman','Tucuman');
insert into sucursales values(3,'Carlos Paz','Cordoba');
insert into sucursales values(4,'Cruz del Eje','Cordoba');
insert into sucursales values(5,'La Plata','Buenos Aires');
insert into empleados values('22222222','Ana Acosta',1,500);
insert into empleados values('23333333','Carlos Caseros',1,610);
insert into empleados values('24444444','Diana Dominguez',2,600);
insert into empleados values('25555555','Fabiola Fuentes',5,700);
insert into empleados values('26666666','Gabriela Gonzalez',3,800);
insert into empleados values('27777777','Juan Juarez',4,850);
insert into empleados values('28888888','Luis Lopez',4,500);
insert into empleados values('29999999','Maria Morales',5,800);
5- Realice un join para mostrar el documento, nombre, sueldo, ciudad y provincia de todos los
empleados
6- El supermercado necesita incrementar en un 10% el sueldo de los empleados de la sucursal de
"Cruz del Eje". Actualice el campo "sueldo" de la tabla "empleados" de todos los empleados de
dicha sucursal empleando subconsulta.
7- El supermercado quiere incrementar en un 20% el sueldo de los empleados de las sucursales
de la provincia de Córdoba. Actualice el campo "sueldo" de la tabla "empleados" de todos los
empleados de tales sucursales empleando subconsulta.
8- La empleada "Ana Acosta" es trasladada a la sucursal de Carlos Paz. Se necesita actualizar el
sueldo y la sucursal de tal empleada empleando subconsultas, debe tener el mismo sueldo que la
empleada "Maria Morales".
9- El empleado "Carlos Caseros" se traslada a la sucursal de "La Plata". Se necesita actualizar el
sueldo y sucursal de tal empleado con los mismos valores que la empleada "Maria Morales"
(emplee subconsulta).
10- El supermercado cerrará todas las sucursales de la provincia de "Cordoba". Elimine los
empleados que pertenezcan a sucursales de tal provincia empleando subconsulta.
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte en el cual se inscribe
y si la matricula está o no paga, y una tabla denominada "socios" en la que guarda los datos
personales de cada socio.
1- Elimine las tablas:
drop table inscriptos;
drop table socios;
2- Cree las tablas:
create table socios(
numero number(5),
documento char(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key (numero)
);
create table inscriptos (
numerosocio number(5) not null,
deporte varchar2(20) not null,
matricula char(1),-- 'n' o 's'
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
);
3- Ingrese algunos registros:
insert into socios values(1,'23333333','Alberto Paredes','Colon 111');
insert into socios values(2,'24444444','Carlos Conte','Sarmiento 755');
insert into socios values(3,'25555555','Fabian Fuentes','Caseros 987');
insert into socios values(4,'26666666','Hector Lopez','Sucre 344');
insert into socios values(5,'27777777','Ines Irala','Colon 888');
insert into inscriptos values(1,'tenis','s');
insert into inscriptos values(1,'basquet','s');
insert into inscriptos values(1,'natacion','s');
insert into inscriptos values(2,'tenis','s');
insert into inscriptos values(2,'natacion','s');
insert into inscriptos values(2,'basquet','n');
insert into inscriptos values(2,'futbol','n');
insert into inscriptos values(3,'tenis','s');
insert into inscriptos values(3,'basquet','s');
insert into inscriptos values(3,'natacion','n');
insert into inscriptos values(4,'basquet','n');
4- Realice una combinación mostrando todos los datos de "socios", el deporte y la matrícula de
todos los socios (se encuentren o no en "inscriptos")
5- Actualizamos la cuota ('s') de todas las inscripciones de un socio determinado (por
documento) empleando subconsulta (3 registros)
6- Elimine todas las inscripciones de los socios que deben alguna matrícula empleando
subconsulta
Ver solución
79 - Subconsulta con update y delete
Primer problema:
Un supermercado almacena los datos de sus empleados en una tabla denominada "empleados" y
en una tabla llamada "sucursales" los códigos y ciudades de las diferentes sucursales.
1- Elimine las tablas "empleados" y "sucursales":
drop table empleados;
drop table sucursales;
2- Cree la tabla "sucursales":
create table sucursales(
codigo number(2),
ciudad varchar2(30) not null,
provincia varchar2(30),
primary key(codigo)
);
3- Cree la tabla "empleados":
create table empleados(
documento char(8) not null,
nombre varchar2(30) not null,
codigosucursal number(2),
sueldo number(6,2),
primary key(documento),
constraint FK_empleados_sucursal
foreign key (codigosucursal)
references sucursales(codigo)
);
4- Ingrese algunos registros para ambas tablas:
insert into sucursales values(1,'Cordoba','Cordoba');
insert into sucursales values(2,'Tucuman','Tucuman');
insert into sucursales values(3,'Carlos Paz','Cordoba');
insert into sucursales values(4,'Cruz del Eje','Cordoba');
insert into sucursales values(5,'La Plata','Buenos Aires');
insert into empleados values('22222222','Ana Acosta',1,500);
insert into empleados values('23333333','Carlos Caseros',1,610);
insert into empleados values('24444444','Diana Dominguez',2,600);
insert into empleados values('25555555','Fabiola Fuentes',5,700);
insert into empleados values('26666666','Gabriela Gonzalez',3,800);
insert into empleados values('27777777','Juan Juarez',4,850);
insert into empleados values('28888888','Luis Lopez',4,500);
insert into empleados values('29999999','Maria Morales',5,800);
5- Realice un join para mostrar el documento, nombre, sueldo, ciudad y provincia de todos los
empleados
6- El supermercado necesita incrementar en un 10% el sueldo de los empleados de la sucursal de
"Cruz del Eje". Actualice el campo "sueldo" de la tabla "empleados" de todos los empleados de
dicha sucursal empleando subconsulta.
7- El supermercado quiere incrementar en un 20% el sueldo de los empleados de las sucursales
de la provincia de Córdoba. Actualice el campo "sueldo" de la tabla "empleados" de todos los
empleados de tales sucursales empleando subconsulta.
8- La empleada "Ana Acosta" es trasladada a la sucursal de Carlos Paz. Se necesita actualizar el
sueldo y la sucursal de tal empleada empleando subconsultas, debe tener el mismo sueldo que la
empleada "Maria Morales".
9- El empleado "Carlos Caseros" se traslada a la sucursal de "La Plata". Se necesita actualizar el
sueldo y sucursal de tal empleado con los mismos valores que la empleada "Maria Morales"
(emplee subconsulta).
10- El supermercado cerrará todas las sucursales de la provincia de "Cordoba". Elimine los
empleados que pertenezcan a sucursales de tal provincia empleando subconsulta.
Ver solución
Segundo problema:
Un club dicta clases de distintos deportes a sus socios. El club tiene una tabla llamada
"inscriptos" en la cual almacena el número de "socio", el código del deporte en el cual se inscribe
y si la matricula está o no paga, y una tabla denominada "socios" en la que guarda los datos
personales de cada socio.
1- Elimine las tablas:
drop table inscriptos;
drop table socios;
2- Cree las tablas:
create table socios(
numero number(5),
documento char(8),
nombre varchar2(30),
domicilio varchar2(30),
primary key (numero)
);
create table inscriptos (
numerosocio number(5) not null,
deporte varchar2(20) not null,
matricula char(1),-- 'n' o 's'
primary key(numerosocio,deporte),
constraint FK_inscriptos_socio
foreign key (numerosocio)
references socios(numero)
);
3- Ingrese algunos registros:
insert into socios values(1,'23333333','Alberto Paredes','Colon 111');
insert into socios values(2,'24444444','Carlos Conte','Sarmiento 755');
insert into socios values(3,'25555555','Fabian Fuentes','Caseros 987');
insert into socios values(4,'26666666','Hector Lopez','Sucre 344');
insert into socios values(5,'27777777','Ines Irala','Colon 888');
insert into inscriptos values(1,'tenis','s');
insert into inscriptos values(1,'basquet','s');
insert into inscriptos values(1,'natacion','s');
insert into inscriptos values(2,'tenis','s');
insert into inscriptos values(2,'natacion','s');
insert into inscriptos values(2,'basquet','n');
insert into inscriptos values(2,'futbol','n');
insert into inscriptos values(3,'tenis','s');
insert into inscriptos values(3,'basquet','s');
insert into inscriptos values(3,'natacion','n');
insert into inscriptos values(4,'basquet','n');
4- Realice una combinación mostrando todos los datos de "socios", el deporte y la matrícula de
todos los socios (se encuentren o no en "inscriptos")
5- Actualizamos la cuota ('s') de todas las inscripciones de un socio determinado (por
documento) empleando subconsulta (3 registros)
6- Elimine todas las inscripciones de los socios que deben alguna matrícula empleando
subconsulta
Ver solución
80 - Subconsulta e insert
Primer problema:
Un comercio que vende artículos de librería y papelería almacena la información de sus ventas
en una tabla llamada "facturas" y otra "clientes".
1- Elimine las tablas:
drop table facturas;
drop table clientes;
2-Créelas:
create table clientes(
codigo number(5),
nombre varchar2(30),
domicilio varchar2(30),
primary key(codigo)
);
create table facturas(
numero number(6) not null,
fecha date,
codigocliente number(5) not null,
total number(6,2),
primary key(numero),
constraint FK_facturas_cliente
foreign key (codigocliente)
references clientes(codigo)
);
3-Ingrese algunos registros:
insert into clientes values(1,'Juan Lopez','Colon 123');
insert into clientes values(2,'Luis Torres','Sucre 987');
insert into clientes values(3,'Ana Garcia','Sarmiento 576');
insert into clientes values(4,'Susana Molina','San Martin 555');
insert into facturas values(1200,'15/04/2007',1,300);
insert into facturas values(1201,'15/04/2007',2,550);
insert into facturas values(1202,'15/04/2007',3,150);
insert into facturas values(1300,'20/04/2007',1,350);
insert into facturas values(1310,'22/04/2007',3,100);
4- El comercio necesita una tabla llamada "clientespref" en la cual quiere almacenar el nombre y
domicilio de aquellos clientes que han comprado hasta el momento más de 500 pesos en
mercaderías. Elimine la tabla y créela con esos 2 campos:
drop table clientespref;
create table clientespref(
nombre varchar2(30),
domicilio varchar2(30)
);
5- Ingrese los registros en la tabla "clientespref" seleccionando registros de la tabla "clientes" y
"facturas"
6- Vea los registros de "clientespref" (2 registros)
Ver solución
81 - Crear tabla a partir de otra (create table-
select)
Podemos crear una tabla e insertar datos en ella en una sola sentencia consultando otra tabla (o
varias) con esta sintaxis:
create table NOMBRENUEVATABLA
as SUBCONSULTA;
Es decir, se crea una nueva tabla y se inserta en ella el resultado de una consulta a otra tabla.
Tenemos la tabla "libros" de una librería y queremos crear una tabla llamada "editoriales" que
contenga los nombres de las editoriales.
La tabla "editoriales", que no existe, contendrá solamente un campo llamado "nombre". La tabla
libros contiene varios registros.
Podemos crear la tabla "editoriales" con el campo "nombre" consultando la tabla "libros" y en el
mismo momento insertar la información:
create table editoriales
as (select distinct editorial as nombre from libros);
La tabla "editoriales" se ha creado con el campo "nombre" seleccionado del campo "editorial" de
"libros".
Los campos de la nueva tabla tienen el mismo nombre, tipo de dato y valores almacenados que
los campos listados de la tabla consultada; si se quiere dar otro nombre a los campos de la nueva
tabla se deben especificar alias.
Podemos emplear "group by", funciones de agrupamiento y "order by" en las consultas. También
podemos crear una tabla que contenga datos de 2 o más tablas empleando combinaciones.
81 - Crear tabla a partir de otra (create
table- select)
Primer problema:
Un supermercado almacena los datos de sus empleados en una tabla denominada "empleados" y
en una tabla llamada "sucursales" los códigos y ciudades de las diferentes sucursales.
1- Elimine las tablas "empleados" y "sucursales":
drop table empleados;
drop table sucursales;
2- Cree la tabla "sucursales":
create table sucursales(
codigo number(4),
ciudad varchar2(30) not null,
primary key(codigo)
);
3- Cree la tabla "empleados":
create table empleados(
documento char(8) not null,
nombre varchar2(30) not null,
domicilio varchar2(30),
seccion varchar2(20),
sueldo number(6,2),
codigosucursal number(4),
primary key(documento),
constraint FK_empleados_sucursal
foreign key (codigosucursal)
references sucursales(codigo)
);
4- Ingrese algunos registros para ambas tablas:
insert into sucursales values(1,'Cordoba');
insert into sucursales values(2,'Villa Maria');
insert into sucursales values(3,'Carlos Paz');
insert into sucursales values(4,'Cruz del Eje');
insert into empleados values('22222222','Ana Acosta','Avellaneda
111','Secretaria',500,1);
insert into empleados values('23333333','Carlos Caseros','Colon
222','Sistemas',800,1);
insert into empleados values('24444444','Diana Dominguez','Dinamarca
333','Secretaria',550,2);
insert into empleados values('25555555','Fabiola Fuentes','Francia
444','Sistemas',750,2);
insert into empleados values('26666666','Gabriela Gonzalez','Guemes
555','Secretaria',580,3);
insert into empleados values('27777777','Juan Juarez','Jujuy
777','Secretaria',500,4);
insert into empleados values('28888888','Luis Lopez','Lules
888','Sistemas',780,4);
insert into empleados values('29999999','Maria Morales','Marina
999','Contaduria',670,4);
5- Realice un join para mostrar todos los datos de "empleados" incluyendo la ciudad de la
sucursal
6-Cree una tabla llamada "secciones" que contenga las secciones de la empresa (primero
elimínela)
drop table secciones;
create table secciones as
(select distinct seccion as nombre
from empleados);
7- Recupere la información de "secciones"
8- Se necesita una nueva tabla llamada "sueldosxseccion" que contenga la suma de los sueldos de
los empleados por sección (de todas las sucursales). Primero elimine la tabla
drop table sueldosxseccion;
create table sueldosxseccion as
(select seccion, sum(sueldo) as total
from empleados
group by seccion);
9- Recupere los registros de la nueva tabla
10- Se necesita una nueva tabla llamada "sucursalCordoba" que contenga los nombres y sección
de los empleados de la ciudad de Córdoba. En primer lugar, eliminamos la tabla. Luego, consulte
las tablas "empleados" y "sucursales" y guarde el resultado en la nueva tabla
11- Consulte la nueva tabla
Ver solución
82 - Vistas (create view)
Una vista es un objeto. Una vista es una alternativa para mostrar datos de varias tablas; es como
una tabla virtual que almacena una consulta. Los datos accesibles a través de la vista no están
almacenados en la base de datos, en la base de datos se guarda la definición de la vista y no el
resultado de ella.
Entonces, una vista almacena una consulta como un objeto para utilizarse posteriormente. Las
tablas consultadas en una vista se llaman tablas base. En general, se puede dar un nombre a
cualquier consulta y almacenarla como una vista.
Una vista suele llamarse también tabla virtual porque los resultados que retorna y la manera de
referenciarlas es la misma que para una tabla.
Las vistas permiten:
<="" p="">
- simplificar la administración de los permisos de usuario: se pueden dar al usuario permisos para
que solamente pueda acceder a los datos a través de vistas, en lugar de concederle permisos para
acceder a ciertos campos, así se protegen las tablas base de cambios en su estructura.
- mejorar el rendimiento: se puede evitar tipear instrucciones repetidamente almacenando en una
vista el resultado de una consulta compleja que incluya información de varias tablas.
Podemos crear vistas con: un subconjunto de registros y campos de una tabla; una unión de
varias tablas; una combinación de varias tablas; un subconjunto de otra vista, combinación de
vistas y tablas.
Una vista se define usando un "select".
La sintaxis básica para crear una vista es la siguiente:
create view NOMBREVISTA as
SUBCONSULTA;
El contenido de una vista se muestra con un "select":
select *from NOMBREVISTA;
En el siguiente ejemplo creamos la vista "vista_empleados", que es resultado de una
combinación en la cual se muestran 4 campos:
create view vista_empleados as
select (apellido||' '||[Link]) as nombre,sexo,
[Link] as seccion, cantidadhijos
from empleados e
join secciones s
on codigo=seccion;
Para ver la información contenida en la vista creada anteriormente tipeamos:
select *from vista_empleados;
Podemos realizar consultas a una vista como si se tratara de una tabla:
select seccion,count(*) as cantidad
from vista_empleados;
Los nombres para vistas deben seguir las mismas reglas que cualquier identificador. Para
distinguir una tabla de una vista podemos fijar una convención para darle nombres, por ejemplo,
colocar el sufijo “vista” y luego el nombre de las tablas consultadas en ellas.
Los campos y expresiones de la consulta que define una vista DEBEN tener un nombre. Se debe
colocar nombre de campo cuando es un campo calculado o si hay 2 campos con el mismo
nombre. Note que en el ejemplo, al concatenar los campos "apellido" y "nombre" colocamos un
alias; si no lo hubiésemos hecho aparecería un mensaje de error porque dicha expresión DEBE
tener un encabezado, Oracle no lo coloca por defecto.
Los nombres de los campos y expresiones de la consulta que define una vista DEBEN ser únicos
(no puede haber dos campos o encabezados con igual nombre). Note que en la vista definida en
el ejemplo, al campo "[Link]" le colocamos un alias porque ya había un encabezado (el alias
de la concatenación) llamado "nombre" y no pueden repetirse, si sucediera, aparecería un
mensaje de error.
Otra sintaxis es la siguiente:
create view NOMBREVISTA (NOMBRESDEENCABEZADOS)
as
SUBCONSULTA;
Creamos otra vista de "empleados" denominada "vista_empleados_ingreso" que almacena la
cantidad de empleados por año:
create view vista_empleados_ingreso (fecha,cantidad)
as
select extract(year from fechaingreso),count(*)
from empleados
group by extract(year from fechaingreso);
La diferencia es que se colocan entre paréntesis los encabezados de las columnas que aparecerán
en la vista. Si no los colocamos y empleamos la sintaxis vista anteriormente, se emplean los
nombres de los campos o alias (que en este caso habría que agregar) colocados en el "select" que
define la vista. Los nombres que se colocan entre paréntesis deben ser tantos como los campos o
expresiones que se definen en la vista.
Las vistas se crean en la base de datos activa.
Al crear una vista, Oracle verifica que existan las tablas a las que se hacen referencia en ella; no
se puede crear una vista que referencie tablas inexistentes. No se puede crear una vista si existe
un objeto con ese nombre.
Se aconseja probar la sentencia "select" con la cual definiremos la vista antes de crearla para
asegurarnos que el resultado que retorna es el imaginado.
Una vista siempre está actualizada; si modificamos las tablas base (a las cuales referencia la
vista), la vista mostrará los cambios.
Se pueden construir vistas sobre otras vistas.
82 - Vistas (create view)
Primer problema:
Un club dicta cursos de distintos deportes. Almacena la información en varias tablas. El director
no quiere que los empleados de administración conozcan la estructura de las tablas ni algunos
datos de los profesores y socios, por ello se crean vistas a las cuales tendrán acceso.
1- Elimine las tablas y créelas nuevamente:
drop table inscriptos;
drop table cursos;
drop table socios;
drop table profesores;
create table socios(
documento char(8) not null,
nombre varchar2(40),
domicilio varchar2(30),
primary key (documento)
);
create table profesores(
documento char(8) not null,
nombre varchar2(40),
domicilio varchar2(30),
primary key (documento)
);
create table cursos(
numero number(2),
deporte varchar2(20),
dia varchar2(15),
documentoprofesor char(8),
constraint CK_inscriptos_dia
check (dia in('lunes','martes','miercoles','jueves','viernes','sabado')),
constraint FK_documentoprofesor
foreign key (documentoprofesor)
references profesores(documento),
primary key (numero)
);
create table inscriptos(
documentosocio char(8) not null,
numero number(2) not null,
matricula char(1),
constraint CK_inscriptos_matricula check (matricula in('s','n')),
constraint FK_documentosocio
foreign key (documentosocio)
references socios(documento),
constraint FK_numerocurso
foreign key (numero)
references cursos(numero),
primary key (documentosocio,numero)
);
2- Ingrese algunos registros para todas las tablas:
insert into socios values('30000000','Fabian Fuentes','Caseros 987');
insert into socios values('31111111','Gaston Garcia','Guemes 65');
insert into socios values('32222222','Hector Huerta','Sucre 534');
insert into socios values('33333333','Ines Irala','Bulnes 345');
insert into profesores values('22222222','Ana Acosta','Avellaneda 231');
insert into profesores values('23333333','Carlos Caseres','Colon 245');
insert into profesores values('24444444','Daniel Duarte','Sarmiento 987');
insert into profesores values('25555555','Esteban Lopez','Sucre 1204');
insert into cursos values(1,'tenis','lunes','22222222');
insert into cursos values(2,'tenis','martes','22222222');
insert into cursos values(3,'natacion','miercoles','22222222');
insert into cursos values(4,'natacion','jueves','23333333');
insert into cursos values(5,'natacion','viernes','23333333');
insert into cursos values(6,'futbol','sabado','24444444');
insert into cursos values(7,'futbol','lunes','24444444');
insert into cursos values(8,'basquet','martes','24444444');
insert into inscriptos values('30000000',1,'s');
insert into inscriptos values('30000000',3,'n');
insert into inscriptos values('30000000',6,null);
insert into inscriptos values('31111111',1,'s');
insert into inscriptos values('31111111',4,'s');
insert into inscriptos values('32222222',8,'s');
3- Elimine la vista "vista_club":
drop view vista_club;
4- Cree una vista en la que aparezca el nombre del socio, el deporte, el día, el nombre del
profesor y el estado de la matrícula (deben incluirse los socios que no están inscriptos en ningún
deporte, los cursos para los cuales no hay inscriptos y los profesores que no tienen designado
deporte también)
5- Muestre la información contenida en la vista (11 registros)
6- Realice una consulta a la vista donde muestre la cantidad de socios inscriptos en cada deporte
(agrupe por deporte y día) ordenados por cantidad
7- Muestre (consultando la vista) los cursos (deporte y día) para los cuales no hay inscriptos (3
registros)
8- Muestre los nombres de los socios que no se han inscripto en ningún curso (consultando la
vista) (1 registro)
9- Muestre (consultando la vista) los profesores que no tienen asignado ningún deporte aún (1
registro)
10- Muestre (consultando la vista) el nombre de los socios que deben matrículas (1 registro)
11- Consulte la vista y muestre los nombres de los profesores y los días en que asisten al club
para dictar sus clases (9 registros)
12- Muestre la misma información anterior pero ordenada por día
13- Muestre todos los socios que son compañeros en tenis los lunes (2 registros)
14- Intente crear una vista denominada "vista_inscriptos" que muestre la cantidad de inscriptos
por curso, incluyendo el número del curso, el nombre del deporte y el día
15- Elimine la vista "vista_inscriptos" y créela para que muestre la cantidad de inscriptos por
curso, incluyendo el número del curso, el nombre del deporte y el día
16- Consulte la vista (9 registros)
Ver solución
83 - Vistas (información)
Las vistas son objetos, así que para obtener información de ellos pueden consultarse los
siguientes catálogos.
"user_catalog" nos muestra todos los objetos del usuario actual, incluidas las vistas. En la
columna "table_type" aparece "view" si es una vista. Ejemplo:
select *from user_catalog where table_type='VIEW';
"user_objects" nos muestra información sobre todos los objetos del usuario actual. En la columna
"OBJECT_TYPE" muestra "view" si es una vista, aparece la fecha de creación y demás
información que no analizaremos por el momento.
Para ver todos los objetos del usuario actual que son vistas tipeamos:
select *from user_catalog where object_type='VIEW';
"user_views" nos muestra información referente a todas las vistas del usuario actual, el nombre
de la vista, la longitud del texto, el texto que la define, etc.
Con la siguiente sentencia obtenemos información sobre todas las vistas cuyo nombre comience
con la cadena "VISTA":
select *from user_views where view_name like 'VISTA%';
84 - Vistas eliminar (drop view)
Para quitar una vista se emplea "drop view":
drop view NOMBREVISTA;
Eliminamos la vista denominada "vista_empleados":
drop view vista_empleados;
Si se elimina una tabla a la que hace referencia una vista, la vista no se elimina, hay que
eliminarla explícitamente.
85 - Vistas (modificar datos a través de ella)
Si se modifican los datos de una vista, se modifica la tabla base.
Se puede insertar, actualizar o eliminar datos de una tabla a través de una vista, teniendo en
cuenta lo siguiente, las modificaciones que se realizan a las vistas:
- no pueden afectar a más de una tabla consultada. Pueden modificarse y eliminarse datos de una
vista que combina varias tablas pero la modificación o eliminación solamente debe afectar a una
sola tabla.
- no se pueden cambiar los campos resultado de un cálculo.
- pueden generar errores si afectan a campos a las que la vista no hace referencia. Por ejemplo, si
se ingresa un registro en una vista que consulta una tabla que tiene campos not null que no están
incluidos en la vista.
85 - Vistas (modificar datos a través de ella)
Primer problema:
Un club dicta cursos de distintos deportes. Almacena la información en varias tablas.
1- Elimine las tabla "inscriptos", "socios" y "cursos":
drop table inscriptos;
drop table socios;
drop table cursos;
2- Cree las tablas:
create table socios(
documento char(8) not null,
nombre varchar2(40),
domicilio varchar2(30),
constraint PK_socios_documento
primary key (documento)
);
create table cursos(
numero number(2),
deporte varchar2(20),
dia varchar2(15),
constraint CK_inscriptos_dia check (dia
in('lunes','martes','miercoles','jueves','viernes','sabado')),
profesor varchar2(20),
constraint PK_cursos_numero
primary key (numero)
);
create table inscriptos(
documentosocio char(8) not null,
numero number(2) not null,
matricula char(1),
constraint PK_inscriptos_documento_numero
primary key (documentosocio,numero),
constraint FK_inscriptos_documento
foreign key (documentosocio)
references socios(documento),
constraint FK_inscriptos_numero
foreign key (numero)
references cursos(numero)
);
3- Ingrese algunos registros para todas las tablas:
insert into socios values('30000000','Fabian Fuentes','Caseros 987');
insert into socios values('31111111','Gaston Garcia','Guemes 65');
insert into socios values('32222222','Hector Huerta','Sucre 534');
insert into socios values('33333333','Ines Irala','Bulnes 345');
insert into cursos values(1,'tenis','lunes','Ana Acosta');
insert into cursos values(2,'tenis','martes','Ana Acosta');
insert into cursos values(3,'natacion','miercoles','Ana Acosta');
insert into cursos values(4,'natacion','jueves','Carlos Caseres');
insert into cursos values(5,'futbol','sabado','Pedro Perez');
insert into cursos values(6,'futbol','lunes','Pedro Perez');
insert into cursos values(7,'basquet','viernes','Pedro Perez');
insert into inscriptos values('30000000',1,'s');
insert into inscriptos values('30000000',3,'n');
insert into inscriptos values('30000000',6,null);
insert into inscriptos values('31111111',1,'s');
insert into inscriptos values('31111111',4,'s');
insert into inscriptos values('32222222',1,'s');
insert into inscriptos values('32222222',7,'s');
4- Realice un join para mostrar todos los datos de todas las tablas, sin repetirlos (7 registros)
5- Elimine la vista "vista_cursos"
6- Cree la vista "vista_cursos" que muestre el número, deporte y día de todos los cursos.
7- Consulte la vista ordenada por deporte (7 registros)
8- Ingrese un registro mediante la vista "vista_cursos" y vea si afectó a "cursos"
9- Actualice un registro sobre la vista y vea si afectó a la tabla "cursos"
10- Elimine un registro de la vista para el cual no haya inscriptos y vea si afectó a "cursos"
11- Intente eliminar un registro de la vista para el cual haya inscriptos
12- Elimine la vista "vista_inscriptos" y créela para que muestre el documento y nombre del
socio, el numero de curso, el deporte y día de los cursos en los cuales está inscripto
13- Intente ingresar un registro en la vista:
insert into vista_inscriptos values('32222222','Hector
Huerta',6,'futbol','lunes');
No lo permite porque la modificación afecta a más de una tabla base.
14- Intente actualizar el documento de un socio (no lo permite)
15- Elimine un registro mediante la vista
16- Verifique que el registro se ha eliminado de "inscriptos"
Ver solución
86 - Vistas (with read only)
Con la cláusula "with read only" (sólo lectura) evitamos que se puedan realizar inserciones,
actualizaciones y eliminaciones mediante una vista.
Sintaxis:
create view NOMBREVISTA
as SUBCONSULTA
with read only;
Evitamos que Oracle acepte "insert", "update" o "delete" sobre la vista si colocamos "with read
only" luego de la subconsulta que define una vista.
Por ejemplo, creamos la siguiente vista:
create view vista_empleados
as
select apellido, nombre, sexo, seccion
from empleados
with read only;
Oracle responde con un mensaje de error ante cualquier "insert", "update" o "delete" realizado
sobre la vista.
86 - Vistas (with read only)
Primer problema:
Una empresa almacena la información de sus clientes en una tabla llamada "clientes".
1- Elimine la tabla:
drop table clientes;
2- Cree la tabla:
create table clientes(
nombre varchar2(40),
documento char(8),
domicilio varchar2(30),
ciudad varchar2(30)
);
3- Ingrese algunos registros:
insert into clientes values('Juan Perez','22222222','Colon 1123','Cordoba');
insert into clientes values('Karina Lopez','23333333','San Martin
254','Cordoba');
insert into clientes values('Luis Garcia','24444444','Caseros
345','Cordoba');
insert into clientes values('Marcos Gonzalez','25555555','Sucre 458','Santa
Fe');
insert into clientes values('Nora Torres','26666666','Bulnes 567','Santa
Fe');
insert into clientes values('Oscar Luque','27777777','San Martin 786','Santa
Fe');
insert into clientes values('Pedro Perez','28888888','Colon 234','Buenos
Aires');
insert into clientes values('Rosa Rodriguez','29999999','Avellaneda
23','Buenos Aires');
4- Cree o reemplace la vista "vista_clientes" para que recupere el nombre y ciudad de todos los
clientes
5- Cree o reemplace la vista "vista_clientes2" para que recupere el nombre y ciudad de todos los
clientes no permita modificaciones.
6- Consulte ambas vistas
7- Intente ingresar el siguiente registro mediante la vista que permite sólo lectura
Oracle no lo permite.
8- Ingrese el registro anterior en la vista "vista_clientes"
9- Intente modificar un registro mediante la vista que permite sólo lectura
10- Actualice el registro anterior en la vista "vista_clientes"
11- Intente eliminar un registro mediante la vista "vista_clientes2"
12- Elimine todos los clientes de "Buenos Aires" a través de la vista "vista_clientes"
Ver solución
87 - Vistas modificar (create or replace view)
Para modificar una vista puede eliminarla y volver a crearla o emplear "create or replace".
Sintaxis:
create or replace view NOMBREVISTA
as SUBCONSULTA;
Con "create or replace view" se modifica la definición de una vista existente o se crea si no
existe.
87 - Vistas modificar (create or replace
view)
Primer problema:
Un club dicta cursos de distintos deportes. Almacena la información en varias tablas.
1- Elimine las tablas "inscriptos", "socios" y "cursos":
drop table inscriptos;
drop table socios;
drop table cursos;
2- Cree las tablas:
create table socios(
documento char(8) not null,
nombre varchar2(40),
domicilio varchar2(30),
constraint PK_socios_documento
primary key (documento)
);
create table cursos(
numero number(2),
deporte varchar2(20),
dia varchar2(15),
constraint CK_inscriptos_dia check (dia
in('lunes','martes','miercoles','jueves','viernes','sabado')),
profesor varchar2(20),
constraint PK_cursos_numero
primary key (numero)
);
create table inscriptos(
documentosocio char(8) not null,
numero number(2) not null,
matricula char(1),
constraint PK_inscriptos_documento_numero
primary key (documentosocio,numero),
constraint FK_inscriptos_documento
foreign key (documentosocio)
references socios(documento),
constraint FK_inscriptos_numero
foreign key (numero)
references cursos(numero)
);
3- Ingrese algunos registros para todas las tablas:
insert into socios values('30000000','Fabian Fuentes','Caseros 987');
insert into socios values('31111111','Gaston Garcia','Guemes 65');
insert into socios values('32222222','Hector Huerta','Sucre 534');
insert into socios values('33333333','Ines Irala','Bulnes 345');
insert into cursos values(1,'tenis','lunes','Ana Acosta');
insert into cursos values(2,'tenis','martes','Ana Acosta');
insert into cursos values(3,'natacion','miercoles','Ana Acosta');
insert into cursos values(4,'natacion','jueves','Carlos Caseres');
insert into cursos values(5,'futbol','sabado','Pedro Perez');
insert into cursos values(6,'futbol','lunes','Pedro Perez');
insert into cursos values(7,'basquet','viernes','Pedro Perez');
insert into inscriptos values('30000000',1,'s');
insert into inscriptos values('30000000',3,'s');
insert into inscriptos values('30000000',6,null);
insert into inscriptos values('31111111',1,'n');
insert into inscriptos values('31111111',4,'s');
insert into inscriptos values('32222222',1,'n');
insert into inscriptos values('32222222',7,'n');
4- Cree o reemplace la vista "vista_inscriptos" que muestre el documento y nombre del socio, el
deporte, el día y la matrícula, de todas las inscripciones no pagas
5- Consulte la vista
6- Veamos el texto de la vista
7- Modifique la vista para que muestre el domicilio
8- Consulte la vista para ver si se modificó
9- Vea el texto de la vista
Ver solución
87 - Vistas modificar (create or replace view)
Primer problema:
Un club dicta cursos de distintos deportes. Almacena la información en varias tablas.
1- Elimine las tablas "inscriptos", "socios" y "cursos":
drop table inscriptos;
drop table socios;
drop table cursos;
2- Cree las tablas:
create table socios(
documento char(8) not null,
nombre varchar2(40),
domicilio varchar2(30),
constraint PK_socios_documento
primary key (documento)
);
create table cursos(
numero number(2),
deporte varchar2(20),
dia varchar2(15),
constraint CK_inscriptos_dia check (dia
in('lunes','martes','miercoles','jueves','viernes','sabado')),
profesor varchar2(20),
constraint PK_cursos_numero
primary key (numero)
);
create table inscriptos(
documentosocio char(8) not null,
numero number(2) not null,
matricula char(1),
constraint PK_inscriptos_documento_numero
primary key (documentosocio,numero),
constraint FK_inscriptos_documento
foreign key (documentosocio)
references socios(documento),
constraint FK_inscriptos_numero
foreign key (numero)
references cursos(numero)
);
3- Ingrese algunos registros para todas las tablas:
insert into socios values('30000000','Fabian Fuentes','Caseros 987');
insert into socios values('31111111','Gaston Garcia','Guemes 65');
insert into socios values('32222222','Hector Huerta','Sucre 534');
insert into socios values('33333333','Ines Irala','Bulnes 345');
insert into cursos values(1,'tenis','lunes','Ana Acosta');
insert into cursos values(2,'tenis','martes','Ana Acosta');
insert into cursos values(3,'natacion','miercoles','Ana Acosta');
insert into cursos values(4,'natacion','jueves','Carlos Caseres');
insert into cursos values(5,'futbol','sabado','Pedro Perez');
insert into cursos values(6,'futbol','lunes','Pedro Perez');
insert into cursos values(7,'basquet','viernes','Pedro Perez');
insert into inscriptos values('30000000',1,'s');
insert into inscriptos values('30000000',3,'s');
insert into inscriptos values('30000000',6,null);
insert into inscriptos values('31111111',1,'n');
insert into inscriptos values('31111111',4,'s');
insert into inscriptos values('32222222',1,'n');
insert into inscriptos values('32222222',7,'n');
4- Cree o reemplace la vista "vista_inscriptos" que muestre el documento y nombre del socio, el
deporte, el día y la matrícula, de todas las inscripciones no pagas
5- Consulte la vista
6- Veamos el texto de la vista
7- Modifique la vista para que muestre el domicilio
8- Consulte la vista para ver si se modificó
9- Vea el texto de la vista
Ver solución
88 - Vistas (with check option)
Primer problema:
Una empresa almacena la información de sus clientes en una tabla llamada "clientes".
1- Elimine la tabla:
drop table clientes;
2- Cree la tabla:
create table clientes(
nombre varchar2(40),
documento char(8),
domicilio varchar2(30),
ciudad varchar2(30)
);
3- Ingrese algunos registros:
insert into clientes values('Juan Perez','22222222','Colon 1123','Cordoba');
insert into clientes values('Karina Lopez','23333333','San Martin
254','Cordoba');
insert into clientes values('Luis Garcia','24444444','Caseros
345','Cordoba');
insert into clientes values('Marcos Gonzalez','25555555','Sucre 458','Santa
Fe');
insert into clientes values('Nora Torres','26666666','Bulnes 567','Santa
Fe');
insert into clientes values('Oscar Luque','27777777','San Martin 786','Santa
Fe');
insert into clientes values('Pedro Perez','28888888','Colon 234','Buenos
Aires');
insert into clientes values('Rosa Rodriguez','29999999','Avellaneda
23','Buenos Aires');
4- Cree o reemplace la vista "vista_clientes" para que recupere el nombre y ciudad de todos los
clientes que no sean de "Cordoba" sin emplear "with check option"
5- Cree o reemplace la vista "vista_clientes2" para que recupere el nombre y ciudad de todos los
clientes que no sean de "Cordoba" empleando "with check option"
6- Consulte ambas vistas
7- Intente modificar la ciudad del cliente "Pedro Perez" a "Cordoba" través de la vista que está
restringida.
8- Realice la misma modificación que intentó en el punto anterior a través de la vista que no está
restringida
9- Actualice la ciudad del cliente "Oscar Luque" a "Buenos Aires" mediante la vista restringida
10- Verifique que "Oscar Luque" aún se incluye en la vista
11- Intente ingresar un empleado de "Cordoba" en la vista restringida
12- Ingrese el empleado anterior a través de la vista no restringida
13- Ingrese un empleado de "Salta" en la vista restringida
14- Verifique que el nuevo registro está incluido en la vista
Ver solución
89 - Vistas (otras consideraciones)
Cuando creamos una vista, Oracle verifica que las tablas a las cuales se hace referencia en ella
existan. Si la vista que se intenta crear hace referencia a tablas inexistentes, Oracle muestra un
mensaje de error.
Podemos "forzar" a Oracle a crear una vista aunque no existan los objetos (tablas, vistas, etc.)
que referenciamos en la misma. Para ello debemos agregar "force" al crearla:
create force view NOMBREVISTA
as SUBCONSULTA;
De esta manera, podemos crear una vista y después las tablas involucradas; luego, al consultar la
vista, DEBEN existir las tablas.
Al crear la vista la opción predeterminada es "no force". Se recomienda crear las tablas y luego
las vistas necesarias.
Otra cuestión a considerar es la siguiente: si crea una vista con "select *" y luego agrega campos
a la estructura de las tablas involucradas, los nuevos campos no aparecerán en la vista; esto es
porque los campos se seleccionan al ejecutar "create view"; debe volver a crear la vista (con
"create view" o "create or replace view").
89 - Vistas (otras consideraciones)
Primer problema:
Una empresa almacena la información de sus clientes en una tabla llamada "clientes".
1- Elimine la tabla:
drop table clientes;
2- Elimine la vista "vista_clientes":
drop view vista_clientes;
3- Intente crear o reemplazar la vista "vista_clientes" para que muestre el nombre, domicilio y
ciudad de todos los clientes de "Cordoba" (sin emplear "force")
Mensaje de error porque la tabla referenciada no existe.
4- Cree o reemplace la vista "vista_clientes" para que recupere el nombre, apellido y ciudad de
todos los clientes de "Cordoba" empleando "force"
5- Cree la tabla:
create table clientes(
nombre varchar2(40),
documento char(8),
domicilio varchar2(30),
ciudad varchar2(30)
);
6- Ingrese algunos registros:
insert into clientes values('Juan Perez','22222222','Colon 1123','Cordoba');
insert into clientes values('Karina Lopez','23333333','San Martin
254','Cordoba');
insert into clientes values('Luis Garcia','24444444','Caseros
345','Cordoba');
insert into clientes values('Marcos Gonzalez','25555555','Sucre 458','Santa
Fe');
insert into clientes values('Nora Torres','26666666','Bulnes 567','Santa
Fe');
insert into clientes values('Oscar Luque','27777777','San Martin 786','Santa
Fe');
insert into clientes values('Pedro Perez','28888888','Colon 234','Buenos
Aires');
insert into clientes values('Rosa Rodriguez','29999999','Avellaneda
23','Buenos Aires');
7- Cree o reemplace la vista "vista_clientes" para que muestre todos los campos de la tabla
"clientes"
8- Consulte la vista
9- Agregue un campo a la tabla "clientes"
10- Consulte la vista "vista_clientes"
El nuevo campo agregado a "clientes" no aparece, pese a que la vista indica que muestre todos
los campos de dicha tabla.
11- Modifique la vista para que aparezcan todos los campos
12- Consulte la vista:
Ahora si aparece el campo.
Ver solución
90 - Vistas materializadas (materialized view)
Una vista materializada se define como una vista común, pero en lugar de almacenar la
definición de la vista, almacena el resultado de la consulta, es decir, la materializa, como un
objeto persistente en la base de datos.
Sintaxis:
create materialized view NOMBREVISTAMATERIALIZADA
as SUBCONSULTA;
Existen varias cláusulas que podemos agregar al crear una vista materializada, pero no las
estudiaremos.
En el "from" de la consulta pueden listarse tablas, vistas y vistas materializadas.
Entonces, una vista materializada almacena su resultado físicamente. Una vista materializada
(materialized view) es una instantánea (snapshot), son sinónimos.
Para obtener información acerca de las vistas materializadas podemos consultar el diccionario
"user_objects", en la columna "object_type" aparecerá "materialized view" si es una vista
materializada. Ejemplo:
select *from user_objects where object_type='MATERIALIZED VIEW';
También podemos consultar "user_mviews" para obtener información de todas las vistas
materializadas del usuario actual:
select *from user_mviews;
Este diccionario muestra mucha información que no explicaremos en detalle.
Para eliminar una vista materializada empleamos "drop materialized view":
drop materialized view NOMBREVISTAMATERIALIZADA;
Ejemplo:
drop materialized view vm_promedios;
No se permite realizar "insert", "update" ni "delete" en las vistas materializadas.
91 - Procedimientos almacenados
Un procedimiento almacenado es un conjunto de instrucciones a las que se les da un nombre, se
almacena en la base de datos activa. Permiten agrupar y organizar tareas repetitivas.
Ventajas:
- comparten la lógica de la aplicación con las otras aplicaciones, con lo cual el acceso y las
modificaciones de los datos se hacen en un solo sitio.
- permiten realizar todas las operaciones que los usuarios necesitan evitando que tengan acceso
directo a las tablas.
- reducen el tráfico de red; en vez de enviar muchas instrucciones, los usuarios realizan
operaciones enviando una única instrucción, lo cual disminuye el número de solicitudes entre el
cliente y el servidor.
Un procedimiento almacenados puede hacer referencia a objetos que no existen al momento de
crearlo. Los objetos deben existir cuando se ejecute el procedimiento almacenado.
92 - Procedimientos Almacenados (crear-
ejecutar)
Al crear un procedimiento almacenado, las instrucciones que contiene se analizan para verificar
si son correctas sintácticamente. Si se encuentra algún error, el procedimiento se compila, pero
aparece un mensaje "con advertencias" que indica tal situación.
Un procedimiento almacenado se invoca llamándolo.
En primer lugar se deben tipear y probar las instrucciones que se incluyen en el procedimiento
almacenado, luego, si se obtiene el resultado esperado, se crea el procedimiento.
Los procedimientos almacenados pueden hacer referencia a tablas, vistas, a funciones definidas
por el usuario, a otros procedimientos almacenados.
Un procedimiento almacenado pueden incluir cualquier cantidad y tipo de instrucciones DML
(de manipulación de datos, como insert, update, delete), no instrucciones DDL (de definición de
datos, como create..., drop... alter...).
Para crear un procedimiento almacenado empleamos la instrucción "create procedure". La
sintaxis básica parcial es:
create or replace procedure NOMBREPROCEDIMIENTO
as
begin
INSTRUCCIONES
end;
El bloque de instrucciones comienza luego de "begin" y acaba con "end".
Si empleamos "or replace", se sobreescribe (se reemplaza) un procedimiento existente; si se
omite y existe un procedimiento con el nombre que le asignamos, Oracle mostrará un mensaje de
error indicando tal situación.
Para diferenciar los procedimientos almacenados del sistema de los procedimientos almacenados
creados por el usuario use un prefijo, por ejemplo "pa_" cuando les de el nombre.
Con las siguientes instrucciones creamos un procedimiento almacenado llamado
"pa_libros_aumentar10" que incrementa en un 10% el precio de todos los libros:
create procedure pa_libros_aumentar10
as
update libros set precio=precio+precio*0.1;
Entonces, creamos un procedimiento almacenado colocando "create procedure" (o "create or
replace", si es que desea reemplazar el existente), luego el nombre del procedimiento y seguido
de "as" las sentencias que definen el procedimiento.
Para ejecutar el procedimiento almacenado creado anteriormente tipeamos:
execute pa_libros_aumentar10;
Entonces, para ejecutar un procedimiento almacenado colocamos "execute" seguido del nombre
del procedimiento.
92 - Procedimientos Almacenados (crear-
ejecutar)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla llamada "empleados".
1- Eliminamos la tabla y la creamos:
drop table empleados;
create table empleados(
documento char(8),
nombre varchar2(20),
apellido varchar2(20),
sueldo number(6,2),
cantidadhijos number(2,0),
fechaingreso date,
primary key(documento)
);
2- Ingrese algunos registros:
insert into empleados values('22222222','Juan','Perez',200,2,'10/10/1980');
insert into empleados values('22333333','Luis','Lopez',250,0,'01/02/1990');
insert into empleados values('22444444','Marta','Perez',350,1,'02/05/1995');
insert into empleados
values('22555555','Susana','Garcia',400,2,'15/12/2000');
insert into empleados values('22666666','Jose
Maria','Morales',500,3,'25/08/2005');
3- Cree (o reemplace) el procedimiento almacenado llamado "pa_aumentarsueldo" que aumente
los sueldos inferiores al promedio en un 20%
4- Ejecute el procedimiento creado anteriormente
5- Verifique que los sueldos han aumentado
6- Ejecute el procedimiento nuevamente
7- Verifique que los sueldos han aumentado
8- Elimine la tabla "empleados_antiguos"
9- Cree la tabla "empleados_antiguos"
create table empleados_antiguos(
documento char(8),
nombre varchar2(40)
);
10- Cree (o reemplace) un procedimiento almacenado que ingrese en la tabla
"empleados_antiguos" el documento, nombre y apellido (concatenados) de todos los empleados
de la tabla "empleados" que ingresaron a la empresa hace más de 10 años
11- Ejecute el procedimiento creado anteriormente
12- Verifique que la tabla "empleados_antiguos" ahora tiene registros (3 registros)
Ver solución
93 - Procedimientos Almacenados (eliminar)
Los procedimientos almacenados se eliminan con "drop procedure". Sintaxis:
drop procedure NOMBREPROCEDIMIENTO;
Eliminamos el procedimiento almacenado llamado "pa_libros_aumentar10":
drop procedure pa_libros_aumentar10;
Si el procedimiento que queremos eliminar no existe, aparece un mensaje de error indicando tal
situación.
Podemos eliminar una tabla referenciada en un procedimiento almacenado, Oracle lo permite,
pero luego, al ejecutar el procedimiento, aparecerá un mensaje de error porque la tabla
referenciada no existe.
Si al crear un procedimiento almacenado colocamos "create or replace procedure...", el nuevo
procedimiento reemplaza al anterior.
94 - Procedimientos almacenados
(parámetros de entrada)
Los procedimientos almacenados pueden recibir y devolver información; para ello se emplean
parámetros.
Veamos los primeros. Los parámetros de entrada posibilitan pasar información a un
procedimiento. Para que un procedimiento almacenado admita parámetros de entrada se deben
declarar al crearlo. La sintaxis es:
create or replace procedure NOMBREPROCEDIMIENTO (PARAMETRO in TIPODEDATO)
as
begin
INSTRUCCIONES;
end;
Los parámetros se definen luego del nombre del procedimiento. Pueden declararse varios
parámetros por procedimiento, se separan por comas.
Cuando el procedimiento es ejecutado, deben explicitarse valores para cada uno de los
parámetros (en el orden que fueron definidos), a menos que se haya definido un valor por
defecto, en tal caso, pueden omitirse.
Creamos un procedimiento que recibe el nombre de una editorial como parámetro y luego lo
utiliza para aumentar los precios de tal editorial:
create or replace procedure pa_libros_aumentar10(aeditorial in varchar2)
as
begin
update libros set precio=precio+(precio*0.1)
where editorial=aeditorial;
end;
El procedimiento se ejecuta colocando "execute" (o "exec") seguido del nombre del
procedimiento y un valor para el parámetro:
execute pa_libros_aumentar10('Planeta');
Luego de definir un parámetro y su tipo, opcionalmente, se puede especificar un valor por
defecto; tal valor es el que asume el procedimiento al ser ejecutado si no recibe parámetros. Si no
se coloca valor por defecto, un procedimiento definido con parámetros no puede ejecutarse sin
valores para ellos. El valor por defecto puede ser "null" o una constante.
Creamos otro procedimiento que recibe 2 parámetros, el nombre de una editorial y el valor de
incremento (que tiene por defecto el valor 10):
create or replace procedure pa_libros_aumentar(aeditorial in
varchar2,aporcentaje in number default 10)
as
begin
update libros set precio=precio+(precio*aporcentaje/100)
where editorial=aeditorial;
end;
El procedimiento se ejecuta colocando "execute" (o "exec") seguido del nombre del
procedimiento y los valores para los parámetros separados por comas:
execute pa_libros_aumentar('Planeta',30);
Podemos omitir el segundo parámetro al invocar el procedimiento porque tiene establecido un
valor por defecto:
execute pa_libros_aumentar('Planeta');
En caso que un procedimiento tenga definidos varios parámetros con valores por defecto y al
invocarlo colocamos uno solo, Oracle asume que es el primero de ellos. si son de tipos de datos
diferentes, Oracle los convierte. Por ejemplo, definimos un procedimiento almacenado de la
siguiente manera:
create or replace procedure pa_libros_insertar
(atitulo in varchar2 default null, aautor in varchar2 default 'desconocido',
aeditorial in varchar2 default 'sin especificar', aprecio in number default
0)
as
begin
insert into libros values (atitulo,aautor,aeditorial,aprecio);
end;
Si luego llamamos al procedimiento enviándoles solamente el primer y cuarto parámetro
correspondientes al título y precio:
execute pa_libros_insertar('Uno',100);
Oracle asume que los argumentos son el primero y segundo, el registro que se almacenará será:
Uno,100,sin especificar,0;
94 - Procedimientos almacenados
(parámetros de entrada)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla llamada "empleados".
1- Eliminamos la tabla y la creamos:
drop table empleados;
create table empleados(
documento char(8),
nombre varchar2(20),
apellido varchar2(20),
sueldo number(6,2),
fechaingreso date
);
2- Ingrese algunos registros:
insert into empleados values('22222222','Juan','Perez',300,'10/10/1980');
insert into empleados values('22333333','Luis','Lopez',300,'12/05/1998');
insert into empleados values('22444444','Marta','Perez',500,'25/08/1990');
insert into empleados values('22555555','Susana','Garcia',400,'05/05/2000');
insert into empleados values('22666666','Jose
Maria','Morales',400,'24/10/2005');
3- Cree un procedimiento almacenado llamado "pa_empleados_aumentarsueldo". Debe
incrementar el sueldo de los empleados con cierta cantidad de años en la empresa (parámetro
"ayear" de tipo numérico) en un porcentaje (parámetro "aporcentaje" de tipo numerico); es decir,
recibe 2 parámetros.
4- Ejecute el procedimiento creado anteriormente.
5- Verifique que los sueldos de los empleados con más de 10 años en la empresa han aumentado
un 20%
6- Ejecute el procedimiento creado anteriormente enviando otros valores como parámetros (por
ejemplo, 8 y 10)
7- Verifique que los sueldos de los empleados con más de 8 años en la empresa han aumentado
un 10%
8- Ejecute el procedimiento almacenado "pa_empleados_aumentarsueldo" sin parámetros
9- Cree un procedimiento almacenado llamado "pa_empleados_ingresar" que ingrese un
empleado en la tabla "empleados", debe recibir valor para el documento, el nombre, apellido y
almacenar valores nulos en los campos "sueldo" y "fechaingreso"
10- Ejecute el procedimiento creado anteriormente y verifique si se ha ingresado en "empleados"
un nuevo registro
11- Reemplace el procedimiento almacenado llamado "pa_empleados_ingresar" para que ingrese
un empleado en la tabla "empleados", debe recibir valor para el documento (con valor por
defecto nulo) y fechaingreso (con la fecha actual como valor por defecto), los demás campos se
llenan con valor nulo
12- Ejecute el procedimiento creado anteriormente enviándole valores para los 2 parámetros y
verifique si se ha ingresado en "empleados" un nuevo registro
13- Ejecute el procedimiento creado anteriormente enviando solamente la fecha de ingreso y vea
el resultado
Oracle toma el valor enviado como primer argumento e intenta ingresarlo en el campo
"documento", muestra un mensaje de error indicando que el valor es muy grande, ya que tal
campo admite 8 caracteres.
14- Cree (o reemplace) un procedimiento almacenado que reciba un documento y elimine de la
tabla "empleados" el empleado que coincida con dicho documento
15- Elimine un empleado empleando el procedimiento del punto anterior
16- Verifique la eliminación
Ver solución
95 - Procedimientos almacenados (variables)
Los procedimientos almacenados pueden contener en su definición, variables locales, que existen
durante el procedimiento.
La sintaxis para declarar variables dentro de un procedimiento almacenado es la siguiente:
create or replace procedure NOMBREPROCEDIMIENTO (PARAMETRO in TIPODEDATO)
as
NOMBREVARIABLE TIPO;
begin
INSTRUCCIONES;
end;
Las variables se definen antes del bloque de sentencias; pueden declararse varias.
Creamos un procedimiento que recibe el nombre de un libro, en una variable guardamos el
nombre del autor de tal libro, luego buscamos todos los libros de ese autor y los almacenamos en
una tabla:
create or replace procedure pa_autorlibro(atitulo in varchar2)
as
vautor varchar2;
begin
vautor= select autor from libros where titulo=atitulo;
drop table tabla1;
create table tabla1(
titulo varchar2(40),
precio number(6,2)
);
insert into tabla1
select titulo,precio
from libros
where autor=vautor;
end;
Ejecutamos el procedimiento: execute pa_autorlibro('Ilusiones');
Luego de definir un parámetro y su tipo, opcionalmente, se puede especificar un valor por
defecto; tal valor es el que asume el procedimiento al ser ejecutado si no recibe parámetros. Si no
se coloca valor por defecto, un procedimiento definido con parámetros no puede ejecutarse sin
valores para ellos.
95 - Procedimientos almacenados
(variables)
Los procedimientos almacenados pueden contener en su definición, variables locales, que existen
durante el procedimiento.
La sintaxis para declarar variables dentro de un procedimiento almacenado es la siguiente:
create or replace procedure NOMBREPROCEDIMIENTO (PARAMETRO in TIPODEDATO)
as
NOMBREVARIABLE TIPO;
begin
INSTRUCCIONES;
end;
Las variables se definen antes del bloque de sentencias; pueden declararse varias.
Creamos un procedimiento que recibe el nombre de un libro, en una variable guardamos el
nombre del autor de tal libro, luego buscamos todos los libros de ese autor y los almacenamos en
una tabla:
create or replace procedure pa_autorlibro(atitulo in varchar2)
as
vautor varchar2;
begin
vautor= select autor from libros where titulo=atitulo;
drop table tabla1;
create table tabla1(
titulo varchar2(40),
precio number(6,2)
);
insert into tabla1
select titulo,precio
from libros
where autor=vautor;
end;
Ejecutamos el procedimiento: execute pa_autorlibro('Ilusiones');
Luego de definir un parámetro y su tipo, opcionalmente, se puede especificar un valor por
defecto; tal valor es el que asume el procedimiento al ser ejecutado si no recibe parámetros. Si no
se coloca valor por defecto, un procedimiento definido con parámetros no puede ejecutarse sin
valores para ellos.
97 - Funciones
Oracle ofrece varios tipos de funciones para realizar distintas operaciones. Hemos empleado
varias de ellas.
Se pueden emplear las funciones del sistema en cualquier lugar en el que se permita una
expresión en una sentencia "select".
Ahora aprenderemos a crear nuestras propias funciones.
Las funciones, como los procedimientos almacenados son bloques de código que permiten
agrupar y organizar sentencias SQL que se ejecutan al invocar la función.
Las funciones tienen una estructura similar a la de los procedimientos. Como los procedimientos,
las funciones tienen una cabecera, una sección de declaración de variables y el bloque
"begin...end" que encierra las acciones. Una función, además contiene la cláusula "return".
Una función acepta parámetros, se invoca con su nombre y retorna un valor.
Para crear una función empleamos la instrucción "create function" o "create or replace function".
Si empleamos "or replace", se sobreescribe (se reemplaza) una función existente; si se omite y
existe una función con el nombre que le asignamos, Oracle mostrará un mensaje de error
indicando tal situación.
La sintaxis básica parcial es:
create o replace function NOMBREFUNCION(PARAMETRO1 TIPODATO, PARAMETRON
TIPODATO)
return TIPODEDATO is
DECLARACION DE VARIABLES
begin
ACCIONES;
return VALOR;
end;
La siguiente funcion recibe 1 parámetro, un valor a incrementar y retorna el valor ingresado
como argumento con el incremento del 10%:
create or replace function f_incremento10 (avalor number)
return number
is
begin
return avalor+(avalor*0.1);
end;
Podemos emplear las funciones en cualquier lugar en el que se permita una expresión en una
sentencia "select", por ejemplo:
select titulo,precio,f_incremento10(precio) from libros;
El resultado mostrará el título de cada libro, el precio y el precio incrementado en un 10%
devuelto por la función.
La siguiente funcion recibe 2 parámetros, un valor a incrementar y el incremento y retorna el
valor ingresado como primer argumento con el incremento especificado por el segundo
argumento:
create or replace function f_incremento (avalor number, aincremento number)
return number
is
begin
return avalor+(avalor*aincremento/100);
end;
Realizamos un "select" y llamamos a la función creada anteriormente, enviando como primer
argumento el campo "precio" y como segundo argumento el valor "20", es decir, incrementará en
un 20" los precios de los libros:
select titulo,precio,f_incremento(precio,20) from libros;
El resultado nos mostrará el título de cada libro, el precio y el precio incrementado en un 20%
devuelto por la función.
Podemos realizar otros "select" llamando a la función con otro valor como segundo argumento,
por ejemplo:
select titulo,precio,f_incremento(precio,50) from libros;
La siguiente función recibe un parámetro de tipo numérico y retorna una cadena de caracteres. Se
define una variable en la zona de definición de variables denominada "valorretornado" de tipo
varchar. En el cuerpo de la función empleamos una estructura condicional (if) para averiguar si
el valor enviado como argumento es menor o igual a 20, si lo es, almacenamos en la variable
"valorretornado" la cadena "economico", en caso contrario guardamos en tal variable la cadena
"costoso"; al finalizar la estructura condicional retornamos la variable "valorretornado":
create or replace function f_costoso (avalor number)
return varchar
is
valorretornado varchar(20);
begin
valorretornado:='';
if avalor<=20 then
valorretornado:='economico';
else valorretornado:='costoso';
end if;
return valorretornado;
end;
Realizamos un "select" y llamamos a la función creada anteriormente, enviando como argumento
el campo "precio":
select titulo,precio,f_costoso(precio) from libros;
El resultado mostrará el título de cada libro, el precio y el resultado devuelto por la función (si el
precio es menor o mayor a $20, la cadena "economico" o "costoso" respectivamente).
Entonces, una función es un bloque de código que implementa acciones y que es referenciado
por un nombre. Puede recibir argumentos. La diferencia con los procedimientos es que retornan
un valor siempre.
Para asignar un valor a una variable, dentro de una función DEBE usarse ":=" (dos puntos e
igual).
Si no se le definen parámetros a una función, no deben colocarse los paréntesis.
Podemos emplear una función sin incluir campos de una tabla. Por ejemplo:
select f_costoso (10) from dual;
Para almacenar los valores de un "select" debemos tipear:
select ...into VARIABLE from...
Por ejemplo:
select sum(precio) into variable from libros where autor='';
La siguiente función recibe dos valores numéricos como parámetros y retorna el promedio:
create or replace function f_promedio (avalor1 number, avalor2 number)
return number
is
begin
return (avalor1+avalor2)/2;
end;
Llamamos a la función "f_promedio":
exec f_promedio (10,20);
98 - Control de flujo (if)
Las estructuras de control pueden ser condicionales y repetitivas.
Estructuras de control de flujo, bifurcaciones condicionales y bucles. Veremos las condicionales.
existen 2: if y case.
Existen palabras especiales que pertenecen al lenguaje de control de flujo que controlan la
ejecución de las sentencias, los bloques de sentencias y procedimientos almacenados. Tales
palabras son: "begin... end", "if... else", "while", "break" y "continue", "return" y "waitfor".
"if... else" testea una condición; se emplea cuando un bloque de sentencias debe ser ejecutado si
una condición se cumple y si no se cumple, se debe ejecutar otro bloque de sentencias diferente.
Sintaxis:
if (CONDICION) then
SENTENCIAS-- si la condición se cumple
else
SENTENCIAS-- si la condición resulta falsa
end if;
98 - Control de flujo (if)
Primer problema:
Un negocio almacena los datos de sus productos en una tabla denominada "productos". Dicha
tabla contiene el código de producto, el precio, el stock mínimo que se necesita (cantidad mínima
requerida antes de comprar más) y el stock actual (cantidad disponible en depósito). Si el stock
actual es cero, es urgente reponer tal producto; menor al stock mínimo requerido, es necesario
reponer tal producto; si el stock actual es igual o supera el stock minimo, está en estado normal.
1- Elimine la tabla "productos":
drop table productos;
2- Cree la tabla con la siguiente estructura:
create table productos(
codigo number(5),
precio number(6,2),
stockminimo number(4),
stockactual number(4)
);
3- Ingrese algunos registros:
insert into productos values(100,10,100,200);
insert into productos values(102,15,200,500);
insert into productos values(130,8,100,0);
insert into productos values(240,23,100,20);
insert into productos values(356,12,100,250);
insert into productos values(360,7,100,100);
insert into productos values(400,18,150,100);
4- Cree una función que reciba dos valores numéricos correspondientes a ambos stosks. Debe
comparar ambos stocks y retornar una cadena de caracteres indicando el estado de cada
producto, si stock actual es:
- cero: "faltante",
- menor al stock mínimo: "reponer",
- igual o superior al stock mínimo: "normal".
5- Realice un "select" mostrando el código del producto, ambos stocks y, empleando la función
creada anteriormente, una columna que muestre el estado del producto
6- Realice la misma función que en el punto 4, pero esta vez empleando en la estructura
condicional la sintaxis "if... elsif...end if"
7- Realice un "select" mostrando el código del producto, ambos stocks y, empleando la función
creada anteriormente, una columna que muestre el estado del producto
8- Realice una función similar a las anteriores, pero esta vez, si el estado es "reponer" o
"faltante", debe especificar la cantidad necesaria (valor necesario para llegar al stock mínimo)
7- Realice un "select" mostrando el código del producto, ambos stocks y, empleando la función
creada anteriormente, una columna que muestre el estado del producto
Ver solución
Segundo problema:
Una clínica almacena la información de sus pacientes en una tabla denominada "pacientes".
1- Elimine la tabla y créela con la siguiente estructura:
drop table pacientes;
create table pacientes(
documento char(8),
nombre varchar2(30),
edad number(2),
sexo char(1)
);
2- Ingrese los siguientes registros:
insert into pacientes values('11111111','Acosta Ana',40,'f');
insert into pacientes values('22222222','Bustos Betina',35,'f');
insert into pacientes values('33333333','Caseres Carlos',18,'m');
insert into pacientes values('44444444','Dominguez Diego',6,'m');
insert into pacientes values('15555555','Fuentes Fabiana',55,'f');
insert into pacientes values('26666666','Gomez Gaston',38,'m');
insert into pacientes values('37777777','Irala Ines',16,'f');
insert into pacientes values('38888888','Juarez Julieta',17,'f');
insert into pacientes values('40000000','Lopez Lucas',3,'m');
3- Realice una función que reciba la edad del paciente y retorne la cadena "menor" o "mayor"
según sea menor a 18 años o no
4- Realice una función que reciba el caracter correspondiente al sexo del paciente y retorne la
cadena "femenino" o "masculino"
5- Realice un "select" mostrando el nombre del paciente y empleando las funciones de los puntos
3 y 4, dos columnas que indiquen si es mayor o menor de edad y el sexo.
Ver solución
99 - Control de flujo (case)
Vimos que hay dos estructuras condicionales, aprendimos "if", nos detendremos ahora en "case".
Aprendimos que el "if" se empleaba cuando teníamos 2 cursos de acción, es decir, se evalúa una
condición y se ejecutan diferentes bloques de sentencias según el resultado de la condición sea
verdadero o falso.
La estructura "case" es similar a "if", sólo que se pueden establecer varias condiciones a cumplir.
Con el "if" solamente podemos obtener dos salidas, cuando la condición resulta verdadera y
cuando es falsa, si queremos más opciones podemos usar "case".
Sintaxis:
case VALORACOMPARAR
when VALOR1 then SENTENCIAS;
when VALOR2 then SENTENCIAS;
when VALOR3 then SENTENCIAS;
else SENTENCIAS;
end case;
Entonces, se emplea "case" cuando tenemos varios cursos de acción; es decir, por cada valor hay
un "when... then"; si encuentra un valor coincidente en algún "where" ejecuta el "then"
correspondiente a ese "where", si no hay ninguna coincidencia, se ejecuta el "else". Finalmente
se coloca "end case" para indicar que el "case" ha finalizado.
Necesitamos, dada una fecha, obtener el nombre del mes en español. Podemos utilizar la
estructura condicional "case". Para ello crearemos una función que reciba una fecha y retorne
una cadena de caracteres indicando el nombre del mes de la fecha enviada como argumento:
create or replace function f_mes(afecha date)
return varchar2
is
mes varchar2(20);
begin
mes:='enero';
case extract(month from afecha)
when 1 then mes:='enero';
when 2 then mes:='febrero';
when 3 then mes:='marzo';
when 4 then mes:='abril';
when 5 then mes:='mayo';
when 6 then mes:='junio';
when 7 then mes:='julio';
when 8 then mes:='agosto';
when 9 then mes:='setiembre';
when 10 then mes:='octubre';
when 11 then mes:='noviembre';
else mes:='diciembre';
end case;
return mes;
end;
Si probamos la función anterior enviándole la siguiente fecha:
select f_mes('10/10/2008') from dual;
obtendremos como resultado "octubre".
La siguiente función recibe una fecha y retorna si se encuentra en el 1º, 2º, 3º ó 4º trimestre del
año:
create or replace function f_trimestre(afecha date)
return varchar2
is
mes varchar2(20);
trimestre number;
begin
mes:=extract(month from afecha);
trimestre:=4;
case mes
when 1 then trimestre:=1;
when 2 then trimestre:=1;
when 3 then trimestre:=1;
when 4 then trimestre:=2;
when 5 then trimestre:=2;
when 6 then trimestre:=2;
when 7 then trimestre:=3;
when 8 then trimestre:=3;
when 9 then trimestre:=3;
else trimestre:=4;
end case;
return trimestre;
end;
La cláusula "else" puede omitirse, en caso que no se encuentre coincidencia con ninguno de los
"where", se sale del "case" sin modificar el valor de la variable "trimestre", con lo cual, retorna el
valor 4, que es que que almacenaba antes de entrar a la estructura "case".
Otra diferencia con "if" es que el "case" toma valores puntuales, no expresiones. No es posible
realizar comparaciones en cada "where". La siguiente sintaxis provocaría un error:
...
case mes
when >=1 then trimestre:=1;
when >=4 then trimestre:=2;
when >=7 then trimestre:=3;
when >=10 then trimestre:=4;
end case;
Si hay más de una sentencia en un "when...then" NO es necesario delimitarlas con "begin... end".
Podemos emplear "case" dentro de un "select". Veamos un ejemplo similar a la función anterior:
select nombre,fechanacimiento,
case extract(month from fechanacimiento)
when 1 then 1
when 2 then 1
when 3 then 1
when 4 then 2
when 5 then 2
when 6 then 2
when 7 then 3
when 8 then 3
when 9 then 3
else 4
end as trimestre
from empleados
order by trimestre;
99 - Control de flujo (case)
Primer problema:
Trabajamos con la tabla "empleados".
1- Elimine la tabla y luego créela con la siguiente estructura:
drop table empleados;
create table empleados (
documento char(8),
nombre varchar(30),
fechanacimiento date,
hijos number(2),
sueldo number(6,2),
sexo char(1)
);
2- Ingrese algunos registros:
insert into empleados values('20000000','Acosta Ana','10/05/1968',0,800,'f');
insert into empleados values('21111111','Bustos
Bernardo','09/07/1970',2,550,'m');
insert into empleados values('22222222','Caseros
Carlos','15/10/1971',3,500,'m');
insert into empleados values('23333333','Fuentes
Fabiana','25/08/1972',0,500,'f');
insert into empleados values('24444444','Gomez
Gaston','28/03/1979',1,850,'m');
insert into empleados values('25555555','Juarez
Javier','18/08/1981',2,600,'m');
insert into empleados values('26666666','Lopez Luis','17/09/1978',4,690,'m');
insert into empleados values('27777777','Morales
Marta','22/08/1975',2,480,'f');
insert into empleados values('28888888','Norberto
Nores','11/08/1973',3,460,'m');
insert into empleados values('29999999','Oscar
Oviedo','19/07/1976',0,700,'m');
3- La empresa tiene por política festejar los cumpleaños de sus empleados cada mes, si es de
sexo femenino se le regala un ramo de flores, sino, una lapicera. Realice un "select" mostrando el
nombre del empleado, el día del cumpleaños y una columna extra que muestre "FLORES" o
"LAPICERA" según el sexo del empleado (case), de todos los empleados que cumplen años en
el mes de agosto (where) y ordene por día.
Ver solución
Segundo problema:
Un profesor guarda los promedios de sus alumnos de un curso en una tabla llamada "alumnos".
1- Elimine la tabla.
drop table alumnos;
2- Cree la tabla:
create table alumnos(
legajo char(5) not null,
nombre varchar2(30),
promedio number(4,2)
);
3- Ingrese los siguientes registros:
insert into alumnos values(3456,'Perez Luis',8.5);
insert into alumnos values(3556,'Garcia Ana',7.0);
insert into alumnos values(3656,'Ludueña Juan',9.6);
insert into alumnos values(2756,'Moreno Gabriela',4.8);
insert into alumnos values(4856,'Morales Hugo',3.2);
insert into alumnos values(7856,'Gomez Susana',6.4);
4- Si el alumno tiene un promedio menor a 4, muestre un mensaje "reprobado", si el promedio es
mayor o igual a 4 y menor a 7, muestre "regular", si el promedio es mayor o igual a 7, muestre
"promocionado", usando "case" (recuerde que "case" toma valores puntuales, emplee "trunc")
5- Elimine la tabla "alumnos"
6- La nueva tabla contendrá varias notas por alumno. Cree la tabla:
create table alumnos(
legajo char(5) not null,
nombre varchar2(30),
nota number(4,2)
);
7- Ingrese los siguientes registros:
insert into alumnos values(3456,'Perez Luis',8.5);
insert into alumnos values(3456,'Perez Luis',9.9);
insert into alumnos values(3456,'Perez Luis',7.8);
insert into alumnos values(3556,'Garcia Ana',7.0);
insert into alumnos values(3556,'Garcia Ana',6.0);
insert into alumnos values(3656,'Ludueña Juan',9.6);
insert into alumnos values(3656,'Ludueña Juan',10);
insert into alumnos values(2756,'Moreno Gabriela',4.2);
insert into alumnos values(2756,'Moreno Gabriela',2.6);
insert into alumnos values(2756,'Moreno Gabriela',2);
insert into alumnos values(4856,'Morales Hugo',3.2);
insert into alumnos values(4856,'Morales Hugo',4.7);
insert into alumnos values(7856,'Gomez Susana',6.4);
insert into alumnos values(7856,'Gomez Susana',8.6);
8- Si el alumno tiene un promedio menor a 4, muestre un mensaje "reprobado", si el promedio es
mayor o igual a 4 y menor a 7, muestre "regular", si el promedio es mayor o igual a 7, muestre
"promocionado", usando "case" (recuerde que "case" toma valores puntuales, emplee "trunc").
Para obtener el promedio agrupe por legajo y emplee la función "avg"
9- Cree una tabla denominada "alumnosCondicion" con los campos "legajo", "notafinal" y
"condicion":
drop table alumnosCondicion;
create table alumnosCondicion(
legajo char(5),
notafinal number(4,2),
condicion varchar2(15)
);
10- Cree o reemplace un procedimiento almacenado llamado "pa_CargarCondicion" que guarde
en la tabla "alumnosCondicion" el legajo de cada alumno, el promedio de sus notas y la
condición (libre, regular o promocionado)
11- Ejecute el procedimiento "pa_cargarCondicion" y recupere todos los datos de la tabla
"alumnoscondicion"
Ver solución
100 - Control de flujo (loop)
Las estructuras repetitivas permiten ejecutar una secuencia de sentencias varias veces. Hay tres
estructuras repetitivas, o bucles: loop, for y while.
Comenzamos por "loop", que es la más simple. Veremos la sintaxis del bucle "loop" que
combina una condición y la palabra "exit".
Sintaxis:
loop
SENTENCIAS;
exit when CONDICION;
SENTENCIAS;
end loop;
Cuando se llega a la línea de código en la que se encuentra la condición "exit when", se evalúa
dicha condición, si resulta cierta, se salta a la línea donde se encuentra "end loop", saliendo del
bucle, omitiendo las sentencias existentes antes del "end loop"; en caso contrario, si la condición
resulta falsa, se continúa con las siguientes sentencias y al llegar a "end loop" se repite el bucle.
La sintaxis anterior es equivalente a la siguiente:
loop
SENTENCIAS
if CONDICION then
exit;
end if;
SENTENCIAS
end loop;
En este ejemplo se muestra la tabla del 3. Se va incrementando la variable "multiplicador" y se
almacena en una variable "resultado"; el ciclo se repite hasta que el multiplicador llega a 5, es
decir, 6 veces.
set serveroutput on;
declare
resultado number;
multiplicador number:=0;
begin
loop
resultado:=3*multiplicador;
dbms_output.put_line('3x'||to_char(multiplicador)||'='||
to_char(resultado));
multiplicador:=multiplicador+1;
exit when multiplicador>5;
end loop;
end;
En el siguiente ejemplo se muestra la tabla del 4. Se va incrementando la variable
"multiplicador" y se almacena en una variable "resultado"; el ciclo se repite hasta que la variable
resultado llega o supera el valor 50.
declare
resultado number;
multiplicador number:=0;
begin
loop
resultado:=4*multiplicador;
exit when resultado>=50;
dbms_output.put_line('4x'||to_char(multiplicador)||'='||
to_char(resultado));
multiplicador:=multiplicador+1;
end loop;
end;
Cuando se cumple la condición del "exit when" (supera el valor 50), no se ejecutan las sentencias
siguientes (líneas de salida y de incremento de "multiplicador"), se salta a "end loop" finalizando
el bucle.
100 - Control de flujo (loop)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados".
1- Elimine la tabla y créela con la siguiente estructura:
drop table empleados;
create table empleados(
nombre varchar2(40),
sueldo number(6,2)
);
2- Ingrese algunos registros:
insert into empleados values('Acosta Ana',550);
insert into empleados values('Bustos Bernardo',850);
insert into empleados values('Caseros Carolina',900);
insert into empleados values('Dominguez Daniel',490);
insert into empleados values('Fuentes Fabiola',820);
insert into empleados values('Gomez Gaston',740);
insert into empleados values('Huerta Hernan',1050);
3- Muestre la suma total de todos los sueldos realizando un "select" (5400)
4- Se necesita incrementar los sueldos en forma proporcional, en un 10% cada vez y controlar
que la suma total de sueldos no sea menor a $7000, si lo es, el bucle debe continuar y volver a
incrementar los sueldos, en caso de superarlo, se saldrá del ciclo repetitivo; es decir, este bucle
continuará el incremento de sueldos hasta que la suma de los mismos llegue o supere los 7000.
5- Verifique que los sueldos han sido incrementados y la suma de todos los sueldos es superior a
7000
6- Muestre el sueldo máximo realizando un "select"
7- Se necesita incrementar los sueldos en forma proporcional, en un 5% cada vez y controlar que
el sueldo máximo alcance o supere los $1600, al llegar o superarlo, el bucle debe finalizar.
Incluya una variable contador que cuente cuántas veces se repite el bucle
8- Verifique que los sueldos han sido incrementados y el sueldo máximo es igual o superior a
1600
9- Muestre el sueldo mínimo realizando un "select"
10- Se necesita incrementar los sueldos en forma proporcional, en un 10% cada vez y controlar
que el sueldo mínimo no supere los $900. Emplee la sintaxis "if CONDICION then exit"
11- Muestre el sueldo mínimo realizando un "select"
Ver solución
101 - Control de flujo (for)
Vimos que hay tres estructuras repetitivas, o bucles, ya estudiamos "loop". Continuamos con
"for".
En la sentencia "for... loop" se especifican dos enteros, un límite inferior y un límite superior, es
decir, un rango de enteros, las sentencias se ejecutan una vez por cada entero; en cada repetición
del bucle, la variable contador del "for" se incrementa en uno.
Sintaxis:
for VARIABLECONTADOR in LIMITEINFERIOR..LIMITESUPERIOR loop
SENTENCIAS;
end loop;
"Variablecontador" debe ser una variable numérica entera; "limiteinferior" y "limitesuperior" son
expresiones numéricas. La variable que se emplea como contador NO se define, se define
automáticamente de tipo entero al iniciar el bucle y se liberará al finalizarlo.
En el siguiente ejemplo se muestra la tabla del 3. La variable "f" comienza en cero (límite
inferior del for) y se va incrementando de a uno; el ciclo se repite hasta que "f" llega a 5 (límite
superior del for), cuando llega a 6, el bucle finaliza.
set serveroutput on;
begin
for f in 0..5 loop
dbms_output.put_line('3x'||to_char(f)||'='||to_char(f*3));
end loop;
end;
Si queremos que el contador se decremente en cada repetición, en lugar de incrementarse,
debemos colocar "reverse" luego de "in" y antes del límite inferior; el contador comenzará por el
valor del límite superior y finalizará al llegar al límite inferior decrementando de a uno. En este
ejemplo mostramos la tabla del 3 desde el 5 hasta el cero:
begin
for f in reverse 0..5 loop
dbms_output.put_line('3*'||to_char(f)||'='||to_char(f*3));
end loop;
end;
Se pueden colocar "for" dentro de otro "for". Por ejemplo, con las siguientes líneas imprimimos
las tablas del 2 y del 3 del 1 al 9:
begin
for f in 2..3 loop
dbms_output.put_line('tabla del '||to_char(f));
for g in 1..9 loop
dbms_output.put_line(to_char(f)||'x'||to_char(g)||'='||to_char(f*g));
end loop;--fin del for g
end loop;--fin del for f
end;
101 - Control de flujo (for)
Primer problema:
Con la estructura repetitiva "for... loop" que vaya del 1 al 20, muestre los números pares.
Dentro del ciclo debe haber una estructura condicional que controle que el número sea par y si lo
es, lo imprima por pantalla.
Con la estructura repetitiva "for... loop" muestre la sumatoria del número 5; la suma de todos los
números del 1 al 5. Al finalizar el ciclo debe mostrarse por pantalla la sumatoria de 5 (15)
Cree una función que reciba un valor entero y retorne el factorial de tal número; el factorial se
obtiene multiplicando el valor que recibe por el anterior hasta llegar a multiplicarlo por uno)
Llame a la función creada anteriormente y obtenga el factorial de 5 y de 4 (120 y 24)
1- Cree un procedimiento que reciba dos parámetros numéricos; la función debe mostrar la tabla
de multiplicar del número enviado como primer argumento, desde el 1 hasta el númeo enviado
como segundo argumento. Emplee "for"
Execute el procedimiento creado anteriormente enviándole los valores necesarios para que
muestre la tabla del 6 hasta el 20
Execute el procedimiento creado anteriormente enviándole los valores necesarios para que
muestre la tabla del 9 hasta el 10
Ver solución
102 - Control de flujo (while loop)
Ya estudiamos dos de las tres estructuras repetitivas. Continuamos con "while".
Vimos que las sentencias repetitivas permiten ejecutar una secuencia de sentencias varias veces.
Se coloca la palabra "loop" antes de las sentencias y al final "end loop".
"while...loop" (mientras) ejecuta repetidamente una instrucción (o bloque de instrucciones)
siempre que la condición sea verdadera.
Sintaxis básica:
while CONDICION loop
SENTENCIAS
end loop;
La diferencia entre "while...loop" y "for...loop" es que en la segunda se puede establecer la
cantidad de repeticiones del bucle con el valor inicial y final. Además, el segundo siempre se
ejecuta, al menos una vez, en cambio el primero puede no ejecutarse nunca, caso en el cual al
evaluar la condicion por primera vez resulte falsa.
En el siguiente ejemplo se muestra la tabla del 3 hasta el 5:
set server output on;
execute dbms_output.enable (20000);
declare
numero number:=0;
resultado number;
begin
while numero<=5 loop
resultado:=3*numero;
dbms_output.put_line('3*'||to_char(numero)||'='||to_char(resultado));
numero:=numero+1;
end loop;
end;
La condición establece que se multiplique la variable "numero" por 3 mientras "numero" sea
menor o igual a 5. En el bloque de sentencias se almacena en "resultado" la multiplicación, luego
se escribe tal valor y finalmente se incrementa la variable "numero" en 1.
Hacemos el seguimiento: cuando se inicia el bucle, la variable "numero" tiene el valor 0, se
ejecuta la primer linea de sentencias y "resultado" almacena el valor 0, se imprime (0) y se
incrementa la variable "numero", ahora contiene el valor 1; se vuelve a la condición, como la
condición es verdadera (1 es menor que 5), se vuelven a ejecutar las sentencias (resultado
almacena 3, se imprime (3), se guarda en numero el valor 2), se vuelve a evaluar la condición,
como resulta cierta (2 es menor que 5), se vuelven a ejecutar las sentencias (resultado almacena
6, se imprime, se guarda en numero el valor 3), se vuelve a evaluar la condición, como resulta
cierta (3 es menor que 5), se vuelven a ejecutar las sentencias (resultado almacena 9, se imprime,
se guarda en numero el valor 4), se vuelve a evaluar la condición, como resulta cierta (4 es
menor que 5), se vuelven a ejecutar las sentencias (resultado almacena 12, se imprime, se guarda
en numero el valor 5), se vuelve a evaluar la condición, como resulta cierta (5 es menor o igual a
5), se vuelven a ejecutar las sentencias (resultado almacena 15, se imprime, se guarda en numero
el valor 6), se vuelve a evaluar la condición, como resulta falsa (6 NO es menor ni igual a 5), se
sale de la estructura.
103 - Disparador (trigger)
Un "trigger" (disparador o desencadenador) es un bloque de código que se ejecuta
automáticamente cuando ocurre algún evento (como inserción, actualización o borrado) sobre
una determinada tabla (o vista); es decir, cuando se intenta modificar los datos de una tabla (o
vista) asociada al disparador.
Se crean para conservar la integridad referencial y la coherencia entre los datos entre distintas
tablas; para registrar los cambios que se efectúan sobre las tablas y la identidad de quien los
realizó; para realizar cualquier acción cuando una tabla es modificada; etc.
Si se intenta modificar (agregar, actualizar o eliminar) datos de una tabla asociada a un
disparador, el disparador se ejecuta (se dispara) en forma automática.
La diferencia con los procedimientos almacenados del sistema es que los triggers:
- no pueden ser invocados directamente; al intentar modificar los datos de una tabla asociada a
un disparador, el disparador se ejecuta automáticamente.
- no reciben y retornan parámetros.
- son apropiados para mantener la integridad de los datos, no para obtener resultados de
consultas.
Sintaxis general para crear un disparador:
create or replace trigger NOMBREDISPARADOR
MOMENTO-- before, after o instead of
EVENTO-- insert, update o delete
of CAMPOS-- solo para update
on NOMBRETABLA
NIVEL--puede ser a nivel de sentencia (statement) o de fila (for each row)
when CONDICION--opcional
begin
CUERPO DEL DISPARADOR--sentencias
end NOMBREDISPARADOR;
Los triggers se crean con la instrucción "create trigger" seguido del nombre del disparador. Si se
agrega "or replace" al momento de crearlo y ya existe un trigger con el mismo nombre, tal
disparador será borrado y vuelto a crear.
"MOMENTO" indica cuando se disparará el trigger en relación al evento, puede ser BEFORE
(antes), AFTER (después) o INSTEAD OF (en lugar de). "before" significa que el disparador se
activará antes que se ejecute la operación (insert, update o delete) sobre la tabla, que causó el
disparo del mismo. "after" significa que el trigger se activará después que se ejecute la operación
que causó el disparo. "instead of" sólo puede definirse sobre vistas, anula la sentencia
disparadora, se ejecuta en lugar de tal sentencia (ni antes ni después).
"EVENTO" especifica la operación (acción, tipo de modificación) que causa que el trigger se
dispare (se active), puede ser "insert", "update" o "delete"; DEBE colocarse al menos una acción,
puede ser más de una, en tal caso se separan con "or". Si "update" lleva una lista de atributos, el
trigger sólo se ejecuta si se actualiza algún atributo de la lista.
"on NOMBRETABLA" indica la tabla (o vista) asociada al disparador;
"NIVEL" puede ser a nivel de sentencia o de fila. "for each row" indica que el trigger es a nivel
de fila, es decir, se activa una vez por cada registro afectado por la operación sobre la tabla,
cuando una sola operación afecta a varios registros. Los triggers a nivel de sentencia, se activan
una sola vez (antes o después de ejecutar la operación sobre la tabla). Si no se especifica, o se
especifica "statement", es a nivel de sentencia.
"CUERPO DEL DISPARADOR" son las acciones que se ejecutan al dispararse el trigger, las
condiciones que determinan cuando un intento de inserción, actualización o borrado provoca las
acciones que el trigger realizará. El bloque se delimita con "begin... end".
Entonces, un disparador es un bloque de código asociado a una tabla que se dispara
automáticamente antes o después de una sentencia "insert", "update" o "delete" sobre la tabla.
Se crean con la instrucción "create trigger" especificando el momento en que se disparará, qué
evento lo desencadenará (inserción, actualización o borrado), sobre qué tabla (o vista) y las
instrucciones que se ejecutarán.
Los disparadores pueden clasificarse según tres parámetros:
- el momento en que se dispara: si se ejecutan antes (before) o después (after) de la sentencia.
- el evento que los dispara: insert, update o delete, según se ejecute una de estas sentencias sobre
la tabla.
- nivel: dependiendo si se ejecuta para cada fila afectada en la sentencia (por cada fila) o bien una
única vez por sentencia independientemente de la filas afectadas (nivel de sentencia).
Consideraciones generales:
- Las siguientes instrucciones no están permitidas en un desencadenador: create database, alter
database, drop database, load database, restore database, load log, reconfigure, restore log, disk
init, disk resize.
- Se pueden crear varios triggers para cada evento, es decir, para cada tipo de modificación
(inserción, actualización o borrado) para una misma tabla. Por ejemplo, se puede crear un "insert
trigger" para una tabla que ya tiene otro "insert trigger".
A continuación veremos la creación de disparadores para los distintos sucesos (inserción,
borrado, actualización) y todas las cláusulas adicionales.
104 - Disparador (información)
Los triggers son objetos, así que para obtener información de ellos pueden consultarse los
siguientes diccionarios:
- "user_objects": nos muestra todos los objetos de la base de datos seleccionada, incluidos los
triggers. En la columna "object_type" aparece "trigger" si es un disparador. En el siguiente
ejemplo solicitamos todos los objetos que son disparadores:
select *from user_objects where object_type='TRIGGER';
- "user_triggers": nos muestra todos los triggers de la base de datos actual. Muestra el nombre del
desencadenador (trigger_name), si es before o after y si es a nivel de sentencia o por fila
(trigger_type), el evento que lo desencadena (triggering_event), a qué objeto está asociado, si
tabla o vista (base_object_type), el nombre de la tabla al que está asociado (table_name), los
campos, si hay referencias, el estado, la descripción, el cuerpo (trigger_body), etc. En el
siguiente ejemplo solicitamos información de todos los disparadores que comienzan con "TR":
select trigger_name, triggering_event from user_triggers where trigger_name
like 'TR%';
- "user_source": se puede visualizar el código fuente almacenado en un disparador consultando
este diccionario: En el siguiente ejemplo solicitamos el código fuente del objeto
"TR_insertar_libros":
select *from user_source where name='TR_INSERTAR_LIBROS';
105 - Disparador de inserción a nivel de
sentencia
Dijimos que un disparador está asociado a una tabla y a una operación específica (inserción,
actualización o borrado).
A continuación veremos la creación de un disparador para el evento de inserción: "insert triger".
La siguiente es la sintaxis para crear un trigger de inserción que se dispare cada vez que se
ejecute una sentencia "insert" sobre la tabla especificada, es decir, cada vez que se intenten
ingresar datos en la tabla:
create or replace trigger NOMBREDISPARADOR
MOMENTO insert
on NOMBRETABLA
begin
CUERPO DEL TRIGGER;
end NOMBREDISPARADOR;
Analizamos la sintaxis:
Luego de la instrucción "create trigger" se coloca el nombre del disparador. Si se agrega "or
replace" al momento de crearlo y ya existe un trigger con el mismo nombre, tal disparador será
borrado y vuelto a crear.
"MOMENTO" indica cuando se disparará el trigger en relación al evento, puede se BEFORE
(antes) o AFTER (después). Se especifica el evento que causa que el trigger se dispare, en este
caso "insert", ya que el trigger se activará cada vez que se ejecute la sentencia "insert" sobre la
tabla especificada luego de "on".
Es un trigger a nivel de sentencia, es decir, se dispara una sola vez por cada sentencia "insert",
aunque la sentencia ingrese varios registros. Es el valor por defecto si no se especifica.
Finalmente se coloca el cuerpo del trigger dentro del bloque "begin.. end".
Las siguientes sentencias disparan un trigger de inserción:
insert into TABLA values ...;
insert into TABLA select ... from...;
Ejemplo: Creamos un desencadenador que se dispara cada vez que se ejecuta un "insert" sobre la
tabla "libros":
create or replace trigger tr_ingresar_libros
before insert
on libros
begin
insert into Control values(user,sysdate);
end tr_ingresar_libros;
Analizamos el trigger anterior:
"create or replace trigger" junto al nombre del disparador que tiene un prefijo "tr" para reconocer
que es un trigger, referencia el evento que lo disparará y la tabla asociada.
Para identificar fácilmente los disparadores de otros objetos se recomienda usar un prefijo y
darles el nombre de la tabla para la cual se crean junto al tipo de acción.
El disparador se activará antes ("before") del evento "insert" sobre la tabla "libros", es decir, se
disparará ANTES que se realice una inserción en "libros". El trigger está definido a nivel de
sentencia, se activa una vez por cada instrucción "insert" sobre "libros". El cuerpo del disparador
se delimita con "begin... end", allí se especifican las acciones que se realizarán al ocurrir el
evento de inserción, en este caso, ingresar en la tabla "control" el nombre del usuario que alteró
la tabla "libros" (obtenida mediante la función "user") y la fecha en que lo hizo (mediante la
función "sysdate").
105 - Disparador de inserción a nivel de
sentencia
Primer problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros" y en una tabla
"ofertas", algunos datos de los libros cuyo precio no supera los $30. Además, controla las
inserciones que los empleados realizan sobre "ofertas", almacenando en la tabla "control" el
nombre del usuario, la fecha y hora, cada vez que se ingresa un nuevo registro en la tabla
"ofertas".
1- Elimine las tres tablas:
drop table libros;
drop table ofertas;
drop table control;
2- Cree las tablas con las siguientes estructuras:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar2(20),
precio number(6,2)
);
create table ofertas(
titulo varchar2(40),
autor varchar2(30),
precio number(6,2)
);
create table control(
usuario varchar2(30),
fecha date
);
3- Establezca el formato de fecha para que muestre "DD/MM/YYYY HH24:MI":
4- Cree un disparador que se dispare cuando se ingrese un nuevo registro en "ofertas"; el trigger
debe ingresar en la tabla "control", el nombre del usuario, la fecha y la hora en la cual se realizó
un "insert" sobre "ofertas"
5- Vea qué informa el diccionario "user_triggers" respecto del trigger anteriormente creado
6- Ingrese algunos registros en "libros"
insert into libros values(100,'Uno','Richard Bach','Planeta',25); insert into libros values(102,'Matematica
estas ahi','Paenza','Nuevo siglo',12); insert into libros values(105,'El aleph','Borges','Emece',32); insert
into libros values(120,'Aprenda PHP','Molina Mario','Nuevo siglo',55);
7- Ingrese en "ofertas" los libros de "libros" cuyo precio no superen los $30, utilizando la
siguiente sentencia:
insert into ofertas select titulo,autor,precio from libros where precio<30;
8- Verifique que el trigger se disparó consultando la tabla "control"
Ver solución
106 - Disparador de insercion a nivel de fila
(insert trigger for each row)
Vimos la creación de un disparador para el evento de inserción a nivel de sentencia, es decir, se
dispara una vez por cada sentencia "insert" sobre la tabla asociada.
En caso que una sola sentencia "insert" ingrese varios registros en la tabla asociada, el trigger se
disparará una sola vez; si queremos que se active una vez por cada registro afectado, debemos
indicarlo con "for each row".
La siguiente es la sintaxis para crear un trigger de inserción a nivel de fila, se dispare una vez por
cada fila ingresada sobre la tabla especificada:
create or replace trigger NOMBREDISPARADOR
MOMENTO insert
on NOMBRETABLA
for each row
begin
CUERPO DEL TRIGGER;
end NOMBREDISPARADOR;
Creamos un desencadenador que se dispara una vez por cada registro ingresado en la tabla
"ofertas":
create or replace trigger tr_ingresar_ofertas
before insert
on ofertas
for each row
begin
insert into Control values(user,sysdate);
end tr_ingresar_ofertas;
Si al ejecutar un "insert" sobre "ofertas" empleamos la siguiente sentencia:
insert into ofertas select titulo,autor,precio from libros where precio<30;
y se ingresan 5 registros en "ofertas", en la tabla "control" se ingresarán 5 registros, uno por cada
inserción en "ofertas". Si el trigger hubiese sido definido a nivel de sentencia (statement), se
agregaría una sola fila en "control".
106 - Disparador de insercion a nivel de fila
(insert trigger for each row)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados" y en
una tabla "control", el nombre del usuario y la fecha, cada vez que se ingresa un nuevo registro
en la tabla "empleados".
1 Elimine las tablas:
drop table empleados;
drop table control;
2- Cree las tablas con las siguientes estructuras:
create table empleados(
documento char(8),
apellido varchar2(30),
nombre varchar2(30),
seccion varchar2(20)
);
create table control(
usuario varchar2(30),
fecha date
);
3- Cree un disparador que se dispare una vez por cada registro ingresado en "empleados"; el
trigger debe ingresar en la tabla "control", el nombre del usuario y la fecha en la cual se realizó
un "insert" sobre "empleados"
4- Vea qué nos informa el diccionario "user_triggers" respecto del trigger anteriormente creado
5- Ingrese algunos registros en "empleados":
insert into empleados values('22333444','ACOSTA','Ana','Secretaria');
insert into empleados values('22777888','DOMINGUEZ','Daniel','Secretaria');
insert into empleados values('22999000','FUENTES','Federico','Sistemas');
insert into empleados values('22555666','CASEROS','Carlos','Contaduria');
insert into empleados values('23444555','GOMEZ','Gabriela','Sistemas');
insert into empleados values('23666777','JUAREZ','Juan','Contaduria');
6- Verifique que el trigger se disparó 6 veces, una por cada fila afectada en la sentencia "insert"
anteriormente ejecutada; consultamos la tabla "control":
select *from control;
Si el trigger hubiese sido creado a nivel de sentencia, no de fila, el "insert" anterior se hubiese
activado una sola vez aún cuando se ingresaron 6 registros.
Ver solución
107 - Disparador de borrado (nivel de
sentencia y de fila)
Dijimos que un disparador está asociado a una tabla y a una operación específica (inserción,
actualización o borrado).
A continuación veremos la creación de un disparador para el evento de borrado: "delete triger".
La siguiente es la sintaxis para crear un trigger de eliminación que se dispare cada vez que se
ejecute una sentencia "delete" sobre la tabla especificada, es decir, cada vez que se eliminen
registros de la tabla:
create or replace trigger NOMBREDISPARADOR
MOMENTO delete
on NOMBRETABLA
NIVEL-- statement o for each row
begin
CUERPO DEL TRIGGER;
end NOMBREDISPARADOR;
Luego de la instrucción "create trigger" o "create or replace trigger" se coloca el nombre del
disparador.
"MOMENTO" indica cuando se disparará el trigger en relación al evento, puede se BEFORE
(antes) o AFTER (después). Se especifica el evento que causa que el trigger se dispare, en este
caso "delete", ya que el trigger se activará cada vez que se ejecute la sentencia "delete" sobre la
tabla especificada luego de "on".
En "NIVEL" se especifica si será un trigger a nivel de sentencia (se dispara una sola vez por cada
sentencia "delete", aunque la sentencia elimine varios registros) o a nivel de fila (se dispara
tantas veces como filas se eliminan en la sentencia "delete").
Finalmente se coloca el cuerpo del tigger dentro del bloque "begin.. end".
Creamos un desencadenador a nivel de fila que se dispara cada vez que se ejecuta un "delete"
sobre la tabla "libros", en el cuerpo del trigger se especifican las acciones, en este caso, por cada
fila eliminada de la tabla "libros", se ingresa un registro en "control" con el nombre del usuario
que realizó la eliminación y la fecha:
create or replace trigger tr_borrar_libros
before delete
on libros
for each row
begin
insert into Control values(user,sysdate);
end tr_borrar_libros;
107 - Disparador de borrado (nivel de
sentencia y de fila)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados" y en
otra llamada "control" guarda un registro por cada empleado que se elimina de la tabla
"empleados".
1- Elimine las tablas:
drop table empleados;
drop table control;
2- Cree las tablas con las siguientes estructuras:
create table empleados(
documento char(8),
apellido varchar2(20),
nombre varchar2(20),
seccion varchar2(30),
sueldo number(8,2)
);
create table control(
usuario varchar2(30),
fecha date
);
3- Ingrese algunos registros en "empleados":
insert into empleados values('22333444','ACOSTA','Ana','Secretaria',500);
insert into empleados
values('22777888','DOMINGUEZ','Daniel','Secretaria',560);
insert into empleados values('22999000','FUENTES','Federico','Sistemas',680);
insert into empleados values('22555666','CASEROS','Carlos','Contaduria',900);
insert into empleados values('23444555','GOMEZ','Gabriela','Sistemas',1200);
insert into empleados values('23666777','JUAREZ','Juan','Contaduria',1000);
4- Cree un disparador a nivel de fila, que se dispare cada vez que se borre un registro de
"empleados"; el trigger debe ingresar en la tabla "control", el nombre del usuario y la fecha en la
cual se realizó un "delete" sobre "empleados"
5- Vea qué informa el diccionario "user_triggers" respecto del trigger anteriormente creado
6- Elimine todos los empleados cuyo sueldo supera los $800
7- Vea si el trigger se disparó consultando la tabla "control"
Se eliminaron 3 registros, como el trigger fue definido a nivel de fila, se disparó 3 veces, una vez
por cada registro eliminado. Si el trigger hubiese sido definido a nivel de sentencia, se hubiese
disparado una sola vez.
8- Reemplace el disparador creado anteriormente por otro con igual código pero a nivel de
sentencia
9- Vea qué nos informa el diccionario "user_triggers" respecto del trigger anteriormente creado
en este caso es un desencadenador a nivel de sentencia; en la columna "TRIGGER_TYPE"
muestra "BEFORE STATEMENT".
10- Elimine todos los empleados de la sección "Secretaria"
Se han eliminado 2 registros, pero el trigger se ha disparado una sola vez.
11- Consultamos la tabla "control"
Si el trigger hubiese sido definido a nivel de fila, se hubiese disparado dos veces.
Ver solución
108 - Disparador de actualizacion a nivel de
sentencia (update trigger)
Dijimos que un disparador está asociado a una tabla y a una operación específica (inserción,
actualización o borrado).
A continuación veremos la creación de un disparador para el evento de actualización: "update
triger".
La siguiente es la sintaxis para crear un trigger de actualización a nivel de sentencia, que se
dispare cada vez que se ejecute una sentencia "update" sobre la tabla especificada, es decir, cada
vez que se intenten modificar datos en la tabla:
create or replace trigger NOMBREDISPARADOR
MOMENTO update
on NOMBRETABLA
statement
begin
CUERPO DEL TRIGGER;
end NOMBREDISPARADOR;
Luego de la instrucción "create trigger" se coloca el nombre del disparador. Si agregamos "or
replace" al momento de crearlo y ya existe un trigger con el mismo nombre, tal disparador será
borrado y vuelto a crear.
"MOMENTO" indica cuando se disparará el trigger en relación al evento, puede ser BEFORE
(antes) o AFTER (después). Se especifica el evento que causa que el trigger se dispare, en este
caso "update", ya que el trigger se activará cada vez que se ejecute la sentencia "update" sobre la
tabla especificada luego de "on".
"statement" significa que es un trigger a nivel de sentencia, es decir, se dispara una sola vez por
cada sentencia "update", aunque la sentencia modifique varios registros; como en cualquier
trigger, es el valor por defecto si no se especifica.
Finalmente se coloca el cuerpo del tigger dentro del bloque "begin.. end".
Las siguientes sentencias disparan un trigger de inserción:
update TABLA set CAMPO=NUEVOVALOR;
update TABLA set CAMPO=NUEVOVALOR where CONDICION;
Ejemplo: Creamos un desencadenador que se dispara cada vez que se ejecuta un "update" sobre
la tabla "libros":
create or replace trigger tr_actualizar_libros
before update
on libros
begin
insert into control values(user,sysdate);
end tr_actualizar_libros;
Al ocurrir el evento de actualización sobre "libros", se ingresa en la tabla "control" el nombre del
usuario que alteró la tabla "libros" (obtenida mediante la función "user") y la fecha en que lo hizo
(mediante la función "sysdate").
108 - Disparador de actualizacion a nivel de
sentencia (update trigger)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados" y en
otra llamada "control" guarda un registro por cada vez que un empleado actualiza datos sobre la
tabla "empleados".
1- Elimine las tablas:
drop table empleados;
drop table control;
2- Cree las tablas con las siguientes estructuras:
create table empleados(
documento char(8),
apellido varchar2(20),
nombre varchar2(20),
seccion varchar2(30),
sueldo number(8,2)
);
create table control(
usuario varchar2(30),
fecha date
);
3- Ingrese algunos registros en "empleados":
insert into empleados values('22333444','ACOSTA','Ana','Secretaria',500);
insert into empleados
values('22777888','DOMINGUEZ','Daniel','Secretaria',560);
insert into empleados values('22999000','FUENTES','Federico','Sistemas',680);
insert into empleados values('22555666','CASEROS','Carlos','Contaduria',900);
insert into empleados values('23444555','GOMEZ','Gabriela','Sistemas',1200);
insert into empleados values('23666777','JUAREZ','Juan','Contaduria',1000);
4- Cree un disparador a nivel de sentencia, que se dispare cada vez que se actualicen registros en
"empleados"; el trigger debe ingresar en la tabla "control", el nombre del usuario y la fecha en la
cual se realizó un "update" sobre "empleados"
5- Vea qué informa el diccionario "user_triggers" respecto del trigger anteriormente creado
6- Actualice un registro en "empleados":
update empleados set nombre='Graciela' where documento='23444555';
7- Vea si el trigger se disparó consultando la tabla "control"
8- Actualice varios registros de "empleados" en una sola sentencia
9- Vea si el trigger se disparó consultando la tabla "control"
Note que se modificaron 2 registros de "empleados", pero como la modificación se realizó con
una sola sentencia "update" y el trigger es a nivel de sentencia, se agregó solamente una fila a la
tabla "control"; si el trigger hubiese sido creado a nivel de fila, la sentencia anterior, hubiese
disparado el trigger 2 veces y habría ingresado en "control" 2 filas.
Ver solución
109 - Disparador de actualización a nivel de
fila (update trigger)
Vimos la creación de un disparador para el evento de actualización a nivel de sentencia, es decir,
se dispara una vez por cada sentencia "update" sobre la tabla asociada.
En caso que una sola sentencia "update" modifique varios registros en la tabla asociada, el
trigger se disparará una sola vez; si queremos que se active una vez por cada registro afectado,
debemos indicarlo con "for each row".
La siguiente es la sintaxis para crear un trigger de actualización a nivel de fila, se dispare una vez
por cada fila modificada sobre la tabla especificada:
create or replace trigger NOMBREDISPARADOR
MOMENTO update
on NOMBRETABLA
for each row
begin
CUERPO DEL TRIGGER;
end NOMBREDISPARADOR;
Creamos un desencadenador a nivel de fila, que se dispara una vez por cada fila afectada por un
"update" sobre la tabla "libros". Se ingresa en la tabla "control" el nombre del usuario que altera
la tabla "libros" (obtenida mediante la función "user") y la fecha en que lo hizo (mediante la
función "sysdate"):
create or replace trigger tr_actualizar_libros
before update
on libros
for each row
begin
insert into control values(user,sysdate);
end tr_actualizar_libros;
Si al ejecutar un "update" sobre "libros" se actualizan 5 registros, en la tabla "control" se
ingresarán 5 registros, uno por cada modificación. Si el trigger hubiese sido definido a nivel de
sentencia (statement), se agregaría una sola fila en "control".
109 - Disparador de actualización a nivel de
fila (update trigger)
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados" y en
otra llamada "control" guarda un registro por cada vez que un empleado actualiza datos sobre la
tabla "empleados".
1- Elimine las tablas:
drop table empleados;
drop table control;
2- Cree las tablas con las siguientes estructuras:
create table empleados(
documento char(8),
apellido varchar2(20),
nombre varchar2(20),
seccion varchar2(30),
sueldo number(8,2)
);
create table control(
usuario varchar2(30),
fecha date
);
3- Ingrese algunos registros en "empleados":
insert into empleados values('22333444','ACOSTA','Ana','Secretaria',500);
insert into empleados
values('22777888','DOMINGUEZ','Daniel','Secretaria',560);
insert into empleados values('22999000','FUENTES','Federico','Sistemas',680);
insert into empleados values('22555666','CASEROS','Carlos','Contaduria',900);
insert into empleados values('23444555','GOMEZ','Gabriela','Sistemas',1200);
insert into empleados values('23666777','JUAREZ','Juan','Contaduria',1000);
4- Cree un disparador que se dispare cada vez que se actualice un registro en "empleados"; el
trigger debe ingresar en la tabla "control", el nombre del usuario y la fecha en la cual se realizó
un "update" sobre "empleados"
5- Actualice varios registros de "empleados". Aumentamos en un 10% el sueldo de todos los
empleados de la seccion "Secretaria'
6- Vea cuántas veces se disparó el trigger consultando la tabla "control"
7- El trigger se disparó 2 veces, una vez por cada registro modificado en "empleados". Si el
trigger hubiese sido creado a nivel de sentencia, el "update" anterior hubiese disparado el trigger
1 sola vez aún cuando se modifican 2 filas.
8- Vea qué informa el diccionario "user_triggers" respecto del trigger anteriormente creado
obtenemos el nombre del disparador, el momento y nivel (before each row), evento que lo
dispara (update), a qué objeto está asociado (table), nombre de la tabla al que está asociado
(empleados) y otras columnas que no analizaremos por el momento.
Ver solución
110 - Disparador de actualización - lista de
campos (update trigger)
El trigger de actualización (a nivel de sentencia o de fila) permite incluir una lista de campos. Si
se incluye el nombre de un campo (o varios) luego de "update", el trigger se disparará
únicamente cuando alguno de esos campos (incluidos en la lista) es actualizado. Si se omite la
lista de campos, el trigger se dispara cuando cualquier campo de la tabla asociada es modificado,
es decir, por defecto toma todos los campos de la tabla.
La lista de campos solamente puede especificarse en disparadores de actualización, nunca en
disparadores de inserción o borrado.
Sintaxis general:
create or replace trigger NOMBREDISPARADOR
MOMENTO update of CAMPOS
on TABLA
NIVEL--statement o for each row
begin
CUERPODEL DISPARADOR;
end NOMBREDISPARADOR;
"CAMPOS" son los campos de la tabla asociada que activarán el trigger si son modificados.
Pueden incluirse más de uno, en tal caso, se separan con comas.
Creamos un desencadenador a nivel de fila que se dispara cada vez que se actualiza el campo
"precio" de la tabla "libros":
create or replace trigger tr_actualizar_precio_libros
before update of precio
on libros
for each row
begin
insert into control values(user,sysdate);
end tr_actualizar_precio_libros;
Si realizamos un "update" sobre el campo "precio" de "libros", el trigger se dispara. Pero si
realizamos un "update" sobre cualquier otro campo, el trigger no se dispara, ya que está definido
solamente para el campo "precio".
110 - Disparador de actualización - lista de
campos (update trigger)
Primer problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros" y controla las
acciones que los empleados realizan sobre dicha tabla almacenando en la tabla "control" el
nombre del usuario y la fecha, cada vez que se modifica el precio o la editorial de un libro.
1- Elimine las tablas:
drop table control;
drop table libros;
2- Cree las tablas con las siguientes estructuras:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar2(20),
precio number(6,2)
);
create table control(
usuario varchar2(30),
fecha date
);
3- Ingrese algunos registros en "libros":
insert into libros values(100,'Uno','Richard Bach','Planeta',25);
insert into libros values(103,'El aleph','Borges','Emece',28);
insert into libros values(105,'Matematica estas ahi','Paenza','Nuevo
siglo',12);
insert into libros values(120,'Aprenda PHP','Molina Mario','Nuevo siglo',55);
insert into libros values(145,'Alicia en el pais de las
maravillas','Carroll','Planeta',35);
4- Establezca el formato de fecha para que muestre "DD/MM/YYYY HH24:MI":
alter session set NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI';
5- Cree un desencadenador a nivel de sentencia que se dispare cada vez que se actualicen los
campos "precio" y "editorial" ; el trigger debe ingresar en la tabla "control", el nombre del
usuario, la fecha y la hora en la cual se realizó un "update" sobre "precio" o "editorial" de
"libros"
6- Vea qué informa el diccionario "user_triggers" respecto del trigger anteriormente creado
7- Aumente en un 10% el precio de todos los libros de editorial "Nuevo siglo'
8- Vea cuántas veces se disparó el trigger consultando la tabla "control"
El trigger se disparó 1 vez.
9- Cambie la editorial, de "Planeta" a "Sudamericana"
10- Veamos si el trigger se disparó consultando la tabla "control"
El trigger se disparó.
11- Modifique un campo diferente de los que activan el trigger
12- Verifique que el cambio se realizó
13- Verifique que el trigger no se disparó
El trigger no se disparó (no hay nuevas filas en "control"), pues está definido únicamente sobre
los campos "precio" y "editorial".
Ver solución
111 - Disparador de múltiples eventos
Hasta el momento hemos aprendido a crear un disparador (trigger) asociado a una única
operación (inserción, actualización o borrado).
Un trigger puede definirse sobre más de un evento; en tal caso se separan con "or".
Sintaxis para crear un disparador para múltiples eventos:
create or replace trigger NOMBREDISPARADOR
MOMENTO-- before, after o instead of
of CAMPO--si alguno de los eventos es update
EVENTOS-- insert, update y/o delete
on NOMBRETABLA
NIVEL--puede ser a nivel de sentencia (statement) o de fila (for each row)
begin
CUERPO DEL DISPARADOR--sentencias
end NOMBREDISPARADOR;
Si el trigger se define para más de un evento desencadenante, en el cuerpo del mismo se puede
emplear un condicional para controlar cuál operación disparó el trigger. Esto permite ejecutar
bloques de código según la clase de acción que disparó el desencadenador.
Para identificar el tipo de operación que disparó el trigger empleamos "inserting", "updating" y
"deleting".
Veamos un ejemplo. El siguiente trigger está definido a nivel de sentencia, para los eventos
"insert", "update" y "delete"; cuando se modifican los datos de "libros", se almacena en la tabla
"control" el nombre del usuario, la fecha y el tipo de modificación que alteró la tabla:
- si se realizó una inserción, se almacena "inserción";
- si se realizó una actualización (update), se almacena "actualización" y
- si se realizó una eliminación (delete) se almacena "borrado".
create or replace trigger tr_cambios_libros
before insert or update or delete
on libros
for each row
begin
if inserting then
insert into control values (user, sysdate,'inserción');
end if;
if updating then
insert into control values (user, sysdate,'actualización');
end if;
if deleting then
insert into control values (user, sysdate,'borrado');
end if;
end tr_cambios_libros;
Si ejecutamos un "insert" sobre "libros", el disparador se activa entrando por el primer "if"; si
ejecutamos un "update" el trigger se dispara entrando por el segundo "if"; si ejecutamos un
"delete" el desencadenador se dispara entrando por el tercer "if".
Las siguientes sentencias disparan el trigger creado anteriormente:
insert into TABLA values ...;
insert into TABLA select ... from...;
update TABLA set...;
delete from TABLA...;
111 - Disparador de múltiples eventos
Primer problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros" y controla las
acciones que los empleados realizan sobre dicha tabla almacenando en la tabla "control" el
nombre del usuario y la fecha, cada vez que se modifica el precio o la editorial de un libro.
1- Elimine las tablas:
drop table control;
drop table libros;
2- Cree las tablas con las siguientes estructuras:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar2(20),
precio number(6,2)
);
create table control(
usuario varchar2(30),
fecha date,
operacion varchar2(20)
);
3- Ingrese algunos registros en "libros":
insert into libros values(100,'Uno','Richard Bach','Planeta',25);
insert into libros values(103,'El aleph','Borges','Emece',28);
insert into libros values(105,'Matematica estas ahi','Paenza','Nuevo
siglo',12);
insert into libros values(120,'Aprenda PHP','Molina Mario','Nuevo siglo',55);
insert into libros values(145,'Alicia en el pais de las
maravillas','Carroll','Planeta',35);
4- El gerente permite:
- ingresar o borrar libros de la tabla "libros" unicamente los sábados de 8 a 12 hs.
- actualizar los precios de los libros de lunes a viernes de 8 a 18 hs. y sábados entre la 8 y 12 hs.
Cree un disparador para los tres eventos que controle la hora en que se realizan las operaciones
sobre "libros". Si se intenta eliminar, ingresar o actualizar registros de "libros" fuera de los días y
horarios permitidos, debe aparecer un mensaje de error. Si la operación de ingreso, borrado o
actualización de registros se realiza, se debe almacenar en "control", el nombre del usuario, la
fecha y el tipo de operación ejecutada
5- Cambie la fecha y hora del sistema a "domingo 19 hs.". Intente ingresar un libro
Mensaje de error.
6- Cambie la fecha y hora del sistema a "lunes 10 hs.". Intente ingresar un libro.
Mensaje de error.
7- Cambie la fecha y hora del sistema a "sabado 8 hs.". Ingrese un libro
8- Realice un "select" sobre "libros" y sobre "control" para verificar que se han cargado los datos
correspondientes/
Aparece el nuevo libro en "libros" y una fila de "ingreso" en "control".
9- Cambie la fecha y hora del sistema a "domingo 18 hs.". Intente modificar el precio de un libro.
Mensaje de error.
10- Cambie la fecha y hora del sistema a "sabado 15 hs.". Intente modificar el precio de un libro.
Mensaje de error.
11- Cambie la fecha y hora del sistema a "sabado 9 hs.". Actualice el precio de un libro
12- Realice un "select" sobre "libros" y sobre "control" para verificar que se han cargado los
datos correspondientes.
Aparece el nuevo precio en "libros" y una nueva fila de "actualización" en "control".
13- Cambie la fecha y hora del sistema a "martes 11:30 hs.". Actualice el precio de un libro
14- Realice un "select" sobre "libros" y sobre "control" para verificar que se han cargado los
datos correspondientes.
Aparece el nuevo precio en "libros" y una nueva fila de "actualización" en "control".
15- Cambie la fecha y hora del sistema a "domingo 18:30 hs.". Intente borrar un libro.
Mensaje de error.
16- Cambie la fecha y hora del sistema a "miercoles 15 hs.". Intente borrar un libro.
Mensaje de error.
17- Cambie la fecha y hora del sistema a "sábado 11:55 hs.". Borre un libro
18- Realice un "select" sobre "libros" y sobre "control" para verificar que se han cargado los
datos correspondientes.
Se ha eliminado el registro en "libros" y se ha cargado una nueva fila de "borrado" en "control".
Ver solución
112 - Disparador (old y new)
Cuando trabajamos con trigger a nivel de fila, Oracle provee de dos tablas temporales a las
cuales se puede acceder, que contienen los antiguos y nuevos valores de los campos del registro
afectado por la sentencia que disparó el trigger. El nuevo valor es ":new" y el viejo valor es
":old". Para referirnos a ellos debemos especificar su campo separado por un punto
":[Link]" y ":[Link]".
El acceso a estos campos depende del evento del disparador.
En un trigger disparado por un "insert", se puede acceder al campo ":new" unicamente, el campo
":old" contiene "null".
En una inserción se puede emplear ":new" para escribir nuevos valores en las columnas de la
tabla.
En un trigger que se dispara con "update", se puede acceder a ambos campos. En una
actualizacion, se pueden comparar los valores de ":new" y ":old".
En un trigger de borrado, unicamente se puede acceder al campo "old", ya que el campo ":new"
no existe luego que el registro es eliminado, el campo ":new" contiene "null" y no puede ser
modificado.
Los valores de "old" y "new" están disponibles en triggers after y before.
El valor de ":new" puede modificarse en un trigger before, es decir, se puede acceder a los
nuevos valores antes que se ingresen en la tabla y cambiar los valores asignando a
":[Link]" otro valor.
El valor de ":new" NO puede modificarse en un trigger after, esto es porque el trigger se activa
luego que los valores de "new" se almacenaron en la tabla.
El campo ":old" nunca se modifica, sólo puede leerse.
Pueden usarse en una clásula "when" (que veremos posteriormente).
En el cuerpo el trigger, los campos "old" y "new" deben estar precedidos por ":" (dos puntos),
pero si está en "when" no.
Veamos un ejemplo.
Creamos un trigger a nivel de fila que se dispara "antes" que se ejecute un "update" sobre el
campo "precio" de la tabla "libros". En el cuerpo del disparador se debe ingresar en la tabla
"control", el nombre del usuario que realizó la actualización, la fecha, el código del libro que ha
sido modificado, el precio anterior y el nuevo:
create or replace trigger tr_actualizar_precio_libros
before update of precio
on libros
for each row
begin
insert into control
values(user,sysdate,:[Link],:[Link],:[Link]);
end tr_actualizar_precio_libros;
Cuando el trigger se dispare, antes de ingresar los valores a la tabla, almacenará en "control",
además del nombre del usuario y la fecha, el precio anterior del libro y el nuevo valor.
El siguiente trigger debe controlar el precio que se está actualizando, si supera los 50 pesos, se
debe redondear tal valor a entero, hacia abajo (empleando "floor"), es decir, se modifica el valor
ingresado accediendo a ":[Link]" asignándole otro valor:
create or replace trigger tr_actualizar_precio_libros
before update of precio
on libros
for each row
begin
if (:[Link]>50) then
:[Link]:=floor(:[Link]);
end if;
insert into control
values(user,sysdate,:[Link],:[Link],:[Link]);
end tr_actualizar_precio_libros;
Si al actualizar el precio de un libro colocamos un valor superior a 50, con decimales, tal valor se
redondea al entero más cercano hacia abajo. Por ejemplo, si el nuevo valor es "54.99", se
almacenará "54".
Podemos crear un disparador para múltiples eventos, que se dispare al ejecutar "insert", "update"
y "delete" sobre "libros". En el cuerpo del trigger se realiza la siguiente acción: se almacena el
nombre del usuario, la fecha y los antiguos y viejos valores del campo "precio":
create or replace trigger tr_libros
before insert or update or delete
on libros
for each row
begin
insert into control
values(user,sysdate,:[Link],:[Link],:[Link]);
end tr_libros;
Si ingresamos un registro, el campo ":[Link]" y el campo ":[Link]" contendrán "null". Si
realizamos una actualización del campo de un campo que no sea "precio", los campos
":[Link]" y ":[Link]" guardarán el mismo valor.
Si eliminamos un registro, el campo ":[Link]" contendrá "null".
Entonces, se puede acceder a los valores de ":new" y ":old" en disparadores a nivel de fila (no en
disparadores a nivel de sentencia). Están disponibles en triggers after y before. Los valores de
":old" solamente pueden leerse, nunca modificarse. Los valores de ":new" pueden modificarse
únicamente en triggers before (nunca en triggers after).
112 - Disparador (old y new)
Primer problema:
Un comercio almacena los datos de sus artículos para la venta en una tabla denominada
"articulos" y controla las operaciones que se realizan en ella guardando ciertos datos en otra tabla
denominada "control".
1- Elimine las tablas:
drop table control;
drop table articulos;
2- Cree las tablas con las siguientes estructuras:
create table articulos(
codigo number(6),
descripcion varchar2(40),
precio number (6,2),
stock number(4)
);
create table control(
usuario varchar2(30),
fecha date,
codigo number(6)
);
3- Ingrese algunos registros en "articulos":
insert into articulos values(100,'regla 20 cm.',5.4,100);
insert into articulos values(102,'regla 40 cm.',15,80);
insert into articulos values(109,'lapices color x12',6,150);
insert into articulos values(130,'lapices color x6',4.5,100);
insert into articulos values(200,'compas metal',21.8,50);
4- Cree un trigger a nivel de fila que se dispara "antes" que se ejecute un "insert" sobre la tabla
"articulos". En el cuerpo del disparador se debe ingresar en la tabla "control", el nombre del
usuario que realizó la inserción, la fecha y el código del articulo que se ha ingresado
5- Ingrese un nuevo registro en "articulos"
6- Vea qué se almacenó en "control"
7- Cree un disparador que calcule el código cada vez que se inserte un nuevo registro
8- Ingrese un nuevo registro en "articulos"
9- Vea qué se almacenó en "articulos".
Note que ignora el valor de código ingresado y calcula el siguiente valor a partir del máximo
existente.
10- Vea qué se almacenó en "control"
11- Ingrese un nuevo artículo sin especificar código
12- Vea qué se almacenó en "articulos"
13- Vea qué se almacenó en "control"
Ver solución
Segundo problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros" y en otra
denominada "ofertas", almacena los códigos y precios de los libros cuyo precio es inferior a $50.
1- Elimine las tablas:
drop table libros;
drop table ofertas;
2- Cree las tablas con las siguientes estructuras:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar(20),
precio number(6,2)
);
create table ofertas(
codigo number(6),
precio number(6,2)
);
3- Ingrese algunos registros en "libros":
insert into libros values(100,'Uno','Richard Bach','Planeta',25);
insert into libros values(103,'El aleph','Borges','Emece',28);
insert into libros values(105,'Matematica estas ahi','Paenza','Nuevo
siglo',12);
insert into libros values(120,'Aprenda PHP','Molina Mario','Nuevo siglo',55);
insert into libros values(145,'Alicia en el pais de las
maravillas','Carroll','Planeta',35);
4- Cree un trigger a nivel de fila que se dispare al ingresar un registro en "libros"; si alguno de
los libros ingresados tiene un precio menor o igual a $30 debe ingresarlo en "ofertas"
5- Ingrese un libro en "libros" cuyo precio sea inferior a $30
6- Verifique que el trigger se disparó consultando "ofertas"
7- Ingrese un libro en "libros" cuyo precio supere los $30
8- Verifique que no se ingresó ningún registro en "ofertas"
9- Cree un trigger a nivel de fila que se dispare al modificar el precio de un libro. Si tal libro
existe en "ofertas" y su nuevo precio ahora es superior a $30, debe eliminarse de "ofertas"; si tal
libro no existe en "ofertas" y su nuevo precio ahora es inferior a $30, debe agregarse a "ofertas"
10- Aumente a más de $30 el precio de un libro que se encuentra en "ofertas"
11- Verifique que el trigger se disparó consultando "libros" y "ofertas"
12- Disminuya a menos de $31 el precio de un libro que no se encuentra en "ofertas"
13- Verifique que el trigger se disparó consultando "libros" y "ofertas"
14- Aumente el precio de un libro que no se encuentra en "ofertas"
15- Verifique que el trigger se disparó pero no se modificó "ofertas"
16- Cree un trigger a nivel de fila que se dispare al borrar un registro en "libros"; si alguno de los
libros eliminados está en "ofertas", también debe eliminarse de dicha tabla.
17- Elimine un libro en "libros" que esté en "ofertas"
18- Verifique que el trigger se disparó consultando "libros" y "ofertas"
19- Elimine un libro en "libros" que No esté en "ofertas"
20- Verifique que el trigger se disparó consultando "libros" y "ofertas"
21- Cree una tabla llamada "control" que almacene el código, la fecha y el precio de un libro,
antes elimínela por si existe
22- Cree un disparador que se dispare cada vez que se actualice el precio de un libro; el trigger
debe ingresar en la tabla "control", el código del libro cuyo precio se actualizó, la fecha y el
precio anterior.
23- Actualice el precio de un libro
24- Controle que el precio se ha modificado en "libros" y que se agregó un registro en "control"
25- Modifique nuevamente el precio del libro cambiado en el punto 11
26- Controle que el precio se ha modificado en "libros" y que se agregó un nuevo registro en
"control"
27- Modifique el precio de varios libros en una sola sentencia que incluya al modificado
anteriormente
28- Controle que el precio se ha modificado en "libros" y que se agregó un nuevo registro en
"control"
29- Vea qué informa el diccionario "user_triggers" respecto del trigger anteriormente creado
Ver solución
113 - Disparador condiciones (when)
En los triggers a nivel de fila, se puede incluir una restricción adicional, agregando la clausula
"when" con una condición que se evalúa para cada fila que afecte el disparador; si resulta cierta,
se ejecutan las sentencias del trigger para ese registro; si resulta falsa, el trigger no se dispara
para ese registro.
Limitaciones de "when":
- no puede contener subconsultas, funciones agregadas ni funciones definidas por el usuario;
- sólo se puede hacer referencia a los parámetros del evento;
- no se puede especificar en los trigers "instead of" ni en trigger a nivel de sentencia.
Creamos el siguiente disparador:
create or replace trigger tr_precio_libros
before insert or update of precio
on libros
for each row when([Link]>50)
begin
:[Link] := round(:[Link]);
end tr_precio_libros;
El disparador anterior se dispara ANTES (before) que se ejecute un "insert" sobre "libros" o un
"update" sobre "precio" de "libros". Se ejecuta una vez por cada fila afectada (for each row) y
solamente si cumple con la condición del "when", es decir, si el nuevo precio que se ingresa o
modifica es superior a 50. Si el precio es menor o igual a 50, el trigger no se dispara. Si el precio
es mayor a 50, se modifica el valor ingresado redondeándolo a entero.
Note que cuando hacemos referencia a "new" (igualmente con "old") en la condición "when", no
se colocan los dos puntos precediéndolo; pero en el cuerpo del trigger si.
Si ingresamos un registro con el valor 30.80 para "precio", el trigger no se dispara.
Si ingresamos un registro con el valor "55.6" para "precio", el trigger se dispara modificando tal
valor a "56".
Si actualizamos el precio de un libro a "40.30", el trigger no se activa.
Si actualizamos el precio de un libro a "50.30", el trigger se activa y modifica el valor a "50".
Si actualizamos el precio de 2 registros a valores que superen los "50", el trigger se activa 2
veces redondeando los valores a entero.
Si actualizamos en una sola sentencia el precio de 2 registros y solamente uno de ellos supera los
"50", el trigger se activa 1 sola vez.
El trigger anterior podría haberse creado de la siguiente manera:
create or replace trigger tr_precio_libros
before insert or update of precio
on libros
for each row
begin
if :[Link]>50 then
:[Link] := round(:[Link]);
end if;
end tr_precio_libros;
En este caso, la condición se chequea en un "if" dentro del cuerpo del trigger. La diferencia con
el primer trigger que contiene "when" es que la condición establecida en el "when" se testea
antes que el trigger se dispare y si resulta verdadera, se dispara el trigger, sino no. En cambio, si
la condición está dentro del cuerpo del disparador, el trigger se dispara y luego se controla el
precio, si cumple la condición, se modifica el precio, sino no.
Por ejemplo, la siguiente sentencia:
update libros set precio=40 where...;
no dispara el primer trigger, ya que no cumple con la condición del "when"; pero si dispara el
segundo trigger, que no realiza ninguna acción ya que al evaluarse la condición del "if", resulta
falsa.
113 - Disparador condiciones (when)
Primer problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros" y en otra
denominada "ofertas", almacena los códigos y precios de los libros cuyo precio es inferior a $50.
1- Elimine las tablas:
drop table libros;
drop table ofertas;
2- Cree las tablas con las siguientes estructuras:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar(20),
precio number(6,2)
);
create table ofertas(
codigo number(6),
titulo varchar2(40)
);
3- Ingrese algunos registros en "libros":
insert into libros values(100,'Uno','Richard Bach','Planeta',25);
insert into libros values(103,'El aleph','Borges','Emece',28);
insert into libros values(105,'Matematica estas ahi','Paenza','Nuevo
siglo',12);
insert into libros values(120,'Aprenda PHP','Molina Mario','Nuevo siglo',55);
insert into libros values(145,'Alicia en el pais de las
maravillas','Carroll','Planeta',35);
4- Cree un trigger a nivel de fila que se dispara "antes" que se ejecute un "insert" sobre "libros".
Se activa solamente si el precio que se ingresa es inferior a $30, en caso de serlo, se ingresa en
"ofertas" el código y precio del libro
5- Ingrese un libro en "libros" cuyo precio sea inferior a $30
6- Verifique que el trigger se disparó consultando "ofertas"
7- Ingrese un libro en "libros" cuyo precio supere los $30
8- Verifique que el trigger no se disparó consultando "ofertas"
9- Cree un trigger a nivel de fila que se dispare al borrar un libro de "libros", únicamente si el
precio del libro que se elimina es inferior a $30, es decir, si existe en "ofertas"
10- Elimine un registro de "libros" cuyo precio sea inferior a $30
11- Verifique que el trigger se disparó consultando "ofertas" y "libros"
12- Elimine un registro de "libros" cuyo precio supere los $30
13- Verifique que el trigger no se disparó consultando "ofertas" y que si se ha eliminado el
registro en "libros"
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados".
1- Elimine la tabla:
drop table empleados;
2- Cree la tabla con la siguiente estructura:
create table empleados(
documento char(8),
apellido varchar2(20),
nombre varchar2(20),
seccion varchar2(30),
sueldo number(8,2)
);
3- Ingrese algunos registros:
insert into empleados values('22333444','ACOSTA','Ana','Secretaria',500);
insert into empleados values('22555666','CASEROS','Carlos','Contaduria',900);
insert into empleados
values('22777888','DOMINGUEZ','Daniel','Secretaria',560);
insert into empleados values('22999000','FUENTES','Federico','Sistemas',680);
insert into empleados values('23444555','GOMEZ','Gabriela','Sistemas',1200);
insert into empleados values('23666777','JUAREZ','Juan','Contaduria',1000);
4- La empresa necesita controlar cuando se le aumenta el sueldo a los empleados, guardando en
una tabla denominada "control", el nombre del usuario, la fecha, el documento de quien se ha
modificado el sueldo, el antiguo sueldo y el nuevo sueldo. Para ello cree la tabla control (antes
elimínela por si existe):
drop table control;
create table control(
usuario varchar2(30),
fecha date,
documento char(8),
antiguosueldo number(8,2),
nuevosueldo number(8,2)
);
5- Cree un disparador que almacene el nombre del usuario, la fecha, documento, el antiguo y el
nuevo sueldo en "control" cada vez que se actualice un sueldo de la tabla "empleados" a un valor
mayor. Si el sueldo se disminuye, el trigger no debe activarse. Si se modifica otro campo
diferente de "sueldo", no debe activarse.
6- Actualice el sueldo de todos los empleados de la sección "Sistemas" a "1000"
7- Consulte la tabla "control" para ver cuántas veces se ha disparado el trigger
Se ha disparado una sola vez; se actualizaron 2 registros, pero en solo uno de ellos se aumentó el
sueldo.
8- Al empleado con documento "22333444" se lo ha cambiado a la sección "contaduria". Realice
el cambio en la tabla "empleados"
9- Verifique que el trigger no se ha activado porque no se ha modificado el campo "sueldo".
Consulte "control"
10- Cree un disparador a nivel de fila que se dispare cada vez que se ingrese un nuevo empleado
y coloque en mayúsculas el apellido ingresado. Además, si no se ingresa sueldo, debe ingresar '0'
11- Ingrese un nuevo empleado empleando minúsculas en el apellido
12- Verifique que el trigger "tr_ingresar_empleados" se disparó
13- Ingrese dos nuevos empleados, uno sin sueldo y otro con sueldo "null"
14- Verifique que el trigger "tr_ingresar_empleados" se ha disparado
Los dos registros deben tener el apellido en mayúsculas y deben tener el valor '0' en sueldo.
15- Cree un disparador a nivel de fila que se dispare cada vez que se ingresa un nuevo empleado
y coloque "null" en "sueldo" si el sueldo ingresado supera los $1000 o es inferior a $500
16- Ingrese un nuevo empleado con un sueldo que dispare el trigger creado anteriormente
17- Verifique que el trigger "tr_ingresar_empleados" se disparó
Ver solución
114 - Disparador de actualizacion - campos
(updating)
En un trigger de actualización a nivel de fila, se puede especificar el nombre de un campo en la
condición "updating" para determinar cuál campo ha sido actualizado.
Sintaxis básica:
create or replace trigger NOMBRETRIGGER
MOMENTO update...
begin
if updating ('CAMPO') then
...
end if;
end NOMBREDISPARADOR;
El siguiente trigger se dispara cuando se actualiza la tabla "libros". Dentro del cuerpo del trigger
se averigua el campo que ha sido modificado; en caso de modificarse el "precio", se ingresa en la
tabla "controlPrecios" la fecha, el código del libro y el antiguo y nuevo precio; en caso de
actualizarse cualquier otro campo, se almacena en la tabla "control" el nombre del usuario que
realizó la modificación, la fecha y el código del libro modificado.
create or replace trigger tr_actualizar_libros
before update
on libros
for each row
begin
if updating ('precio') then
insert into controlprecios
values(sysdate,:[Link],:[Link],:[Link]);
else
insert into control values(user,sysdate,:[Link]);
end if;
end tr_actualizar_libros;
114 - Disparador de actualizacion - campos
(updating)
Primer problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros".
1- Elimine la tabla:
drop table libros;
2- Cree la tabla con la siguiente estructura:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar2(20),
precio number(6,2),
stock number(4)
);
3-Ingrese algunos registros en "libros":
insert into libros values(100,'Uno','Richard Bach','Planeta',25,100);
insert into libros values(103,'El aleph','Borges','Emece',28,0);
insert into libros values(105,'Matematica estas ahi','Paenza','Nuevo
siglo',12,50);
insert into libros values(120,'Aprenda PHP','Molina Mario','Nuevo
siglo',55,200);
insert into libros values(145,'Alicia en el pais de las
maravillas','Carroll','Planeta',35,10);
4- Cree un trigger a nivel de fila que se dispare "antes" que se ejecute un "update" sobre la tabla
"libros". En el cuerpo del trigger se debe averiguar el campo que ha sido modificado. En caso de
modificarse:
- el código, debe rechazarse la modificación con un mensaje de error.
- el "precio", se controla si es mayor o igual a cero, si lo es, debe dejarse el precio anterior y
mostrar un mensaje de error.
- el stock, debe controlarse que no se ingrese un número negativo ni superior a 1000, en tal caso,
debe rechazarse con un mensaje de error.
5- Intente modificar el precio de un libro con un valor negativo
Mensaje de error 20001;
6- Verifique que el trigger se ha disparado consultando la tabla "libros"
El cambio de precio no se realizó.
7- Actualice un precio a un valor aceptado
8- Verifique que el trigger se ha disparado consultando la tabla "libros"
El cambio de precio se realizó.
9- Intente cambiar el código de un libro
Mensaje de error 20000.
10- Verifique que el cambio no se ha realizado
11- Intente cambiar el stock de un libro a un valor negativo
Mensaje de error 20002.
12- Verifique que el cambio no se ha realizado
13- Intente cambiar el stock de un libro a un valor que supere los 1000
Mensaje de error 20002.
14- Cambie el stock de un libro a un valor permitido
15- Verifique que el cambio se ha realizado
Ver solución
Segundo problema:
Un comercio almacena los datos de los artículos que tiene para la venta en una tabla denominada
"articulos". En otra tabla denominada "pedidos" almacena el código de cada artículo y la
cantidad que necesita solicitar a los mayoristas. En una tabla llamada "controlPrecios" almacena
la fecha, el código del artículo y ambos precios (antiguo y nuevo).
1- Elimine las tablas:
drop table articulos;
drop table pedidos;
drop table controlPrecios;
2- Cree las tablas con las siguientes estructuras:
create table articulos(
codigo number(4),
descripcion varchar2(40),
precio number (6,2),
stock number(4)
);
create table pedidos(
codigo number(4),
cantidad number(4)
);
create table controlPrecios(
fecha date,
codigo number(4),
anterior number(6,2),
nuevo number(6,2)
);
3- Ingrese algunos registros en "articulos":
insert into articulos values(100,'cuaderno rayado 24h',4.5,100);
insert into articulos values(102,'cuaderno liso 12h',3.5,150);
insert into articulos values(104,'lapices color x6',8.4,60);
insert into articulos values(160,'regla 20cm.',6.5,40);
insert into articulos values(173,'compas xxx',14,35);
insert into articulos values(234,'goma lapiz',0.95,200);
4- Ingrese en "pedidos" todos los códigos de "articulos", con "cantidad" cero
5- Active el paquete "dbms_output":
set serveroutput on;
execute dbms_output.enable(20000);
6- Cada vez que se disminuye el stock de un artículo de la tabla "articulos", se debe incrementar
la misma cantidad de ese artículo en "pedidos" y cuando se incrementa en "articulos", se debe
disminuir la misma cantidad en "pedidos". Si se ingresa un nuevo artículo en "articulos", debe
agregarse un registro en "pedidos" con "cantidad" cero. Si se elimina un registro en "articulos",
debe eliminarse tal artículo de "pedidos". Cree un trigger para los tres eventos (inserción,
borrado y actualización), a nivel de fila, sobre "articulos", para los campos "stock" y "precio",
que realice las tareas descriptas anteriormente, si el campo modificado es "stock". Si el campo
modificado es "precio", almacene en la tabla "controlPrecios", la fecha, el código del artículo, el
precio anterior y el nuevo.
El trigger muestra el mensaje "Trigger activado" cada vez que se dispara; en cada "if" muestra un
segundo mensaje que indica cuál condición se ha cumplido.
7- Disminuya el stock del artículo "100" a 30
Un mensaje muestra que el trigger se ha disparado actualizando el "stock".
8- Verifique que el trigger se disparó consultando la tabla "pedidos" (debe aparecer "70" en
"cantidad" en el registro correspondiente al artículo "100")
9- Ingrese un nuevo artículo en "articulos"
Un mensaje muestra que el trigger se ha disparado por una inserción.
10- Verifique que se ha agregado un registro en "pedidos" con código "280" y cantidad igual a 0
11- Elimine un artículo de "articulos"
Un mensaje muestra que el trigger se ha disparado por un borrado.
12- Verifique que se ha borrado el registro correspondiente al artículo con código "234" en
"pedidos"
13- Modifique el precio de un artículo
Un mensaje muestra que el trigger se ha disparado por una actualización de precio.
14- Verifique que se ha agregado un registro en "controlPrecios"
15- Modifique la descripción de un artículo
El trigger no se ha disparado, no aparece mensaje.
16- Modifique el precio, stock y descripcion de un artículo
Un mensaje muestra que el trigger se ha disparado por una actualización de stock y otra de
precio. La actualización de "descripcion" no disparó el trigger.
17- Verifique que se ha agregado un registro en "controlPrecios" y se ha modificado el campo
"cantidad" con el valor "5"
18- Modifique el stock de varios artículos en una sola sentencia
Cuatro mensajes muestran que el trigger se ha disparado 4 veces, por actualizaciones de stock.
19- Verifique que se han modificado 4 registros en "pedidos"
20- Modifique el precio de varios artículos en una sola sentencia
Cuatro mensajes muestran que el trigger se ha disparado 4 veces, por actualizaciones de precio.
21- Verifique que se han agregado 4 nuevos registros en "controlPrecios"
22- Elimine varios artículos en una sola sentencia
Cuatro mensajes muestran que el trigger se ha disparado 4 veces, por borrado de registros.
23- Verifique que se han eliminado 4 registros en "pedidos"
Ver solución
115 - Disparadores (habilitar y deshabilitar)
Un disparador puede estar en dos estados: habilitado (enabled) o deshabilitado (disabled).
Cuando se crea un trigger, por defecto está habilitado.
Se puede deshabilitar un trigger para que no se ejecute. Un trigger deshabilitado sigue existiendo,
pero al ejecutar una instrucción que lo dispara, no se activa.
Sintaxis para deshabilitar un trigger:
alter trigger NOMBREDISPARADOR disable;
Ejemplo: Deshabilitamos el trigger "tr_ingresar_empleados":
alter trigger tr_ingresar_empleados disable;
Sintaxis para habilitar un trigger que está deshabilitado:
alter trigger NOMBREDISPARADOR enable;
Ejemplo: Habilitamos el trigger "tr_actualizar_empleados":
alter trigger tr_actualizar_empleados enable;
Se pueden habilitar o deshabilitar todos los trigger establecidos sobre una tabla especifica, se
emplea la siguiente sentencia;
alter table TABLA disable all triggers;--deshabilita
alter table TABLA enable all triggers;-- habilita
La siguiente sentencia deshabilita todos los triggers de la tabla "empleados":
alter table empleados enable all triggers;
Podemos saber si un trigger está o no habilitado cosultando el diccionario "user_triggers", en la
columna "status" aparece "enabled" si está habilitado y "disabled" si está deshabilitado.
115 - Disparadores (habilitar y deshabilitar)
Primer problema:
Una librería almacena los datos de sus libros en una tabla denominada "libros" y controla las
acciones que los empleados realizan sobre dicha tabla almacenando en la tabla "control" el
nombre del usuario, la fecha, y el tipo de modificación que se realizó sobre la tabla "libros".
1- Elimine la tabla "libros" y la tabla "control":
drop table libros;
drop table control;
2- Cree las tablas con las siguientes estructuras:
create table libros(
codigo number(6),
titulo varchar2(40),
autor varchar2(30),
editorial varchar2(20),
precio number(6,2)
);
create table control(
usuario varchar2(30),
fecha date,
operacion varchar2(20)
);
3- Ingrese algunos registros en "libros":
insert into libros values(100,'Uno','Richard Bach','Planeta',25);
insert into libros values(103,'El aleph','Borges','Emece',28);
insert into libros values(105,'Matematica estas ahi','Paenza','Nuevo
siglo',12);
insert into libros values(120,'Aprenda PHP','Molina Mario','Nuevo siglo',55);
insert into libros values(145,'Alicia en el pais de las
maravillas','Carroll','Planeta',35);
4- Cree un disparador que se active cuando modificamos algún campo de "libros" y almacene en
"control" el nombre del usuario que realiza la actualización, la fecha y en "operacion" coloque el
nombre del campo actualizado
5- Cree otro desencadenador que se active cuando ingresamos un nuevo registro en "libros", debe
almacenar en "control" el nombre del usuario que realiza el ingreso, la fecha e "insercion" en
"operacion"
6- Cree un tercer trigger sobre "libros" que se active cuando eliminamos un registro de "libros",
debe almacenar en "control" el nombre del usuario que realiza la eliminación, la fecha y
"borrado" en "operacion"
7- Los tres triggers están habilitados. Consultamos el diccionario "user_triggers" para
corroborarlo
8- Ingrese un libro y compruebe que el trigger "tr_ingresar_libros" se dispara recuperando los
registros de "control"
9- Deshabilite el trigger "tr_ingresar_libros"
10- Consulte el diccionario "user_triggers" para corroborarlo
El trigger "tr_ingresar_libros" está deshabilitado, "tr_actualizar_libros" y "tr_eliminar_libros"
están habilitados.
11- Ingrese un libro y compruebe que el trigger de inserción no se dispara recuperando los
registros de "control":
insert into libros values(152,'El anillo del
hechicero','Gaskin','Planeta',22);
select *from control;
12- Actualice la editorial de varios libros y compruebe que el trigger de actualización se dispara
recuperando los registros de "control"
13- Deshabilite el trigger "tr_actualizar_libros"
14- Consulte el diccionario "user_triggers" para corroborarlo
Los triggers "tr_ingresar_libros" y "tr_actualizar_libros" están deshabilitados,
"tr_eliminar_libros" está habilitado.
15- Borre un libro de "libros" y compruebe que el trigger de borrado se disparó recuperando los
registros de "control"
16- Deshabilite el trigger "tr_eliminar_libros"
17- Consulte el diccionario "user_triggers" para comprobarlo
Los tres trigger establecidos sobre "empleados" están deshabilitados.
18- Elimine un libro de "libros" y compruebe que tal registro se eliminó de "libros" pero que el
trigger de borrado no se dispara recuperando los registros de "control"
19- Habilite el trigger "tr_actualizar_libros"
20- Actualice el autor de un libro y compruebe que el trigger de actualización se dispara
recuperando los registros de "control"
21- Habilite todos los triggers establecidos sobre "libros"
22- Consulte el diccionario "user_triggers" para comprobar que el estado (status) de todos los
triggers establecidos sobre "libros" es habilitado
Los tres trigger establecidos sobre "libros" han sido habilitados. Se activarán ante cualquier
sentencia "insert", "update" y "delete".
Ver solución
116 - Disparador (eliminar)
Para eliminar un trigger se emplea la siguiente sentencia:
drop trigger NOMBRETRIGGER;
Ejemplo:
drop trigger tr_insertar_libros;
Si eliminamos una tabla, se eliminan todos los triggers establecidos sobre ella.
116 - Disparador (eliminar)
Primer problema:
Un comercio almacena los datos de los artículos que tiene para la venta en una tabla denominada
"articulos". En otra tabla denominada "ventas" almacena el código de cada artículo, la cantidad
que se vende y la fecha.
1- Elimine las tablas:
drop table ventas;
drop table articulos;
2- Cree las tablas con las siguientes estructuras:
create table articulos(
codigo number(4) not null,
descripcion varchar2(40),
precio number (6,2),
stock number(4),
constraint PK_articulos_codigo
primary key (codigo)
);
create table ventas(
codigo number(4),
cantidad number(4),
fecha date,
constraint FK_ventas_articulos
foreign key (codigo)
references articulos(codigo)
);
3- Cree una secuencia llamada "sec_codigoart", estableciendo que comience en 1, sus valores
estén entre 1 y 9999 y se incrementen en 1. Antes elimínela por si existe
4- Active el paquete para permitir mostrar salida en pantalla
5- Cree un trigger que coloque el siguiente valor de una secuencia para el código de "articulos"
cada vez que se ingrese un nuevo artículo
Podemos ingresar un nuevo registro en "articulos" sin incluir el código porque lo ingresará el
disparador luego de calcularlo. Si al ingresar un registro en "articulos" incluimos un valor para
código, será ignorado y reemplazado por el valor calculado por el disparador.
6- Ingrese algunos registros en "articulos" sin incluir el código:
insert into articulos (descripcion, precio, stock) values ('cuaderno rayado
24h',4.5,100);
insert into articulos (descripcion, precio, stock) values ('cuaderno liso
12h',3.5,150);
insert into articulos (descripcion, precio, stock) values ('lapices color
x6',8.4,60);
7- Recupere todos los artículos para ver cómo se almacenó el código
8- Ingrese algunos registros en "articulos" incluyendo el código:
insert into articulos values(160,'regla 20cm.',6.5,40);
insert into articulos values(173,'compas metal',14,35);
insert into articulos values(234,'goma lapiz',0.95,200);
9- Recupere todos los artículos para ver cómo se almacenó los códigos
Ignora los códigos especificados ingresando el siguiente de la secuencia.
10- Cuando se ingresa un registro en "ventas", se debe:
- controlar que el código del artículo exista en "articulos" (lo hacemos con la restricción "foreign
key" establecida en "ventas");
- controlar que exista stock, lo cual no puede controlarse con una restricción "foreign key"
porque el campo "stock" no es clave primaria en la tabla "articulos"; cree un trigger. Si existe
stock, debe disminuirse en "articulos".
Cree un trigger a nivel de fila sobre la tabla "ventas" para el evento se inserción. Cada vez que se
realiza un "insert" sobre "ventas", el disparador se ejecuta. El disparador controla que la cantidad
que se intenta vender sea menor o igual al stock del articulo y actualiza el campo "stock" de
"articulos", restando al valor anterior la cantidad vendida. Si la cantidad supera el stock, debe
producirse un error, revertirse la acción y mostrar un mensaje
11- Ingrese un registro en "ventas" cuyo código no exista en "articulos"
Aparece un mensaje de error, porque el código no existe. El trigger se ejecutó.
12- Verifique que no se ha agregado ningún registro en "ventas"
13- Ingrese un registro en "ventas" cuyo código exista en "articulos" y del cual haya suficiente
stock
Note que el trigger se disparó, aparece el texto "tr_insertar_ventas activado".
14- Verifique que el trigger se disparó consultando la tabla "articulos" (debe haberse disminuido
el stock) y se agregó un registro en "ventas"
15- Ingrese un registro en "ventas" cuyo código exista en "articulos" y del cual NO haya
suficiente stock
Aparece el mensaje mensaje de error 20001 y el texto que muestra que se disparó el trigger.
16- Verifique que NO se ha disminuido el stock en "articulos" ni se ha agregado un registro en
"ventas"
17- El comercio quiere que se realicen las ventas de lunes a viernes de 8 a 18 hs. Reemplace el
trigger creado anteriormente "tr_insertar_ventas" para que No permita que se realicen ventas
fuera de los días y horarios especificados y muestre un mensaje de error
18- Ingrese un registro en "ventas", un día y horario permitido, si es necesario, modifique la
fecha y la hora del sistema
19- Verifique que se ha agregado un registro en "ventas" y se ha disminuido el stock en
"articulos"
20- Ingrese un registro en "ventas", un día permitido fuera del horario permitido (si es necesario,
modifique la fecha y hora del sistema)
Se muestra un mensaje de error.
21- Ingrese un registro en "ventas", un día sábado a las 15 hs.
22- El comercio quiere que los registros de la tabla "articulos" puedan ser ingresados,
modificados y/o eliminados únicamente los sábados de 8 a 12 hs. Cree un trigger "tr_articulos"
que No permita que se realicen inserciones, actualizaciones ni eliminaciones en "articulos" fuera
del horario especificado los días sábados, mostrando un mensaje de error. Recuerde que al
ingresar un registro en "ventas", se actualiza el "stock" en "articulos"; el trigger debe permitir las
actualizaciones del campo "stock" en "articulos" de lunes a viernes de 8 a 18 hs. (horario de
ventas)
23- Ingrese un nuevo artículo un sábado a las 9 AM
Note que se activan 2 triggers.
24- Elimine un artículo, un sábado a las 16 hs.
Mensaje de error.
25- Actualice el precio de un artículo, un domingo
26- Actualice el precio de un artículo, un lunes en horario de ventas
Mensaje de error.
27- Ingrese un registro en "ventas" que modifique el "stock" en "articulos", un martes entre las 8
y 18 hs.
Note que se activan 2 triggers.
28- Consulte el diccionario "user_triggers" para ver cuántos trigger están asociados a "articulos"
y a "ventas" (3 triggers)
29- Elimine el trigger asociado a "ventas"
30- Elimine las tablas "ventas" y "articulos"
31- Consulte el diccionario "user_triggers" para verificar que al eliminar la tabla "articulos" se
han eliminado todos los triggers asociados a ella
Ver solución
Segundo problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados" y en
otra tabla llamada "secciones", el código de la sección y el sueldo máximo de cada una de ellas.
1- Elimine las tablas:
drop table empleados;
drop table secciones;
2- Cree las tablas, con las siguientes estructuras:
create table secciones(
codigo number(2),
nombre varchar2(30),
sueldomaximo number(8,2),
constraint PK_secciones primary key(codigo)
);
create table empleados(
documento char(8) not null,
nombre varchar2(30) not null,
domicilio varchar2(30),
codigoseccion number(2) not null,
sueldo number(8,2),
constraint PK_empleados primary key(documento),
constraint FK_empleados_seccion
foreign key (codigoseccion)
references secciones(codigo)
);
3- Ingrese algunos registros en ambas tablas:
insert into secciones values(1,'Administracion',1500);
insert into secciones values(2,'Sistemas',2000);
insert into secciones values(3,'Secretaria',1000);
insert into empleados values('22222222','Ana Acosta','Avellaneda 88',1,1100);
insert into empleados values('23333333','Bernardo Bustos','Bulnes
345',1,1200);
insert into empleados values('24444444','Carlos Caseres','Colon 674',2,1800);
insert into empleados values('25555555','Diana Duarte','Colon 873',3,1000);
4- Active el paquete necesario para mostrar mensaje por pantalla:
set serveroutput on;
execute dbms_output.enable (20000);
5- En cada disparador que cree próximamente muestre un mensaje por pantalla que indique su
nombre.
6- Cree un disparador para que se ejecute cada vez que una instrucción "insert" ingrese datos en
"empleados"; el mismo debe verificar que el sueldo del empleado no sea mayor al sueldo
máximo establecido para la sección, si lo es, debe mostrar un mensaje indicando tal situación y
deshacer la transacción
7- Ingrese un nuevo registro en "empleados" cuyo sueldo sea menor o igual al establecido para la
sección:
insert into empleados values('26666666','Federico Fuentes','Francia
938',2,1000);
El disparador se ejecutó, un texto en pantalla muestra su nombre.
8- Verifique que el disparador se ejecutó consultando la tabla "empleados"
9- Intente ingresar un nuevo registro en "empleados" cuyo sueldo sea mayor al establecido para
la sección
El disparador se ejecutó mostrando un mensaje de error y la transacción se deshizo.
10- Verifique que el registro no se agregó en "empleados"
11- Intente ingresar un empleado con código de sección inexistente
Aparece un mensaje de error porque se viola la restricción "foreign key"; el trigger se ejecutó,
aparece el mensaje de texto que lo indica.
12- Cree un disparador para que se ejecute cada vez que una instrucción "update" aumente el
sueldo de "empleados"; el mismo debe verificar que el sueldo del empleado no supere al sueldo
máximo establecido para la sección, si lo es, debe mostrar un mensaje indicando tal situación y
deshacer la transacción
13- Modifique el sueldo de un empleado, debe ser menor o igual al establecido para la sección
El trigger se disparó.
14- Verifique que el disparador se ejecutó consultando la tabla "empleados"
15- Intente actualizar el sueldo de un empleado a un valor mayor al establecido para la sección
El disparador se ejecutó mostrando un mensaje de error y la transacción se deshizo.
16- Verifique que el registro no se modificó en "empleados"
17- Disminuya el sueldo de un empleado
El trigger no se disparo (no se mostró el texto con su nombre) porque se estableció en la
condición "when" que el sueldo nuevo fuera mayor al anterior.
18- Verifique que el registro se modificó en "empleados"
19- Modifique el código de sección del empleado cuyo documento es "22222222" a "3"
Note que el cambio se realizó, y ahora existe un empleado de la sección "Secretaria" con sueldo
"1350" cuando el máximo para esa sección es de "1000". Debe crear el trigger
"tr_empleados_update_seccion", que se dispare cada vez que se modifique la seccion de un
empleado y verifique que el sueldo no supere el máximo de la nueva sección, si lo supera, la
transacción debe deshacerse
20- Modifique el código de sección del empleado cuyo documento es "22222222" a "1"
El trigger se disparó, como el sueldo no supera el máximo permitido para la nueva sección, el
cambio se realizó.
21- Verifique que el cambio se realizó
22- Modifique el código de sección del empleado cuyo documento es "23333333" a "3"
El trigger se disparó y mostró el mensaje de error, la transacción se deshizo.
23- Verifique que el cambio no se realizó
24- Modifique el sueldo del empleado cuyo documento es "23333333" a "1000" y el código de
sección a "3"
El trigger se disparó.
25- Verifique que el cambio se realizó
26- Si modificamos el sueldo máximo de una sección de "secciones", disminuyéndolo, pueden
quedar en "empleados" valores de sueldos superiores al permitido para la sección. Para evitar
esto debe crear un disparador sobre "secciones" que se active cuando se disminuya el campo
"sueldomaximo" y modifique el sueldo (al máximo permitido para la sección) de todos los
empleados de esa sección cuyos sueldos superen el nuevo máximo establecido
27- Modifique el sueldo máximo para la sección "Administracion" a 2000, es decir, auméntelo
Note que el trigger No se disparó, porque el trigger tiene una condición "when" que especifica
que se active unicamente cuando el nuevo sueldo maximo sea menor al anterior.
28- Verifique que el sueldo máximo de "Administracion" se ha modificado
29- Modifique el sueldo máximo para la sección "Administracion" a 1800, es decir, disminúyalo
Note que el trigger se disparó, cumple con la condición "when". Pero, como no hay en
"empleados", sueldos de tal sección que superen tal valor, no se han modificado registros en
"empleados".
30- Verifique que se modificó el sueldo máximo en "secciones" pero ningún registro en
"empleados"
31- Modifique el sueldo máximo para la sección "Administracion" a 1200, es decir, disminúyalo
Note que el trigger se disparó, cumple con la condición "when". Como hay en "empleados" un
sueldo de 1350, de "Administracion", es decir supera el nuevo "sueldomaximo" que se intenta
establecer, se modifica tal registro en "empleados".
32- Verifique que se modificó el sueldo máximo en "secciones" y un registro en "empleados"
33- Cree un trigger que no permita que se modifique el código de "secciones"
34- Intente modificar el código de una sección de "secciones"
Note que el trigger se disparó y muestra el mensaje de error. El código no se modificó.
Verifíquelo
35- Actualice en una misma sentencia "update", el sueldo a "1800" y el codigo de sección a "2"
del empleado cuyo documento es "22222222"
Note que se activan 2 triggers.
36- Cree un trigger a nivel de sentencia sobre "empleados", que muestre un mensaje de error para
evitar que se actualice el campo "documento"
37- Consulte el diccionario "user_triggers" para ver cuántos trigger están asociados a
"empleados" y a "secciones"
38- Elimine los 2 triggers asociados a la tabla "secciones"
39- Consulte el diccionario "user_triggers" para verificar que "secciones" ya no tiene
disparadores asociados a ella
40- Cree un trigger sobre "secciones", para el evento de actualización que realice todas las
acciones que ejecutaban los 2 triggers que "secciones" tenía asociados anteriormente; es decir:
- si se actualiza un sueldo máximo, modificar el sueldo, al máximo permitido, a todos los
empleados (de la sección modificada) cuyos sueldos superen el nuevo sueldo máximo;
- definir un mensaje de error si se intenta actualizar un código se sección.
41- Probarlo. Disminuir el sueldo máximo de una sección que no supere el sueldo de ningun
empleado:
Se activó el trigger de actualizacion de secciones pero ningún registro de "empleados" fue
modificado.
42- Disminuir el sueldo máximo de una sección de modo que supere el sueldo de algún
empleado
Se activó el trigger de actualizacion de secciones y 2 registros de "empleados" fueron
modificados.
43- Intente modificar un código de sección
Mensaje de error.
44- Consulte el diccionario "user_triggers" para ver cuántos triggers están asociados a las tablas
"secciones" y "empleados"
45- Elimine la tabla "empleados"
46- Consulte el diccionario "user_triggers" para verificar que al borrar la tabla "empleados" se
eliminaron todos los disparadores asociados a ella
47- Elimine la tabla "secciones" y consulte "user_triggers" para verificar que al borrar la tabla
"secciones" se eliminaron todos los desencadenadores asociados a ella
Ver solución
117 - Errores definidos por el usuario
Oracle permite definir a los usuarios errores especificando un número de error y un mensaje
empleando el procedimiento "raise_application_error".
Sintaxis:
raise_application_error (NUMERO,TEXTO);
El procedimiento "raise_application_error" permite emitir un mensaje de error. El NUMERO de
mensaje debe ser un número negativo entre -20000 y -20999 y el mensaje de TEXTO una cadena
de caracteres de hasta 2048 bytes.
Si durante la ejecución de un trigger se produce un error definido por el usuario, se anulan todas
las actualizaciones realizadas por la acción del trigger así como el evento que la activó, es decir,
se reanuda cualquier efecto retornando un mensaje y se deshace la orden ejecutada.
En caso que se incluya en el cuerpo de un disparador "after" (que se ejecuta después de la
sentencia, es decir, cuando los datos ya han sido actualizados), la sentencia será deshecha
(rollback). Si es un disparador "before" (que se ejecuta antes de la sentencia, o sea, cuando los
datos aún no han sido actualizados), la sentencia no se ejecuta.
Veamos un ejemplo: Creamos un trigger de actualización a nivel de fila sobre la tabla "libros".
Ante cualquier modificación de los registros de "libros", se debe ingresar en la tabla "control", el
nombre del usuario que realizó la actualización y la fecha; pero, controlamos que NO se permita
modificar el campo "codigo", en caso de suceder, la acción no debe realizarse y debe mostrarse
un mensaje de error indicándolo:
create or replace trigger tr_actualizar_libros
before update
on libros
for each row
begin
if updating('codigo') then
raise_application_error(-20001,'No se puede modificar el código de los
libros');
else
insert into control values(user,sysdate);
end if;
end;
Si se actualiza cualquier campo de "libros", se dispara el trigger; si se actualiza el campo
"codigo", aparece un mensaje de error y la actualización no se realiza; en caso de actualizarse
cualquier otro campo, se almacenará en "control", el nombre del usuario y la fecha.
117 - Errores definidos por el usuario
Primer problema:
Una empresa almacena los datos de sus empleados en una tabla denominada "empleados" y en
otra tabla llamada "control", guarda el nombre del usuario, la fecha y el tipo de operación que se
realiza en la tabla "empleados".
1- Elimine las tablas "empleados" y "control":
drop table empleados;
drop table control;
2- Cree las tablas:
create table empleados(
documento char(8),
apellido varchar2(30),
nombre varchar2(30),
domicilio varchar2(30),
seccion varchar2(20),
sueldo number(8,2)
);
create table control(
usuario varchar2(30),
fecha date,
operacion varchar2(30)
);
3- Ingrese algunos registros:
insert into empleados values('22222222','Acosta','Ana','Avellaneda
11','Secretaria',1800);
insert into empleados values('23333333','Bustos','Betina','Bulnes
22','Gerencia',5000);
insert into empleados values('24444444','Caseres','Carlos','Colon
333','Contaduria',3000);
4- Cree un trigger de inserción sobre "empleados" que guarde en "control" el nombre del usuario
que ingresa datos, la fecha y "insercion", en el campo "operacion". Pero, si el sueldo que se
intenta ingresar supera los $5000, debe mostrarse un mensaje de error y deshacer la transacción
5- Cree un trigger de borrado sobre "empleados" que guarde en "control" los datos requeridos (en
"operacion" debe almacenar "borrado". Si se intenta eliminar un empleado de la sección
"gerencia", debe aparecer un mensaje de error y deshacer la operación
6- Cree un trigger de actualización. Ante cualquier modificación de los registros de "empleados",
se debe ingresar en la tabla "control", el nombre del usuario que realizó la actualización, la fecha
y "actualizacion". Pero, controlamos que NO se permita modificar el campo "documento", en
caso de suceder, la acción no debe realizarse y debe mostrarse un mensaje de error indicándolo
7- Intente ingresar un empleado con sueldo superior a $5000:
insert into empleados values('25555555','Duarte','Dario','Dominicana
444','Secretaria',5800);
Note que muestra el mensaje de error definido por usted.
8- Ingrese un empleado con valores permitidos:
insert into empleados values('25555555','Duarte','Dario','Dominicana
444','Secretaria',2800);
9- Intente borrar un empleado de "gerencia"
Aparece un mensaje de error.
10- Elimine un empleado que no sea de "Gerencia"
11- Intente modificar el documento de un empleado
Mensaje de error.
12- Modifique un campo diferente de "documento"
13- Vea que se ha almacenado hasta el momento en "control"
Debe haber 3 registros, de inserción, de borrado y actualización.
Ver solución
118 - Seguridad y acceso a Oracle
Una de las tareas al administrar Oracle es permitir el acceso a bases de datos y asignar permisos
sobre los objetos que conforman una base de datos.
Para conectarnos con un servidor Oracle necesitamos un modo de acceso que incluye los
permisos que dispondremos durante la conexión; estos permisos se definen a partir de un nombre
de usuario.
Un USUARIO es un identificador necesario para acceder a una base de datos. Un usuario es un
conjunto de permisos que se aplican a una conexión de base de datos. Un usuario es además
propietario de ciertos objetos.
Los PRIVILEGIOS (permisos) especifican qué operaciones puede realizar un usuario y sobre
qué objetos de la base de datos tiene autorización, es decir, qué tarea puede realizar con esos
objetos y si puede emitir determinadas instrucciones. Estas operaciones pueden ser de dos tipos:
de sistema y sobre objeto.
Un rol de base de datos es una agrupación de permisos de sistema y de objeto.
Un ROL (role) es un grupo de usuarios; permite agrupar usuarios para aplicarles permisos; así, al
agregar un nuevo usuario a la base de datos, no es necesario concederle permiso para cada
objeto, sino que lo agregamos a un rol; cuando asignamos permisos sobre un objeto al rol,
automáticamente el permiso afectará a los usuarios que pertenezcan a tal rol.
Los permisos controlan el acceso a los distintos objetos de una base de datos; pueden concederse
a nivel de usuario (individualmente) o a nivel de rol (a todos los usuarios de un grupo).
Los permisos que un usuario tiene en una base de datos dependen de los permisos de usuario y
de los roles al que pertenezca dicho usuario.
Usuarios, roles y permisos son la base de los mecanismos de seguridad de Oracle.
119 - Usuarios (crear)
Puede haber varios usuarios diferentes de la base de datos. Cada uno es propietario de sus
objetos.
Para crear un usuario debemos conectarnos a la base datos como administradores (por ejemplo
"system").
Sintaxis básica para crear un usuario:
create user NOMBREUSUARIO identified by CONTRASEÑA
default tablespace NOMBRETABLESPACEPORDEFECTO
quota CANTIDAD on TABLEESPACE;
** [default role ROLE, ALL];
La cláusula "identified by" permite indicar una contraseña.
La cláusula "default tablespace" será el tablespace (espacio de tablas) por defecto en la creación
de objetos del usuario. Si se omite se utilizará el tablespace SYSTEM. Los tablespaces son
unidades lógicas en las cuales de divide una base de datos, en las cuales se almacenan los objetos
(tablas, secuencias, etc.); todos los objetos están almacenados dentro de un tablespace.
La cláusula "quota" permite configurar un espacio en bytes, Kb o Mb en la base de datos. Si no
se especifica, por defecto es cero y no podrá crear objetos.
La cláusula "default role" permite asignar roles de permisos durante la creación del usuario.
Ejemplo:
create user ana identified by anita;
Con la sentencia anterior se crea un usuario denominado "ana" con la clave "anita", el tablespace
por defecto es "system" porque no se especificó otro.
Con la siguiente sentencia se crea un usuario denominado "juan" con la clave "juancito", se le
asigna un espacio de 100 mb:
create user juan identified by juancito
default tablespace system
quota 100M on system;
Si intentamos crear un usuario que ya existe, Oracle muestra un mensaje de error indicando tal
situación.
El diccionario "dba_users" muestra información sobre todos los usuarios; el nombre de usuario
(username), contraseña (password), estado (account_status), espacio (default_tablespace), fecha
de expiración (expiry_date), fecha de creación (created), entre otros.
Luego de crear un usuario, aún no podemos conectarnos, ya que no tenemos permiso para crear
una sesión. Los permisos se aprenderán próximamente.
119 - Usuarios (crear)
Primer problema:
Una escuela necesita crear 2 usuarios diferentes en su base de datos. Uno denominado "director"
y otro "profesor". Luego se les concederán diferentes permisos para retringir el acceso a los
diferentes objetos. Conéctese como administrador (por ejemplo "system").
1- Primero eliminamos el usuario "director", porque si existe, aparecerá un mensaje de error:
drop user director cascade;
2- Cree un usuario "director", con contraseña "escuela" y 100M de espacio en "system"
3- Elimine el usuario "profesor":
drop user profesor cascade;
4- Cree un usuario "profesor", con contraseña "maestro" y espacio en "system"
5- Consulte el diccionario "dba_users" y analice la información que nos muestra
Ver solución
120 - Permiso de conexión
Los usuarios necesitan permisos para poder acceder a la base de datos y a los objetos de la
misma.
Los privilegios pueden ser de dos tipos: del sistema y sobre objetos.
Como mínimo, un usuario debe tener permiso para conectarse.
El permiso "create session" es un privilegio de sistema.
Para conceder permiso de conexión a un usuario empleamos la instrucción "grant".
Sintaxis básica:
grant create session
to USUARIO;
En el siguiente ejemplo concedemos al usuario "juan" permiso para conectarse:
grant create session to juan;
Podemos consultar el diccionario "dba_sys_privs" para encontrar los privilegios concedidos a los
usuarios. Nos mostrará el nombre del usuario (grantee) y el permiso (privilege), entre otra
información que analizaremos próximamente.
Luego de tener permiso para crear sesión, puede crear una sesión presionando el ícono "new
connection" en la solapa "connections"; se abrirá una ventana en la cual deberá colocar un
nombre de conexión ("connection name", puede ser el mismo nombre de usuario), el nombre del
usuario ("username") y la contraseña ("password"), luego presionar el botón "connect"; se abrirá
una nueva solapa (nueva conexión) con el nombre del usuario; no se abrirá la nueva conexión si:
a) el usuario para quien quiere abrir una nueva sesión no existe,
b) la contraseña es incorrecta o
c) el usuario existe pero no tiene permiso "create session".
Si consultamos el diccionario "user_sys_privs" obtendremos la misma información que
"dba_sys_privs" pero únicamente del usuario actual.
Podemos averiguar el nombre del usuario conectado con la siguiente sentencia:
select user from dual;
120 - Permiso de conexión
Primer problema:
Una escuela necesita crear 3 usuarios diferentes en su base de datos. Uno denominado "director",
otro "profesor" y un tercero "alumno".
Conéctese como administrador (por ejemplo "system").
1- Elimine el usuario "director", porque si existe, aparecerá un mensaje de error:
drop user director cascade;
2- Cree un usuario "director", con contraseña "dire" y 100M de espacio en "system"
3- Elimine el usuario "profesor":
drop user profesor cascade;
4- Cree un usuario "profesor", con contraseña "profe" y espacio en "system"
5- Elimine el usuario "alumno" y luego créelo con contraseña "alu" y espacio en "system"
6- Consulte el diccionario "dba_users" y analice la información que nos muestra
Deben aparecer los tres usuarios creados anteriormente.
7- Consulte el diccionario "dba_sys_privs" para encontrar los privilegios concedidos a nuestros
tres usuarios
Nos muestra que estos usuarios no tienen ningún privilegio concedido.
8- Conceda a "director" permiso para conectarse
9- Conceda a "profesor" permiso para conectarse
10- Consulte el diccionario "dba_sys_privs" para encontrar los privilegios concedidos a nuestros
3 usuarios
11- Abra una nueva conexión para "director". Se debe abrir una nueva solapa (nueva conexión)
con el nombre del usuario (director)
12- En la conexión de "director" consulte sus privilegios
13- Obtenga el nombre del usuario conectado
14- Vuelva a la conexión "system" (la otra solapa) y compruebe el usuario actual
15- Intente abrir una nueva conexión para el usuario inexistente. Debe aparecer un mensaje de
error y denegarse la conexión. Cancele.
16- Intente abrir una nueva conexión para el usuario "profesor" colocando una contraseña
incorrecta. Debe aparecer un mensaje de error y denegarse la conexión. Cancele.
17- Abra una nueva conexión para "profesor" colocando los datos correctos. Se debe abrir una
nueva solapa (nueva conexión) con el nombre del usuario (profesor).
18- Intentemos abrir una nueva conexión para el usuario "alumno", el cual no tiene permiso. Un
mensaje de error indica que el usuario "alumno" no tiene permiso "create session" por lo cual se
deniega la conexión. Cancele.
19- Conceda a "alumno" permiso de conexión
20- Consulte el diccionario "dba_sys_privs" para encontrar los privilegios concedidos a
"alumno"
21- Abra una nueva conexión para "ALUMNO". Se debe abrir una nueva solapa (nueva
conexión) con el nombre del usuario (profesor)
22- Consulte el diccionario "user_sys_privs"
23- Compruebe que está en la sesión de "alumno"
Ver solución
121 - Privilegios del sistema (conceder)
Aprendimos que los usuarios necesitan permisos para poder acceder a la base de datos y a los
objetos de la misma. Dijimos que los privilegios pueden ser de dos tipos: a) del sistema y b)
sobre objetos.
Hemos aprendido a conceder un privilegio de sistema: "create session", que es necesario para
poder conectarse a la base de datos, es decir, para iniciar una sesión.
Pero teniendo únicamente este permiso, no podemos hacer mucho, solamente iniciar una sesión,
pero no podemos crear tablas, ni ningún otro objeto; por ello son importantes los permisos de
creación de objetos.
Aprendamos más sobre los privilegios de sistema.
Los privilegios de sistema son permisos para realizar ciertas operaciones en la base de datos.
Los siguientes son algunos de los privilegios de sistema existentes:
- create session: para conectarse a la base de datos;
- create table: crear tablas;
- create sequence: crear secuencias;
- create view: crear vistas;
- create trigger: crear disparadores en su propio esquema;
- create procedure: crear procedimientos y funciones;
- execute any procedure: ejecutar cualquier procedimiento en cualquier esquema;
- create user: crear usuarios y especificar claves;
- create role: crear roles;
- drop user: eliminar usuarios.
Se asignan privilegios de sistema a un usuario mediante la instrucción "grant":
Sintaxis básica:
grant PERMISODESISTEMA
to USUARIO;
Oracle permite conceder múltiples privilegios a múltiples usuarios en una misma sentencia,
debemos separarlos por comas.
En el siguiente ejemplo se concede el permiso para crear sesión a los usuarios "juan" y "ana":
grant create sesion
to juan, ana;
En el siguiente ejemplo se conceden los permisos para crear tablas y vistas al usuario "ana":
grant create table, create view
to ana;
En el siguiente ejemplo se conceden 2 permisos a 2 usuarios en una sola sentencia:
grant create trigger, create procedure
to juan, ana;
Consultando el diccionario "dba_sys_privs" encontramos los privilegios concedidos a los
distintos usuarios; y consultando "user_sys_privs" obtendremos la misma información pero
únicamente del usuario actual.
121 - Privilegios del sistema (conceder)
Primer problema:
Una escuela necesita crear 3 usuarios diferentes en su base de datos. Uno denominado "director",
otro "profesor" y otro "estudiante". Luego se les concederán diferentes permisos para retringir el
acceso a los diferentes objetos. Conéctese como administrador (por ejemplo "system").
1- Cree un usuario denominado "director", con contraseña "escuela", asignándole 100M de
espacio en "system" (100M). Antes elimínelo por si existe:
2- Intente iniciar una sesión como "director".
No es posible, no hemos concedido el permiso correspondiente. Aparece un mensaje indicando
que el usuario "director" no tiene permiso "create session" por lo tanto no puede conectarse.
3- Vea los permisos de "director"
No tiene ningún permiso.
4- Conceda a "director" permiso para iniciar sesion y para crear tablas
5- Vea los permisos de "director"
Tiene permiso "create session" y para crear tablas.
6- Inicie una sesión como "director".
7- Como "administrador", elimine los usuarios "profesor" y "alumno", por si existen
8- Cree un usuario denominado "profesor", con contraseña "maestro", asigne espacio en
"system" (100M)
9- Cree un usuario denominado "estudiante", con contraseña "alumno" y tablespace "system" (no
asigne "quota")
10- Consulte el diccionario de datos correspondiente para ver si existen los 3 usuarios creados
11- Conceda a "profesor" y a "estudiante" permiso para conectarse
12- Conceda a "estudiante" permiso para crear tablas
13- Consulte el diccionario de datos "sys_privs" para ver los permisos de los 3 usuarios creados
"director" y "estudiante" tienen permisos para conectarse y para crear tablas, "profesor" tiene
permiso para conectarse.
14- Retome su sesión como "director" y cree una tabla:
create table prueba(
nombre varchar2(30),
apellido varchar2(30)
);
Podemos hacerlo poque "director" tiene el permiso necesario y espacio en "system".
15- Inicie una sesión como "profesor" e intente crear una tabla:
create table prueba(
nombre varchar2(30),
apellido varchar2(30)
);
Mensaje de error "privilegios insuficientes". Esto sucede porque "profesor" NO tiene permiso
para crear tablas.
16- Consulte los permisos de "profesor"
No tiene permiso para crear tablas, únicamente para crear sesión.
17- Cambie a la conexión de administrador y conceda a "profesor" permiso para crear tablas
18- Cambie a la sesión de "profesor" y cree una tabla
Ahora si podemos hacerlo, "profesor" tiene permiso "create table".
19- Consulte nuevamente los permisos de "profesor"
Tiene permiso para crear tablas y para crear sesión.
20- Inicie una sesión como "estudiante" e intente crear una tabla:
create table prueba(
nombre varchar2(30),
apellido varchar2(30)
);
Mensaje de error "no existen privilegios en tablespace SYSTEM". Esto sucede porque
"estudiante", si bien tiene permiso para crear tablas, no tiene asignado espacio (recuerde que al
crearlo no especificamos "quota", por lo tanto, por defecto es cero).
21- Vuelva a la conexión de "administrador" y consulte todas las tablas denominadas
"PRUEBA"
Note que hay una tabla propiedad de "director" y otra que pertenece a "profesor".
Ver solución
122 - Privilegios del sistema (with admin
option)
Hemos aprendido la sintaxis básica para conceder permisos de sistema a los usuarios, mediante
la instrucción "grant".
Agregando a la sentencia "grant", la cláusula "with admin option" concedemos permiso para
ceder a terceros los privilegios de sistema obtenidos. Es decir, la cláusula "with admin option"
permite que el privilegio concedido a un usuario (o rol) pueda ser otorgado a otros usuarios por
el usuario al que estamos asignándoselo; es decir, se concede permiso para conceder el permiso
obtenido, a otros usuarios.
Sintaxis:
grant PERMISODESISTEMA
to USUARIO
with admin option;
En el siguiente ejemplo, concedemos el permiso de crear tablas al usuario "juan" y con "with
admin option", el usuario "juan" podrá conceder este permiso de crear tablas a otros usuarios:
grant create table
to juan
with grant option;
Podemos consultar el diccionario "dba_sys_privs" para encontrar los privilegios concedidos a los
usuarios. Nos mostrará una tabla con las siguientes columnas:
- grantee: el nombre del usuario,
- privilege: el permiso y
- admin_option: si el permiso adquirido puede ser cedido a otros o no, YES o NO.