Documentos de Académico
Documentos de Profesional
Documentos de Cultura
El autor repasa los conceptos, definiciones y reglas del modelo relacional y detalla su utilización
dentro del marco de las herramientas ofrecidas de manera estándar con Oracle Database 12c,
es decir SQL, SQL*PLUS, PL/SQL et Java.
Se estudian las técnicas de programación en PL/SQL, con el objetivo de poder utilizar toda la
potencia del servidor de base de datos Oracle 12c, así como las novedades añadidas en esta
versión : tipo de datos extendidos, uso de una secuencia como valor por defecto de una
columna de tipo clave primaria o identidad, secuencia de nivel de sesión, soporte de
la sintaxis ANSI que permite limitar el número de filas devuelto por una consulta, definición de
una función PL/SQL en la cláusula WITH de una consulta, procedimiento PL/SQL que
devuelve un resultado implícito, etc.
Además de todo esto, este libro presenta la herramienta SQL Developer y el entorno de
desarrollo de aplicaciones Web Oracle Application Express (APEX).
Jérôme GABILLAUD
Jérôme GABILLAUD es ingeniero en informática, consultor y responsable pedagógico en un gran
centro de formación informática. Está especializado en sistemas de acceso a datos y es autor de
numerosos libros sobre este asunto, reconocidos por sus calidades técnicas y pedagógicas.
Introducción
Oracle 12c es un potente sistema de gestión de bases de datos relacionales (RDBMS) que
proporciona, además de un motor de base de datos, numerosas herramientas para el usuario,
el desarrollador y el administrador.
Oracle permite gestionar los datos de una aplicación basándose en una lógica que se ha
convertido en un estándar: el modelo relacional. Los fundamentos de este modelo se
establecieron a principios de los años 70 por E.F. Codd y constituyen una referencia para la
gestión de datos.
La lógica de extracción de los datos de una base de datos estructurada de acuerdo con el modelo
relacional constituye el álgebra relacional. Proporciona a los usuarios un método independiente
del sistema físico para llegar a obtener un resultado.
El SQL es un lenguaje de consulta descriptivo, que se ha adoptado como estándar en todas las
bases de datos que siguen el modelo relacional. Este lenguaje permite realizar todo tipo de
operaciones sobre los datos en cualquier situación en la que se emplee la base de datos.
Con Oracle, se puede asociar al SQL un lenguaje procedimental, el PL/SQL, que añade numerosas
posibilidades para la manipulación de los datos.
Desde la versión 8i, el sistema de gestión de bases de datos de Oracle propone un nuevo método
de gestión de la información en la empresa a través de la implementación del modelo objeto-
relacional. El objetivo de este método es simplificar el modelado de los datos permitiendo el
almacenamiento y la manipulación de nuevos tipos de datos. Estos objetos reutilizables, propios
de cada sector de actividad o de cada empresa, deben permitir un modelado más eficiente.
La implantación de este modelo a través de las extensiones del lenguaje SQL permite una
migración flexible entre el modelo relacional puro de las versiones anteriores y este nuevo
modelo objeto-relacional. Este libro está dedicado al método relacional clásico.
En primer lugar, este libro presenta los conceptos, definiciones y reglas del modelo relacional
(capítulo Modelo relacional) y, a continuación, detalla su uso en el marco del lenguaje SQL
(capítulo SQL). Después de presentar las herramientas ofrecidas de manera estándar con Oracle
Database 12c, SQL*Plus y Oracle SQL Developer (capítulo SQL*Plus y SQL Developer), el libro
aborda el lenguaje PL/SQL (capítulos PL/SQL y PL/SQL en objetos de la base de datos), además
del uso de Java y de XML en la base de datos (capítulos Java y El analizador de XML). Para
terminar, este libro presenta el entorno de desarrollo de aplicación Web Oracle Application
Express (capítulo Application Express).
Gestión de datos
En todas las aplicaciones de gestión es necesario almacenar datos con el fin de reutilizarlos de
diferentes formas según sea preciso. La mayor parte de los sistemas operativos (MS/DOS, UNIX,
VMS, GCOS...) proporcionan herramientas que permiten llevar a cabo este almacenamiento.
Estas aplicaciones de software generan archivos basándose en diferentes principios.
archivo de programa: contiene código que puede ser ejecutado por el sistema operativo.
archivo de texto: contiene caracteres ASCII.
biblioteca de funciones: contiene código ejecutable que puede ser utilizado por un
programa.
archivo de periférico: permite el direccionamiento de los periféricos (UNIX).
archivo de datos: permite almacenar información generada por una aplicación, etc.
Los archivos permanentes contienen los datos básicos de la aplicación. Generalmente, sus
registros están formados por numerosos campos y su tamaño es grande. El tiempo de vida de
estos archivos suele ser largo. Algunos ejemplos de archivos permanentes son los archivos de
clientes, los catálogos de productos y las fichas de empleados.
Los archivos de operación contienen datos que hacen referencia a los archivos permanentes,
aportando información complementaria, en general de carácter puntual. Los registros están
compuestos principalmente por códigos que identifican los registros de los archivos básicos. El
número de registros de estos archivos suele ser elevado, aunque su tiempo de vida es corto.
Dentro de este tipo de archivo se puede citar, por ejemplo, el archivo de pedidos de un
departamento comercial, que almacena los pedidos de un cliente, o las fichas horarias de una
aplicación de gestión de personal, que almacenan el número de horas trabajadas por un
empleado en un determinado puesto de trabajo.
Los archivos de trabajo los crean, generalmente, las aplicaciones. Contienen toda la información
de los archivos permanentes y de los archivos de operación reagrupada en registros compuestos.
Su tiempo de vida es el mismo que el dedicado a su tratamiento. Por regla general, estos archivos
ocupan mucho espacio. En este tipo de archivo se incluyen, por ejemplo, los archivos de edición
o los resultados de las consultas.
Los archivos históricos contienen los datos archivados de forma definitiva. Estos archivos
proceden, después del cálculo o la depuración, de los archivos permanentes y de los archivos de
operación, quedando como registros inactivos o para la realización de estadísticas.
El analista decidirá qué tipo de organización adoptará para los archivos en función del tipo de
archivo, del soporte físico, de la aplicación y, por supuesto, de las restricciones impuestas por
las especificaciones que se le entreguen.
Organización secuencial
El principio de este tipo de organización consiste en generar los registros como series de bytes
estructuradas (mediante caracteres delimitadores o tamaños fijos).
Sin embargo, los archivos no guardan entre sí ningún tipo de relación dentro de la aplicación y
sólo se pueden leer secuencialmente (un byte a continuación del otro).
Este tipo de organización es una mejora de la organización secuencial que añade un archivo de
claves (o de índice) vinculado al archivo secuencial.
Este archivo de índice contiene criterios de búsqueda seleccionados (índice) y la dirección del
dato correspondiente dentro del archivo secuencial.
Son colecciones de archivos relacionados de forma lógica entre sí. Estas bases se crean sobre
sistemas propietarios con el fin de compensar los inconvenientes de los tipos de organización
anteriores, en lo que se refiere a la traducción del diccionario de datos resultante del análisis.
Las ventajas de estas bases de datos son numerosas, destacando los mecanismos de seguridad
para el acceso de los usuarios a la base de datos mediante contraseña, la garantía estructural
de la integridad de los datos o las nuevas posibilidades de lectura de datos gracias a los vínculos
directos entre registros de archivos diferentes (lecturas encadenadas).
Estos sistemas también presentan importantes inconvenientes, entre los que se pueden destacar
la complejidad de mantenimiento y de uso, los requisitos elevados de espacio en disco, memoria
y tiempo de procesador y, por último, la dependencia de estas bases de datos con respecto al
sistema operativo.
El modelo relacional
Una base de datos relacional es una colección de datos relacionados mediante tablas lógicas,
siendo una tabla un conjunto de filas y columnas.
El éxito de los sistemas RDBMS procede fundamentalmente de esta característica. Con estos
sistemas, el usuario solamente gestiona el nivel lógico, lo que proporciona una gran simplicidad
a la gestión de los datos, incluso en el caso de usuarios con pocos conocimientos informáticos.
1. Conceptos y definiciones
El modelo relacional se basa en conceptos básicos sencillos (dominio, relación, atributo) a los
que se aplican reglas precisas.
a. Dominio
Cardinalidad
Es el número de elementos de un dominio.
Ejemplo
El diccionario de datos del análisis de una aplicación de gestión comercial puede incluir, entre
otras cosas, especificaciones sobre la gestión de los estados de los pedidos o los números de
orden que se deseen visualizar. El modelo relacional traducirá estas especificaciones del siguiente
modo:
b. Producto cartesiano
El producto cartesiano P entre varios dominios D1, D2, ..., Dn se expresa como P = D1 X D2 X
... X Dn y es el conjunto de las n tuplas (d1, d2, ..., dn) donde cada "di" es un elemento del
dominio Di.
Ejemplo
Si se desean generar dos dominios (códigos e impuestos), se pueden obtener parejas formadas
por un código y un impuesto.
Codigos = {1,2,3,4}
IVA = {0,4,16}
Codigos X IVA ={(1,0),(1,4),(1,16),
(2,0),(2,4),(2,16),(3,0),(3,4),(3,16),
(4,0),(4,4),(4,16)}
c. Relación
Una relación definida sobre los dominios D1, D2, ..., Dn es un subconjunto del producto
cartesiano de estos dominios, caracterizado por un nombre.
Atributo
Grado
Ejemplo
Para asociar un único tipo de impuesto a cada código, sólo deben considerarse tres parejas.
O de forma declarativa:
2. Principales reglas
Por tanto, el objeto principal gestionado por el modelo relacional es la relación, que está asociada
a los conceptos de dominio y de atributo.
A esta relación se le aplican reglas con el fin de satisfacer las restricciones identificadas en el
análisis.
Coherencia
Todo valor tomado por un atributo debe pertenecer al dominio sobre el que está definido.
Unicidad
Identificador
Atributo o conjunto de atributos que permiten caracterizar de forma unívoca cada elemento de
la relación.
Clave primaria
Claves secundarias
Integridad referencial
Esta regla impone que un atributo o conjunto de atributos de una relación aparezca como clave
primaria en otra relación.
Clave externa
Ejemplo
El análisis de una aplicación de gestión comercial requiere gestionar una serie de clientes que
tienen unas determinadas características (nombre y dirección) y los pedidos que realicen dichos
clientes.
CLIENTES (NUMEROCLI,NOMBRECLI,DIRECCLI)
PEDIDOS (NUMEROPED,FECHAPED,NUMEROCLI,ESTADOPED)
Valor nulo
Restricción de entidad
Cualquier valor que forme parte de una clave primaria debe ser diferente a NULL.
Ejemplo
En la relación de artículos se admite que el precio o el código de IVA sean desconocidos, pero la
referencia del artículo (clave primaria) debe especificarse.
Álgebra relacional
Se trata de un método de extracción de datos que permite manipular tablas y columnas. Su
principio se basa en la creación de tablas nuevas (tablas de resultados) a partir de las tablas
existentes; estas tablas nuevas serán objetos que podrán emplearse de forma inmediata.
Los operadores del álgebra relacional que permiten crear tablas de resultados se basan en la
teoría de conjuntos.
1. Operadores
a. Unión
La unión entre dos relaciones con la misma estructura (grado y dominios) proporciona una tabla
resultante con la misma estructura y cuyos elementos son el conjunto de los elementos
diferentes de las dos relaciones iniciales.
Notación : Rx = R1 R2
Ejemplos
CLIENTES=CLIOESTE CLICENTRO
b. Intersección
La intersección entre dos relaciones de la misma estructura (grado y dominios) proporciona una
tabla resultante de la misma estructura y cuyos elementos son el conjunto de los elementos
comunes a ambas relaciones iniciales.
Notación: Rx = R1 R2
Ejemplo
CLICOMUN=CLIOESTE CLICENTRO
c. Diferencia
La diferencia entre dos relaciones con la misma estructura (grado y dominios) proporciona una
tabla resultante con la misma estructura y cuyos elementos son el conjunto de los elementos de
la primera relación que no se encuentran en la segunda relación.
Notación: Rx = R1 - R2
Ejemplo
d. Restricción
La restricción de acuerdo con una condición produce, a partir de una relación, otra relación con
el mismo esquema y que solo contiene los elementos de la relación inicial que cumplen la
condición.
Notación: Rx = σ (condición) R1
Ejemplos
Clientes de ORENSE:
CLIORENSE=σ(DIRECCION="ORENSE")CLIOESTE
Alfombras "baratas":
ART2=σ(PRECIO<=1000)ART1
e. Proyección
La proyección de una relación sobre un grupo de atributos da lugar a una relación resultante que
tiene como esquema solamente dichos atributos y como elementos las distintas n-tuplas
compuestas por los valores asociados a dichos atributos.
Ejemplos
PED= π PEDIDOS(NUMEROPED,NUMEROCLI,ESTADOPED)
CLIPED1= π PEDIDOS(NUMEROCLI)
CLIPED2= π PEDIDOS(NUMEROCLI,ESTADOPED)
f. Producto cartesiano
El producto cartesiano de dos relaciones da como resultado una relación que tiene como esquema
todos los atributos de las dos relaciones existentes y como elementos la asociación de cada línea
de la primera tabla con cada línea de la segunda tabla.
Notación: Rx = S1 X S2
Ejemplo
g. Combinaciones
La combinación entre dos relaciones de acuerdo a una condición se obtiene aplicando una
restricción al producto cartesiano.
Ejemplo
Combinación-theta
Equi-combinación
Combinación natural
Proyección sobre una relación asociada a un cálculo que se realiza sobre cada línea para crear
uno o varios atributos nuevos.
Ejemplo
LINEAPEDIMP = π LINEAPED(NUMPED,NUMLIN,REFART,
IMPLINEA=CANTPED*PRECSINIVA)
Proyección sobre una relación asociada con uno o varios valores agregados que se calculan sobre
un atributo para todos los elementos de la relación o de la agrupación vinculada a la proyección,
con el fin de crear uno o varios atributos nuevos.
Ejemplos
NUMCLIENTES=π CLIENTES(N=COUNT(*))
Total de los importes de línea por pedido:
PEDVALOR=π LINEAPEDIMP(NUMPED,TOTPED=SUM(IMPLINEA))
Precios más altos, más bajos y el precio medio por cada categoría de artículo:
STATART=π ARTICULOS(CATEGORIA,MASCARO=MAX(PRECIO),
MASBARATO=MIN(PRECIO),MEDIO=AVG(PRECIO))
La vista es una relación intermedia que contiene todos los atributos que permiten realizar la
extracción de datos, con sus relaciones de origen, sus clases de atributos y las operaciones que
hay que aplicar.
Clases de atributos
1 Relaciones implicadas.
3 Combinaciones, Productos cartesianos, Uniones, Intersecciones, Diferencias (para asociar las filas
restantes).
6 Combinación entre la tabla obtenida en el punto 5 y la tabla inicial del punto 4 (para añadir las
columnas agregadas a las restantes).
Ejemplo
CLIENTES (NUMCLI,NOMCLI,DIRECCION)
ARTICULOS (REFART,DESCRIPCION,PRECSINIVA)
PEDIDOS (NUMPED,NUMCLI,FECHAPED,ESTADOPED)
LINEASPED (NUMPED,NUMLIN,REFART,CANTPED)
CONFPED (NUMPED,FECHAPED,NOMCLI,DIRECCION,REFART,
DESCRIPCION,PRECSINIVA,CANTPED,IMPSINIVA,TOTSINIVA)
Vista
Operaciones
T1=σ(NUMPED=1301) PEDIDOS
T2=σ(NUMPED=1301) LINEASPED
Proyección del campo calculado elemental IMPSINIVA y eliminación de las columnas no útiles:
T6=π T5(NUMPED,FECHAPED,NOMCLI,DIRECCION,REFART,
DESCRIPCION,PRECSINIVA,CANTPED,IMPSINIVA=PRECSINIVA*CANTPED)
T7=πT6(NUMPED,TOTSINIVA=SUM(IMPSINIVA))
Fue desarrollado a mediados de los años 70 por IBM y lo comenzó a comercializar Oracle en
1979.
Normalización
Estándar
Debido a esta normalización, la mayor parte de los creadores de sistemas de bases de datos
relacionales integran el SQL en sus productos (INFORMIX, DB2, MS SQL Server, SYBASE...).
Los datos, consultas y aplicaciones pueden por tanto migrarse con bastante facilidad de una base
de datos a otra.
No procedimental
El SQL es un lenguaje de consulta que permite al usuario solicitar un resultado sin preocuparse
de los medios técnicos necesarios para obtener dicho resultado. Un componente del motor de la
base de datos (el optimizador) se encarga de esta tarea.
Universal
El lenguaje SQL puede utilizarse en todos los niveles de la gestión de una base de datos:
Todos los usuarios de la base de datos disponen por tanto de un lenguaje común.
consultar datos,
añadir, eliminar y modificar datos,
gestionar objetos (estructuras),
gestionar los mecanismos de seguridad de acceso a los datos.
1. Componentes de la base de datos lógica: los objetos SQL
Una base de datos relacional está formada por entidades lógicas o físicas que el lenguaje SQL
puede manipular. Estas entidades se denominan objetos SQL.
índice (index) Columna o conjunto de columnas que permiten realizar búsquedas más
rápidamente.
vista (view) Consulta que puede manipularse como una tabla (tabla virtual).
instantáneas (snapshots) Tabla que contiene el resultado de una consulta realizada sobre una
tabla creada en una base de datos remota.
c. Almacenamiento de instrucciones
esquema (schema) Conjunto de objetos de la base de datos lógica que pertenecen a un
mismo usuario.
disparador de base de datos Fragmento de código procedimental asociado con una tabla.
(database trigger)
usuario (user) Individuo que puede conectarse y acceder a los recursos de la base de datos.
Los objetos creados por los usuarios del sistema de gestión de bases de datos relacionales
(RDBMS) de Oracle deben tener un nombre.
Deben tener una longitud de 1 a 30 caracteres, excepto la base de datos (8) y los enlaces
de base de datos (128).
No se distingue entre mayúsculas y minúsculas.
Deben comenzar por una letra.
Pueden emplearse los caracteres alfanuméricos + _ $ y # (además de @ y . para los
enlaces de base de datos).
No deben utilizarse palabras reservadas para designar objetos.
Deben ser unívocos en el esquema de un usuario, incluso cuando se trate de tipos de
objetos diferentes.
Convenciones
Es aconsejable emplear nombres idénticos para designar las mismas entidades en objetos
diferentes de la base de datos (nombres de columnas).
Cuando los nombres de los objetos se especifican sin comillas, Oracle no tiene en cuenta que se
usen mayúsculas o minúsculas (los nombres se almacenan en mayúsculas al crearse los objetos
y después, cuando se hace referencia a ellos, Oracle realiza automáticamente la conversión a
mayúsculas).
Sin embargo, los nombres de los objetos pueden especificarse entre comillas dobles. En este
caso, Oracle utiliza las mayúsculas y minúsculas empleadas en el nombre escrito entre comillas
para hacer referencia al objeto. No es recomendable utilizar esta posibilidad, ya que la escritura
se hace más pesada y los riesgos de cometer errores de sintaxis aumentan.
2. Categorías de instrucciones
Las instrucciones DDL son: CREATE, ALTER, DROP, GRANT, REVOKE, AUDIT, NOAUDIT,
ANALYZE, RENAME, TRUNCATE, COMMENT, FLASHBACK y PURGE.
Las instrucciones DML son: INSERT, UPDATE, DELETE, SELECT, EXPLAIN PLAN, LOCK TABLE y
MERGE.
Las instrucciones del TCL son: COMMIT, SAVEPOINT, ROLLBACK, SET TRANSACTION y SET
CONSTRAINT.
d. SCL (Session Control language)
e. Embedded SQL
Las instrucciones del SQL embebido son: DECLARE, TYPE, DESCRIBE, VAR, CONNECT, PREPARE,
EXECUTE, OPEN, FETCH, CLOSE, WHENEVER.
Descripción de objetos
Cuando se emplea una base de datos, los primeros objetos que hay que manipular son las tablas,
que "contienen" los datos, y los índices, que permiten obtener un mejor rendimiento de las
consultas.
Estos dos tipos de objetos se deben crear antes de comenzar a manipular los datos en sí.
1. Tipos
CHAR (n)
VARCHAR2 (n)
NCHAR (n)
NUMBER (p,s)
Número con una precisión de p cifras, de las cuales s son decimales, siendo (1 <= p <= 38 y -
84 <= s <= +127).
DATE
TIMESTAMP (p)
Datos de tipo Date (año, mes, día, hora, minutos y segundos) en los que es posible especificar,
con una precisión p, el número de cifras significativas para las fracciones de segundo. El valor
predeterminado es 6.
Datos de tipo TIMESTAMP WITH TIME ZONE que están almacenados en el servidor teniendo en
cuenta la zona horaria del mismo, pero que se muestran en el equipo del cliente teniendo en
cuenta la zona horaria definida en el nivel de sesión.
BLOB
Datos binarios no estructurados (hasta 128 TB como máximo, dependiendo del tamaño del
bloque utilizado en la base de datos).
CLOB
Cadena de caracteres de longitud variable (hasta 128 TB como máximo, dependiendo del
tamaño del bloque utilizado en la base de datos). Solo puede contener caracteres codificados
con 1 byte.
NCLOB
Cadena de caracteres de longitud variable (hasta 128 TB como máximo, dependiendo del
tamaño del bloque utilizado en la base de datos). Tiene en cuenta los juegos de caracteres de
longitud variable.
BFILE
Datos binarios almacenados en archivos externos a la base de datos (hasta 264-1 bytes,
excepto si existe alguna limitación por parte del sistema operativo).
LONG
RAW (n)
Datos binarios de longitud variable (n bytes como máximo; n < = 2000 si el argumento
MAX_STRING_SIZE es igual a STANDARD; n <= 32767 si el argumento MAX_STRING_SIZE es
igual a EXTENDED); cuyo contenido no es interpretado por Oracle.
Desde la version 12, el tamaño máximo posible de una cadena de caracteres de tipo
[N]VARCHAR2 es de 32.767 bytes (4.000 bytes en las versiones anteriores). Para usar esta
funcionalidad, el argumento de inicio MAX_STRING_SIZE debe ser igual a EXTENDED; por
defecto, es igual a STANDARD y se aplica el antiguo.
Esta funcionalidad se puede activar en una nueva base de datos definiendo el argumento
MAX_STRING_SIZE con el valor EXTENDED durante la creación de la misma. También se puede
activar en una base de datos existente (consulte la descripción del argumento
MAX_STRING_SIZE en la documentación Oracle® Database Reference para el modo operativo).
Por el contrario, no es posible usar el valor del argumento MAX_STRING_SIZE igual a EXTENDED
con valor STANDARD.
De manera interna, los tipos de datos extendidos se almacenan de manera transparente bajo la
forma de LOB, que no se pueden manipular directamente.
Una tabla es un conjunto de filas y columnas. La creación consiste en definir (en función del
análisis realizado) el nombre de las columnas, su formato (type, el tipo), un valor
predeterminado (DEFAULT) para cuando se crea la fila y las reglas de gestión que se aplican a
la columna (CONSTRAINT). Si una regla de gestión afecta a varias columnas de la fila, se define
una restricción de tabla.
Sintaxis
DEFAULT
El valor por defecto solo se usa cuando la columna no está en una operación INSERT.
La cláusula ON NULL, que apareció en la versión 12, permite especificar que el valor por defecto
también se debe usar si un valor NULL se asigna a la columna en una operación INSERT. El valor
por defecto de la columna también se puede asignar explícitamente a la columna en una
operación INSERT o UPDATE con la palabra clave DEFAULT ().
Desde la versión 12, el valor por defecto de una columna puede hacer referencia a una secuencia
con las pseudo-columnas nomseq.NEXTVAL y nomseq.CURRVAL; la secuencia debe haberse
definido previamente (consulte la sección SQL avanzado en este capítulo).
a. Restricciones de columna
NULL/NOT NULL
Autoriza (NULL) o prohíbe (NOT NULL) la inserción del valor NULL en un atributo.
PRIMARY KEY
Designa al atributo como clave primaria de la tabla. Esta restricción solo puede aparecer una
vez en la instrucción.
UNIQUE
Designa el atributo como clave secundaria de la tabla. En el caso de que la restricción UNIQUE
se aplique a una única columna, el atributo puede tomar el valor NULL. Esta restricción puede
aparecer varias veces en la instrucción.
CHECK (condición)
Verifica, al insertar filas, que el atributo cumple la condición especificada (consulte la sección
Manipulación de los datos para ver la sintaxis de la condición).
Preste atención, en una restricción CHECK no es posible hacer referencia a la función SYSDATE
o bien CURRENT_DATE para comparar el valor de una columna de tipo fecha con el resultado de
la ejecución de esta función. Sin embargo, sí es posible, si así se desea, comparar mediante una
restricción CHECK los valores de dos columnas de tipo fecha.
Si se quiere comparar el valor de una columna de tipo fecha con la fecha actual es necesario
implementar un disparador (trigger) de base de datos. Otra posibilidad consiste en crear una
columna de tipo fecha con un valor predeterminado igual a la fecha del día más una restricción
CHECK que compare los valores presentes en las dos columnas.
Designa la concatenación de los atributos citados como clave primaria de la tabla. Esta
restricción no puede aparecer más de una vez en la instrucción.
UNIQUE (columna,...)
CHECK (condición)
Esta restricción permite expresar una condición que debe cumplirse para una serie de atributos
de la fila (consulte la sección Manipulación de los datos para ver la sintaxis de la condición).
Las restricciones de tabla se aplican a varias columnas de la tabla sobre la que están definidas.
No es posible definir una restricción de integridad utilizando columnas procedentes de dos o más
tablas. Este tipo de restricción se implementará mediante de disparadores (triggers) de la base
de datos, cuya definición se verá más adelante en el libro.
ON DELETE CASCADE
[NOT] DEFERRABLE
Es posible asignar un nombre a las restricciones con el fin de poder después manipularlas más
fácilmente (activación y eliminación). En el caso de que no se asigne explícitamente un nombre
a una restricción, Oracle genera automáticamente un nombre de la forma SYS_Cn (n es un
número entero exclusivo).
A la hora de asignar explícitamente un nombre a una restricción, resulta útil emplear el siguiente
convenio de nomenclatura:
Tabla_Columna_TipoDeRestriccion
Ejemplos
Creación de una tabla ARTICULOS con una sola restricción de clave primaria REFART:
Tabla creada.
SQL>
En este caso, DESCRIPCION, PRECIO y CANTALM pueden ser NULL: PRECIO y CANTALM pueden
tomar valores negativos.
Tabla creada.
SQL>
Creación de la tabla de pedidos utilizando una sintaxis de tipo restricción de tabla para definir
las restricciones de integridad.
Tabla creada.
SQL>
Creación de la tabla LINPED con restricciones de referencia sobre las columnas y una restricción
de tabla para la clave primaria:
Tabla creada.
SQL>
Sea cual sea el modo de definición de las restricciones (a nivel de columna o de tabla), el
resultado es el mismo. Solo las restricciones de integridad que se aplican a varias columnas de
la misma tabla deben obligatoriamente definirse empleando una sintaxis de restricción de tabla.
e. La columna virtual
Una columna virtual es una columna definida por una expresión que se evalúa cada vez que se
produce una consulta; no se almacena ningún valor en la tabla para la columna en cuestión. Esta
funcionalidad es nueva a partir de la versión 11.
Sintaxis
nombrecolumna [tipo] [GENERATED ALWAYS] AS (expresión) [VIRTUAL]
[restricción_de_columna]
El tipo de datos es opcional; si no se especifica, Oracle lo determina a partir del tipo de datos de
la expresión.
Las palabras reservadas GENERATED ALWAYS y VIRTUAL son opcionales; pueden especificarse
para hacer la sintaxis más clara.
Ejemplo
SQL>
SQL> insert into ARTICULOS (REFART, DESCRIPCION, PRECSINIVA, IVA)
2 values (’XT10’,’Paquete de 10 lápices’,10,21);
1 fila creada.
SQL>
SQL> insert into ARTICULOS (REFART, DESCRIPCION, PRECSINIVA, IVA)
2 values (’AD23’,’Los Tres Mosqueteros’,10,4);
1 fila creada.
SQL>
SQL> select DESCRIPCION, PRECSINIVA, PRECCONIVA from ARTICULOS;
DESCRIPCION PRECSINIVA PRECCONIVA
------------------------- ------------- ---------------
Paquete de 10 lápices 10 12,10
Los Tres Mosqueteros 10 10,40
Una columna de tipo identidad es una columna numérica entera a la que se asigna
automáticamente un valor creciente (o decreciente) durante un INSERT. De manera interna,
Oracle utiliza une secuencia para generar el número (consulte la sección SQL avanzado en este
capítulo). Esta funcionalidad apareció en la versión 12.
Sintaxis
La cláusula BY DEFAULT permite al usuario asignar un valor (no NULL) a la columna en un INSERT
o un UPDATE; en ambos casos la asignación de un valor NULL genera un error. La cláusula ON
NULL permite especificar que la identidad también se debe usar si un valor NULL se asigna a la
columna en un INSERT.
La cláusula options permite especificar las características de la secuencia que usa Oracle para
generar el valor. Esta cláusula ofrece las mismas opciones que CREATE SEQUENCE (consulte la
sección SQL avanzado en este capítulo).
Solo se puede definir una única columna de tipo identidad en una tabla.
La columna de tipo identidad debe ser de tipo numérico.
Una columna de tipo identidad no puede tener valor por defecto.
La columna de tipo identidad es obligatoria (restricción NOT NULL implícita).
Ejemplo
Tabla creada.
SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);
1 fila creada.
1 fila creada.
NOCAT NOMBRE
---------- ---------------
1 Informática
2 Bricolaje
SQL>
SQL> -- Prohibición de asignar un valor a la columna en un INSERT o UPDATE.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (123,’Libros’);
insert into CATEGORIAS (NOCAT,NOMBRE)
*
ERROR en la línea 1:
ORA-32795: imposible insertar el valor en una columna
de identidad con las palabras reservadas GENERATED ALWAYS
Tabla eliminada.
Tabla creada.
SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);
1 fila creada.
1 fila creada.
NOCAT NOMBRE
---------- ---------------
1 Informática
2 Bricolaje
SQL>
SQL> -- Ahora es posible asignar un valor (no NULL) a la columna en un INSERT
SQL> -- o UPDATE.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (123,’Libros’);
1 fila creada.
1 fila modificada.
NOCAT NOMBRE
---------- ---------------
456 Informática
2 Bricolaje
123 Libros
SQL>
SQL> -- Pero no es posible asignar un valor NULL.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (null,’Maletas’);
values (null,’Maletas’)
*
ERROR en la línea 2:
ORA-01400: imposible insertar NULL en ("ENI"."CATEGORIAS"."NOCAT")
SQL>
SQL> -- Recreación de la tabla con la opción BY DEFAULT ON NULL.
SQL> drop table CATEGORIAS;
Tabla eliminada.
Tabla creada.
SQL>
SQL> -- La identidad se usa ahora durante la asignación de un valor NULL
SQL> -- a la columna en un INSERT.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (null,’Maletas’);
1 fila creada.
NOCAT NOMBRE
---------- ---------------
1 Maletas
g. Columna invisible
Desde la version 12, una columna se puede declarar invisible. Una columna como esta solo es
visible si se especifica explícitamente en una sentencia SQL. Las columnas invisibles no se
muestran con la sentencia SQL SELECT * o con el comando SQL*Plus DESCRIBE.
Sintaxis
La cláusula INVISIBLE permite declarar una columna invisible. Por defecto, las columnas de una
tabla son visibles (cláusula VISIBLE).
Exemplo
Table creada.
SQL>
SQL> -- Un INSERT sin enumeración explícita de columnas funciona
SQL> -- como si la columna no existiera.
SQL> insert into CATEGORIAS
2 values (1,’Informática’);
1 fila creada.
1 fila creada.
SQL>
SQL> -- Un SELECT * no muestra la columna invisible.
SQL> select * from CATEGORIAS;
NOCAT NOMBRE
---------- ---------------
1 Informática
2 Libros
SQL>
SQL> -- Es necesario seleccionarla explícitamente para verla.
SQL> select NOCAT,NOMBRE,RESPONSABLE from CATEGORIAS;
Para borrar una tabla es necesario eliminar su estructura y todos los datos que contenga. Los
índices asociados también se borran; las vistas creadas directa o indirectamente sobre esta tabla
las desactiva automáticamente Oracle.
La cláusula PURGE permite borrar la tabla y liberar el espacio físico que ocupaba. Si no se
encuentra esta cláusula, la tabla se borra lógicamente pero no físicamente. Esto permite utilizar
la instrucción FLASHBACK TABLE para recuperar la tabla y sus datos en el momento del borrado.
Con este principio de funcionamiento, Oracle permite dejar de hacer definitiva una acción de
eliminación de una tabla y facilita así la restauración de las tablas suprimidas por error.
Sintaxis
Ejemplo
Eliminación de la tabla CLIENTES cuya columna NUMCLI es una clave externa en la tabla
PEDIDOS:
Tabla borrada.
Table dropped.
SQL>
Sintaxis
Ejemplo
Tabla modificada.
Tabla modificada.
SQL> describe CLIENTES
Nombre Nulo? Tipo
----------------------------------------- -------- ------------
NUMCLI NOT NULL NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
DIRECCLI CHAR(30)
COD_POSTAL NUMBER(5)
CIUDAD CHAR(30)
TEL CHAR(14)
SQL>
SQL> alter table CATEGORIAS add (RESPONSABLE varchar2(30)
invisible default ’Ángel’);
Tabla modificada.
También es posible añadir o modificar una columna virtual usando la misma sintaxis que para la
creación de la tabla.
Ejemplo
Tabla modificada.
Tabla modificada.
De la misma manera, es posible añadir o modificar una columna de tipo identidad usando la
misma sintaxis que para la creación de la tabla, y eliminar la propiedad de tipo identidad de una
columna. Por el contrario, no es posible añadir la propiedad de tipo identidad a una columna
existente.
Ejemplo
Tabla modificada.
SQL> alter table CATEGORIAS modify (NOCAT drop identity);
Tabla modificada.
Sintaxis
La sintaxis de declaración de restricciones es idéntica a la que se utiliza para crear una tabla.
Ejemplo
Tabla modificada.
SQL>
Es posible definir una restricción de tipo NOT NULL mediante el comando ALTER TABLE.
La tabla en la que se almacenarán las referencias de las filas que impiden la creación de la
restricción de integridad puede crearse mediante el script utlexcpt.sql (uso del identificador de
fila físico) o utlexpt1.sql (uso del identificador de fila universal) almacenado en el directorio
ORACLE_HOME\ rdbms\admin.
Tabla creada.
SQL>
Incluye en la tabla de excepciones las referencias de las filas que plantean problemas.
SQL>
Ahora es necesario emplear los identificadores de fila para saber qué filas impiden añadir la
restricción.
El siguiente fragmento de código enumera los números de cliente que poseen la misma dirección:
NUMCLI DIRECCLI
---------- ------------------------------
152 C/ Portugal,26
100 C/ Portugal,26
SQL>
Añadir una restricción sobre las tablas existentes es un método práctico porque, asociado a la
creación de tablas, permite producir scripts de creación de tablas sin fijar un orden de creación
que tenga en cuenta las restricciones de clave externa y de clave primaria.
Sintaxis
Ejemplo
Tabla modificada.
SQL>
El comando ALTER TABLE también permite activar y desactivar las restricciones de integridad.
Esta operación puede resultar interesante al realizar una importación masiva de datos con el fin
de, por ejemplo, limitar el tiempo necesario para llevar a cabo dicha importación.
Sintaxis
ENABLE VALIDATE
ENABLE NOVALIDATE
Activa la restricción para las siguientes instrucciones de manipulación de datos (no verifica los
datos actuales).
DISABLE
Desactiva la restricción.
También es posible trabajar con restricciones de clave primaria y UNIQUE proporcionando
simplemente la definición de la restricción.
Ejemplo
Tabla modificada.
ERROR en línea 2:
ORA-02293: no se puede validar
[CLIENTES_COD_POSTAL_CK] - restricción de control violada
SQL>
Sintaxis
DEFERRABLE
La validación de la restricción puede realizarse al finalizar la transacción.
NOT DEFERRABLE
La restricción se verifica al completar cada instrucción DML. Esta opción está activada de
manera predeterminada.
INITIALLY IMMEDIATE
INITIALLY DEFERRED
Implica que la restricción está en modo DEFERRABLE y que, de manera predeterminada, esta
restricción se verifique únicamente al completarse la transacción.
RELY o NORELY
El valor RELY permite indicar que Oracle puede tener en cuenta una restricción en modo
NOVALIDATE, para la reescritura de una consulta (query rewrite). El valor por defecto es
NORELY.
USING INDEX
Permite especificar los parámetros de los índices utilizados para establecer las restricciones de
clave primaria y de unicidad.
Ejemplo
Tabla modificada.
SQL>
f. Eliminación de columnas
Se puede eliminar una columna utilizando la cláusula DROP COLUMN de la instrucción ALTER
TABLE. Esta operación permite recuperar el espacio en disco ocupado por cada columna
eliminada.
Sintaxis
ALTER TABLE nombre_tabla DROP COLUMN nombre_columna;
Ejemplo
Tabla modificada.
SQL>
Eliminar columnas en una tabla que posea muchas filas puede resultar una operación muy larga.
En ocasiones, es más adecuado hacer simplemente que la columna no pueda utilizarse, mediante
la cláusula SET UNUSED. Esta opción no permite liberar el espacio en disco ocupado por la
columna, pero sí permite planificar la operación de eliminación de la columna para el momento
en que la carga de trabajo en el servidor sea menor.
Sintaxis
Ejemplo
Convertir la columna TEL de la tabla CLIENTES en una columna no utilizable. Para ello, primero
se marca la columna como no utilizable.
Tabla modificada.
SQL>
SQL>
Para saber qué tablas contienen columnas que no se pueden utilizar, es necesario consultar la
vista del diccionario de datos denominada USER_UNUSED_COL_TABS.
SQL>
La instrucción RENAME permite cambiar el nombre de una tabla, así como de las vistas,
secuencias y sinónimos privados.
Los sinónimos públicos no pueden cambiar de nombre; deben eliminarse y crearse de nuevo.
Sintaxis
Ejemplo
SQL>
h. Hacer una tabla accesible sólo en modo lectura, o en modo lectura y escritura
A partir de la versión 11, es posible hacer una tabla accesible únicamente en modo lectura para
impedir cualquier modificación de datos en la tabla y posteriormente hacerla de nuevo accesible
en modo lectura y escritura.
Sintaxis
Ejemplo
Tabla modificada.
Tabla modificada.
2 registro(s) eliminado(s).
La estructura de una tabla en modo de solo lectura no puede modificarse (agregar, modificar o
eliminar columnas). En cambio, una tabla en modo de solo lectura puede eliminarse (DROP
TABLE).
La instrucción FLASHBACK TABLE permite restaurar de forma automática una tabla modificada
de forma accidental. El lapso de tiempo durante el que es posible volver a la versión anterior de
la tabla es función del espacio de anulación reservado por la base de datos.
Esta instrucción permite anular el borrado de una tabla efectuado con la instrucción DROP TABLE.
Sintaxis
Ejemplo
En el ejemplo siguiente, la tabla linped se borra por error y se restaura mediante la acción de la
instrucción FLASHBACK TABLE:
Table dropped.
Flashback complete.
SQL>
La instrucción FLASHBACK TABLE permite anular las modificaciones efectuadas por las
instrucciones INSERT, UPDATE o DELETE en una tabla. Es posible incluso restaurar los datos de
una o más tablas hasta una fecha y hora concretas.
Para poder aprovechar esta funcionalidad, la tabla debe estar configurada para tener en cuenta
los movimientos de filas en la tabla. Es posible activar esta opción al crear la tabla, utilizando la
cláusulaenable row movement, o bien al modificar la tabla.
Sintaxis
Ejemplo
Table altered.
SQL>
En el ejemplo siguiente, los clientes cuyo nombre empieza por E se han borrado por error. La
transacción ahora se valida y los datos modificados son visibles para todos los usuarios.
2 rows deleted.
SQL> commit;
Commit complete.
SQL>
Afortunadamente, el usuario ha anotado la hora en la que se ha ejecutado esta operación
equivocada. De este modo, es posible restaurar los datos borrados sin tener que hacer una
restauración completa de la base de datos.
flashback complete.
COUNT(*)
---------------
7
SQL>
6. Gestion de índices
Los índices sirven para mejorar el rendimiento de las consultas. El optimizador de consultas de
Oracle los utiliza implícitamente y se actualizan de forma automática al actualizar las filas.
En general, los índices se crean sobre todas las claves externas y sobre los criterios de búsqueda
actuales. Es posible indexar una columna virtual o invisible.
Los índices que afectan a las claves primarias y secundarias (índice UNIQUE) se crean
automáticamente en el momento de la creación de la restricción, utilizando como nombre el
nombre de la restricción. Para crear otros índices hay que utilizar la instrucción CREATE INDEX.
Sintaxis
Ejemplos
Índice creado.
Índice creado.
b. Eliminación de un índice
Sintaxis
Existen índices de diferentes tipos que tienen una incidencia directa sobre la organización física
de los datos y estas opciones incumben a la administración.
Descripción de objetos
Cuando se emplea una base de datos, los primeros objetos que hay que manipular son las tablas,
que "contienen" los datos, y los índices, que permiten obtener un mejor rendimiento de las
consultas.
Estos dos tipos de objetos se deben crear antes de comenzar a manipular los datos en sí.
1. Tipos
CHAR (n)
NCHAR (n)
NVARCHAR2 (n)
NUMBER (p,s)
Número con una precisión de p cifras, de las cuales s son decimales, siendo (1 <= p <= 38 y -
84 <= s <= +127).
DATE
TIMESTAMP (p)
Datos de tipo Date (año, mes, día, hora, minutos y segundos) en los que es posible especificar,
con una precisión p, el número de cifras significativas para las fracciones de segundo. El valor
predeterminado es 6.
Datos de tipo TIMESTAMP WITH TIME ZONE que están almacenados en el servidor teniendo en
cuenta la zona horaria del mismo, pero que se muestran en el equipo del cliente teniendo en
cuenta la zona horaria definida en el nivel de sesión.
BLOB
Datos binarios no estructurados (hasta 128 TB como máximo, dependiendo del tamaño del
bloque utilizado en la base de datos).
CLOB
Cadena de caracteres de longitud variable (hasta 128 TB como máximo, dependiendo del
tamaño del bloque utilizado en la base de datos). Solo puede contener caracteres codificados
con 1 byte.
NCLOB
Cadena de caracteres de longitud variable (hasta 128 TB como máximo, dependiendo del
tamaño del bloque utilizado en la base de datos). Tiene en cuenta los juegos de caracteres de
longitud variable.
BFILE
Datos binarios almacenados en archivos externos a la base de datos (hasta 264-1 bytes,
excepto si existe alguna limitación por parte del sistema operativo).
LONG
RAW (n)
Datos binarios de longitud variable (n bytes como máximo; n < = 2000 si el argumento
MAX_STRING_SIZE es igual a STANDARD; n <= 32767 si el argumento MAX_STRING_SIZE es
igual a EXTENDED); cuyo contenido no es interpretado por Oracle.
Desde la version 12, el tamaño máximo posible de una cadena de caracteres de tipo
[N]VARCHAR2 es de 32.767 bytes (4.000 bytes en las versiones anteriores). Para usar esta
funcionalidad, el argumento de inicio MAX_STRING_SIZE debe ser igual a EXTENDED; por
defecto, es igual a STANDARD y se aplica el antiguo.
Esta funcionalidad se puede activar en una nueva base de datos definiendo el argumento
MAX_STRING_SIZE con el valor EXTENDED durante la creación de la misma. También se puede
activar en una base de datos existente (consulte la descripción del argumento
MAX_STRING_SIZE en la documentación Oracle® Database Reference para el modo operativo).
Por el contrario, no es posible usar el valor del argumento MAX_STRING_SIZE igual a EXTENDED
con valor STANDARD.
De manera interna, los tipos de datos extendidos se almacenan de manera transparente bajo la
forma de LOB, que no se pueden manipular directamente.
2. Creación de una tabla
Una tabla es un conjunto de filas y columnas. La creación consiste en definir (en función del
análisis realizado) el nombre de las columnas, su formato (type, el tipo), un valor
predeterminado (DEFAULT) para cuando se crea la fila y las reglas de gestión que se aplican a
la columna (CONSTRAINT). Si una regla de gestión afecta a varias columnas de la fila, se define
una restricción de tabla.
Sintaxis
DEFAULT
El valor por defecto solo se usa cuando la columna no está en una operación INSERT.
La cláusula ON NULL, que apareció en la versión 12, permite especificar que el valor por defecto
también se debe usar si un valor NULL se asigna a la columna en una operación INSERT. El valor
por defecto de la columna también se puede asignar explícitamente a la columna en una
operación INSERT o UPDATE con la palabra clave DEFAULT ().
Desde la versión 12, el valor por defecto de una columna puede hacer referencia a una secuencia
con las pseudo-columnas nomseq.NEXTVAL y nomseq.CURRVAL; la secuencia debe haberse
definido previamente (consulte la sección SQL avanzado en este capítulo).
a. Restricciones de columna
NULL/NOT NULL
Autoriza (NULL) o prohíbe (NOT NULL) la inserción del valor NULL en un atributo.
PRIMARY KEY
Designa al atributo como clave primaria de la tabla. Esta restricción solo puede aparecer una
vez en la instrucción.
UNIQUE
Designa el atributo como clave secundaria de la tabla. En el caso de que la restricción UNIQUE
se aplique a una única columna, el atributo puede tomar el valor NULL. Esta restricción puede
aparecer varias veces en la instrucción.
CHECK (condición)
Verifica, al insertar filas, que el atributo cumple la condición especificada (consulte la sección
Manipulación de los datos para ver la sintaxis de la condición).
Preste atención, en una restricción CHECK no es posible hacer referencia a la función SYSDATE
o bien CURRENT_DATE para comparar el valor de una columna de tipo fecha con el resultado de
la ejecución de esta función. Sin embargo, sí es posible, si así se desea, comparar mediante una
restricción CHECK los valores de dos columnas de tipo fecha.
Si se quiere comparar el valor de una columna de tipo fecha con la fecha actual es necesario
implementar un disparador (trigger) de base de datos. Otra posibilidad consiste en crear una
columna de tipo fecha con un valor predeterminado igual a la fecha del día más una restricción
CHECK que compare los valores presentes en las dos columnas.
Designa la concatenación de los atributos citados como clave primaria de la tabla. Esta
restricción no puede aparecer más de una vez en la instrucción.
UNIQUE (columna,...)
CHECK (condición)
Esta restricción permite expresar una condición que debe cumplirse para una serie de atributos
de la fila (consulte la sección Manipulación de los datos para ver la sintaxis de la condición).
Las restricciones de tabla se aplican a varias columnas de la tabla sobre la que están definidas.
No es posible definir una restricción de integridad utilizando columnas procedentes de dos o más
tablas. Este tipo de restricción se implementará mediante de disparadores (triggers) de la base
de datos, cuya definición se verá más adelante en el libro.
c. Opciones de las restricciones
ON DELETE CASCADE
Especifica que se asigne el valor NULL a las columnas que constituyen la clave externa que
hace referencia a la fila eliminada. Si esta opción no se especifica, será imposible eliminar en la
tabla maestra las filas que hacen referencia a este valor de la clave.
[NOT] DEFERRABLE
Es posible asignar un nombre a las restricciones con el fin de poder después manipularlas más
fácilmente (activación y eliminación). En el caso de que no se asigne explícitamente un nombre
a una restricción, Oracle genera automáticamente un nombre de la forma SYS_Cn (n es un
número entero exclusivo).
A la hora de asignar explícitamente un nombre a una restricción, resulta útil emplear el siguiente
convenio de nomenclatura:
Tabla_Columna_TipoDeRestriccion
Ejemplos
Creación de una tabla ARTICULOS con una sola restricción de clave primaria REFART:
Tabla creada.
SQL>
En este caso, DESCRIPCION, PRECIO y CANTALM pueden ser NULL: PRECIO y CANTALM pueden
tomar valores negativos.
Tabla creada.
SQL>
Tabla creada.
SQL>
Creación de la tabla LINPED con restricciones de referencia sobre las columnas y una restricción
de tabla para la clave primaria:
Tabla creada.
SQL>
Sea cual sea el modo de definición de las restricciones (a nivel de columna o de tabla), el
resultado es el mismo. Solo las restricciones de integridad que se aplican a varias columnas de
la misma tabla deben obligatoriamente definirse empleando una sintaxis de restricción de tabla.
e. La columna virtual
Una columna virtual es una columna definida por una expresión que se evalúa cada vez que se
produce una consulta; no se almacena ningún valor en la tabla para la columna en cuestión. Esta
funcionalidad es nueva a partir de la versión 11.
Sintaxis
El tipo de datos es opcional; si no se especifica, Oracle lo determina a partir del tipo de datos de
la expresión.
Las palabras reservadas GENERATED ALWAYS y VIRTUAL son opcionales; pueden especificarse
para hacer la sintaxis más clara.
Ejemplo
SQL>
SQL> insert into ARTICULOS (REFART, DESCRIPCION, PRECSINIVA, IVA)
2 values (’XT10’,’Paquete de 10 lápices’,10,21);
1 fila creada.
SQL>
SQL> insert into ARTICULOS (REFART, DESCRIPCION, PRECSINIVA, IVA)
2 values (’AD23’,’Los Tres Mosqueteros’,10,4);
1 fila creada.
SQL>
SQL> select DESCRIPCION, PRECSINIVA, PRECCONIVA from ARTICULOS;
Una columna de tipo identidad es una columna numérica entera a la que se asigna
automáticamente un valor creciente (o decreciente) durante un INSERT. De manera interna,
Oracle utiliza une secuencia para generar el número (consulte la sección SQL avanzado en este
capítulo). Esta funcionalidad apareció en la versión 12.
Sintaxis
La cláusula BY DEFAULT permite al usuario asignar un valor (no NULL) a la columna en un INSERT
o un UPDATE; en ambos casos la asignación de un valor NULL genera un error. La cláusula ON
NULL permite especificar que la identidad también se debe usar si un valor NULL se asigna a la
columna en un INSERT.
La cláusula options permite especificar las características de la secuencia que usa Oracle para
generar el valor. Esta cláusula ofrece las mismas opciones que CREATE SEQUENCE (consulte la
sección SQL avanzado en este capítulo).
Solo se puede definir una única columna de tipo identidad en una tabla.
La columna de tipo identidad debe ser de tipo numérico.
Una columna de tipo identidad no puede tener valor por defecto.
La columna de tipo identidad es obligatoria (restricción NOT NULL implícita).
Ejemplo
Tabla creada.
SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);
1 fila creada.
1 fila creada.
NOCAT NOMBRE
---------- ---------------
1 Informática
2 Bricolaje
SQL>
SQL> -- Prohibición de asignar un valor a la columna en un INSERT o UPDATE.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (123,’Libros’);
insert into CATEGORIAS (NOCAT,NOMBRE)
*
ERROR en la línea 1:
ORA-32795: imposible insertar el valor en una columna
de identidad con las palabras reservadas GENERATED ALWAYS
SQL> update CATEGORIAS set NOCAT = 456 where NOMBRE = ’Informática’;
update CATEGORIAS set NOCAT = 456 where NOMBRE = ’Informática’
*
ERROR en la línea 1:
ORA-32796: imposible modificar un columna de identidad
con las palabras reservadas GENERATED ALWAYS
SQL>
SQL> -- Recreación de la tabla con la opción BY DEFAULT.
SQL> drop table CATEGORIAS;
Tabla eliminada.
Tabla creada.
SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);
1 fila creada.
1 fila creada.
SQL>
SQL> -- Ahora es posible asignar un valor (no NULL) a la columna en un INSERT
SQL> -- o UPDATE.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (123,’Libros’);
1 fila creada.
1 fila modificada.
NOCAT NOMBRE
---------- ---------------
456 Informática
2 Bricolaje
123 Libros
SQL>
SQL> -- Pero no es posible asignar un valor NULL.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (null,’Maletas’);
values (null,’Maletas’)
*
ERROR en la línea 2:
ORA-01400: imposible insertar NULL en ("ENI"."CATEGORIAS"."NOCAT")
SQL>
SQL> -- Recreación de la tabla con la opción BY DEFAULT ON NULL.
SQL> drop table CATEGORIAS;
Tabla eliminada.
Tabla creada.
SQL>
SQL> -- La identidad se usa ahora durante la asignación de un valor NULL
SQL> -- a la columna en un INSERT.
SQL> insert into CATEGORIAS (NOCAT,NOMBRE)
2 values (null,’Maletas’);
1 fila creada.
NOCAT NOMBRE
---------- ---------------
1 Maletas
g. Columna invisible
Desde la version 12, una columna se puede declarar invisible. Una columna como esta solo es
visible si se especifica explícitamente en una sentencia SQL. Las columnas invisibles no se
muestran con la sentencia SQL SELECT * o con el comando SQL*Plus DESCRIBE.
Sintaxis
La cláusula INVISIBLE permite declarar una columna invisible. Por defecto, las columnas de una
tabla son visibles (cláusula VISIBLE).
Exemplo
SQL> create table CATEGORIAS (
2 NOCAT number(3),
3 NOMBRE varchar2(30),
4 RESPONSABLE varchar2(30) invisible
5 );
Table creada.
SQL>
SQL> -- Un INSERT sin enumeración explícita de columnas funciona
SQL> -- como si la columna no existiera.
SQL> insert into CATEGORIAS
2 values (1,’Informática’);
1 fila creada.
1 fila creada.
SQL>
SQL> -- Un SELECT * no muestra la columna invisible.
SQL> select * from CATEGORIAS;
NOCAT NOMBRE
---------- ---------------
1 Informática
2 Libros
SQL>
SQL> -- Es necesario seleccionarla explícitamente para verla.
SQL> select NOCAT,NOMBRE,RESPONSABLE from CATEGORIAS;
NOCAT NOMBRE RESPONSABLE
---------- --------------- ---------------
1 Informática
2 Libros Ángel
Para borrar una tabla es necesario eliminar su estructura y todos los datos que contenga. Los
índices asociados también se borran; las vistas creadas directa o indirectamente sobre esta tabla
las desactiva automáticamente Oracle.
La cláusula PURGE permite borrar la tabla y liberar el espacio físico que ocupaba. Si no se
encuentra esta cláusula, la tabla se borra lógicamente pero no físicamente. Esto permite utilizar
la instrucción FLASHBACK TABLE para recuperar la tabla y sus datos en el momento del borrado.
Con este principio de funcionamiento, Oracle permite dejar de hacer definitiva una acción de
eliminación de una tabla y facilita así la restauración de las tablas suprimidas por error.
Sintaxis
Ejemplo
Eliminación de la tabla CLIENTES cuya columna NUMCLI es una clave externa en la tabla
PEDIDOS:
Table dropped.
SQL>
Sintaxis
Ejemplo
Tabla modificada.
SQL> describe CLIENTES
Nombre Nulo? Tipo
----------------------------------------- -------- ------------
NUMCLI NOT NULL NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
DIRECCLI CHAR(30)
COD_POSTAL NUMBER(5)
CIUDAD CHAR(30)
TEL CHAR(14)
SQL>
SQL> alter table CATEGORIAS add (RESPONSABLE varchar2(30)
invisible default ’Ángel’);
Tabla modificada.
También es posible añadir o modificar una columna virtual usando la misma sintaxis que para la
creación de la tabla.
Ejemplo
Tabla modificada.
Tabla modificada.
De la misma manera, es posible añadir o modificar una columna de tipo identidad usando la
misma sintaxis que para la creación de la tabla, y eliminar la propiedad de tipo identidad de una
columna. Por el contrario, no es posible añadir la propiedad de tipo identidad a una columna
existente.
Ejemplo
Tabla modificada.
Tabla modificada.
Sintaxis
La sintaxis de declaración de restricciones es idéntica a la que se utiliza para crear una tabla.
Ejemplo
Tabla modificada.
SQL>
Es posible definir una restricción de tipo NOT NULL mediante el comando ALTER TABLE.
Tabla creada.
SQL>
Incluye en la tabla de excepciones las referencias de las filas que plantean problemas.
SQL>
Ahora es necesario emplear los identificadores de fila para saber qué filas impiden añadir la
restricción.
El siguiente fragmento de código enumera los números de cliente que poseen la misma dirección:
NUMCLI DIRECCLI
---------- ------------------------------
152 C/ Portugal,26
100 C/ Portugal,26
SQL>
Añadir una restricción sobre las tablas existentes es un método práctico porque, asociado a la
creación de tablas, permite producir scripts de creación de tablas sin fijar un orden de creación
que tenga en cuenta las restricciones de clave externa y de clave primaria.
Sintaxis
Ejemplo
Tabla modificada.
SQL>
El comando ALTER TABLE también permite activar y desactivar las restricciones de integridad.
Esta operación puede resultar interesante al realizar una importación masiva de datos con el fin
de, por ejemplo, limitar el tiempo necesario para llevar a cabo dicha importación.
Sintaxis
ENABLE VALIDATE
Activa la restricción para las siguientes instrucciones de manipulación de datos (no verifica los
datos actuales).
DISABLE
Desactiva la restricción.
Ejemplo
Tabla modificada.
ERROR en línea 2:
ORA-02293: no se puede validar
[CLIENTES_COD_POSTAL_CK] - restricción de control violada
SQL>
DEFERRABLE
NOT DEFERRABLE
La restricción se verifica al completar cada instrucción DML. Esta opción está activada de
manera predeterminada.
INITIALLY IMMEDIATE
INITIALLY DEFERRED
Implica que la restricción está en modo DEFERRABLE y que, de manera predeterminada, esta
restricción se verifique únicamente al completarse la transacción.
RELY o NORELY
El valor RELY permite indicar que Oracle puede tener en cuenta una restricción en modo
NOVALIDATE, para la reescritura de una consulta (query rewrite). El valor por defecto es
NORELY.
USING INDEX
Permite especificar los parámetros de los índices utilizados para establecer las restricciones de
clave primaria y de unicidad.
Ejemplo
Tabla modificada.
SQL>
f. Eliminación de columnas
Se puede eliminar una columna utilizando la cláusula DROP COLUMN de la instrucción ALTER
TABLE. Esta operación permite recuperar el espacio en disco ocupado por cada columna
eliminada.
Sintaxis
Ejemplo
Tabla modificada.
SQL>
Eliminar columnas en una tabla que posea muchas filas puede resultar una operación muy larga.
En ocasiones, es más adecuado hacer simplemente que la columna no pueda utilizarse, mediante
la cláusula SET UNUSED. Esta opción no permite liberar el espacio en disco ocupado por la
columna, pero sí permite planificar la operación de eliminación de la columna para el momento
en que la carga de trabajo en el servidor sea menor.
Sintaxis
Ejemplo
Convertir la columna TEL de la tabla CLIENTES en una columna no utilizable. Para ello, primero
se marca la columna como no utilizable.
Tabla modificada.
SQL>
Tabla modificada.
SQL>
Para saber qué tablas contienen columnas que no se pueden utilizar, es necesario consultar la
vista del diccionario de datos denominada USER_UNUSED_COL_TABS.
SQL>
La instrucción RENAME permite cambiar el nombre de una tabla, así como de las vistas,
secuencias y sinónimos privados.
Los sinónimos públicos no pueden cambiar de nombre; deben eliminarse y crearse de nuevo.
Sintaxis
Ejemplo
SQL>
h. Hacer una tabla accesible sólo en modo lectura, o en modo lectura y escritura
A partir de la versión 11, es posible hacer una tabla accesible únicamente en modo lectura para
impedir cualquier modificación de datos en la tabla y posteriormente hacerla de nuevo accesible
en modo lectura y escritura.
Sintaxis
Ejemplo
Tabla modificada.
Tabla modificada.
SQL> delete from ARTICULOS;
2 registro(s) eliminado(s).
La estructura de una tabla en modo de solo lectura no puede modificarse (agregar, modificar o
eliminar columnas). En cambio, una tabla en modo de solo lectura puede eliminarse (DROP
TABLE).
La instrucción FLASHBACK TABLE permite restaurar de forma automática una tabla modificada
de forma accidental. El lapso de tiempo durante el que es posible volver a la versión anterior de
la tabla es función del espacio de anulación reservado por la base de datos.
Esta instrucción permite anular el borrado de una tabla efectuado con la instrucción DROP TABLE.
Sintaxis
Ejemplo
En el ejemplo siguiente, la tabla linped se borra por error y se restaura mediante la acción de la
instrucción FLASHBACK TABLE:
Table dropped.
Flashback complete.
SQL> desc linped
Name Null? Type
-------------------------- ----------------- -----------------------
NUMPED NOT NULL NUMBER(6)
NUMLIN NOT NULL NUMBER(2)
REFART CHAR(4)
CANTPED NUMBER(5)
SQL>
La instrucción FLASHBACK TABLE permite anular las modificaciones efectuadas por las
instrucciones INSERT, UPDATE o DELETE en una tabla. Es posible incluso restaurar los datos de
una o más tablas hasta una fecha y hora concretas.
Para poder aprovechar esta funcionalidad, la tabla debe estar configurada para tener en cuenta
los movimientos de filas en la tabla. Es posible activar esta opción al crear la tabla, utilizando la
cláusulaenable row movement, o bien al modificar la tabla.
Sintaxis
Ejemplo
Table altered.
SQL>
En el ejemplo siguiente, los clientes cuyo nombre empieza por E se han borrado por error. La
transacción ahora se valida y los datos modificados son visibles para todos los usuarios.
2 rows deleted.
SQL> commit;
Commit complete.
SQL>
flashback complete.
COUNT(*)
---------------
7
SQL>
6. Gestion de índices
Los índices sirven para mejorar el rendimiento de las consultas. El optimizador de consultas de
Oracle los utiliza implícitamente y se actualizan de forma automática al actualizar las filas.
En general, los índices se crean sobre todas las claves externas y sobre los criterios de búsqueda
actuales. Es posible indexar una columna virtual o invisible.
Los índices que afectan a las claves primarias y secundarias (índice UNIQUE) se crean
automáticamente en el momento de la creación de la restricción, utilizando como nombre el
nombre de la restricción. Para crear otros índices hay que utilizar la instrucción CREATE INDEX.
a. Creación de un índice
Sintaxis
Ejemplos
Índice creado.
Índice creado.
b. Eliminación de un índice
Sintaxis
Existen índices de diferentes tipos que tienen una incidencia directa sobre la organización física
de los datos y estas opciones incumben a la administración.
Las instrucciones SQL manipulan expresiones. Estas expresiones hacen referencia a constantes
y nombres de objetos de la base de datos, realizan llamadas a funciones estándar y establecen
relaciones entre estos elementos mediante el uso de operadores.
Las expresiones lógicas (condiciones) también permiten definir el ámbito de las instrucciones.
a. Expresiones
constantes de caracteres
ejemplo: ’cadena de caracteres’; ’Escuela de Informática’.
constantes literales de fecha (el formato depende del idioma que se haya configurado para
la instancia)
ejemplo: ’15-JAN-94’
constantes numéricas
ejemplo: 10; -123.459; -1.26e+6
nombres de atributos de tabla
ejemplo: CLIENTES.NUMCLI; ARTICULOS.DESCRIPCION
funciones
ejemplo: SQRT(81); REPLACE(’IAGADIGI’, ’I’, ’OU’); SYSDATE
pseudo-columnas
ejemplo: nombresecuencia.NEXTVAL; ROWID.
b. Operadores
Aritméticos + - / * ( )
ejemplo: 1.15 * PRECIO; (2 * IMPLIN)/5; SYSDATE +15
Sobre cadenas de caracteres: concatenación: ||
ejemplo: ’Señor’|| NOMBRE
c. Condiciones
Operadores de comparación
El valor de las expresiones lógicas puede ser VERDADERO, FALSO o DESCONOCIDO. Una
comparación se evaluará como DESCONOCIDO si al menos uno de los términos es NULL.
Comparación simple
expresión1 {=,!=,<>, <,<=, >, >=} expresión2
Pertenencia a un conjunto de valores
expresión1 IN (expresión2,...)
VERDADERO si expresión1 aparece al menos una vez en la lista (expresión2, ...).
Pertenencia a un intervalo de valores
expresión1 BETWEEN expresión2 AND expresión3
VERDADERO si expresión1 se encuentra entre los valores límite determinados por
expresión2 y expresión3, ambos inclusive.
Comparación con un formato de cadena de caracteres.
expresión1 LIKE ’formato’
El formato puede incluir los metacaracteres:
Operadores lógicos
Las funciones escalares (scalar function) que se aplican a una sola fila: la función se
ejecuta y devuelve un resultado para cada fila de la consulta.
Las funciones sobre una agrupación de filas (group function): la función se ejecuta una
vez y devuelve un resultado para un grupo de filas de la consulta. Estas funciones se
denominan funciones de agregación.
Si se llama a una función utilizando un argumento NULL, el valor devuelto es NULL. Esta regla
se aplica a todas las funciones excepto a CONCAT, NVL y REPLACE, y las funciones de agregación.
n: expresión numérica.
d: expresión de fecha.
c: expresión de caracteres.
b: expresión lógica.
ABS (n)
Valor absoluto de n.
CEIL (n)
COS (n)
Coseno.
COSH (n)
Coseno hiperbólico.
EXP (n)
FLOOR (n)
LN (n)
Logaritmo neperiano de n.
LOG (m,n)
Logaritmo de n en base m.
MOD (n1,n2)
POWER (n1,n2)
n1 elevado a n2.
ROUND (n1,[n2])
SIGN (n)
SIN (n)
Seno de n.
SINH (n)
Seno hiperbólico de n.
SQRT (n)
Raíz cuadrada de n.
TAN (n)
Tangente de n.
TANH (n)
Tangente hiperbólica de n.
TRUNC (n1,[n2])
La mayor parte de las funciones numéricas devuelven un valor con 38 cifras significativas. No
obstante, las funciones COS, COSH, EXP, LN, LOG, SIN, SINH, SQRT, TAN y TANH devuelven un
valor con solo 36 cifras significativas.
ASCII (c)
ASCIISTR (c)
La cadena de caracteres que se pasa como parámetro se convierte al formato de la tabla ASCII
de la base de datos.
CHR (n)
COMPOSE (c)
Concatenación de c1 y c2.
DECOMPOSE (c)
Esta función es valida únicamente para cadenas en formato UNICODE. Devuelve una cadena
que contiene los diferentes caracteres introducidos.
INITCAP (c)
Devuelve c con la primera letra de cada palabra en mayúscula y las restantes en minúsculas.
INSTR (c1,c2[,n1[n2]])
INSTRB (c1,c2,n1[,n2])
LENGTH (c)
Número de caracteres de c.
LENGTHB (c)
LOWER (c)
Devuelve c en minúsculas.
LPAD (c1,n[,c2])
Devuelve c1 con una longitud total n que se obtiene añadiendo a la izquierda c2 (que por
omisión es un espacio, ’ ’).
LTRIM (c1[,c2])
NLS_INITCAP (c,’param’)
NLS_LOWER (c,’param’)
NLSSORT (c)
NLS_UPPER (c,’param’)
Idéntica a UPPER teniendo en cuenta param (código del país).
REPLACE (c1,c2,c3)
Reemplaza en c1 todas las apariciones de c2 por c3 (c3 puede ser una cadena nula).
RPAD (c1,n[,c2])
Devuelve c1 con una longitud total n que se obtiene añadiendo a la derecha c2 (que por
omisión es un espacio, ’ ’).
RTRIM (c1[,c2])
SOUNDEX (c)
Representación fonética de c.
SUBSTR (c,n1[,n2])
SUBSTRB (c,n1[,n2])
TRANSLATE (c1,c2,c3)
Reemplaza en c1 todas las apariciones de c2 por c3 (c3 no puede ser una cadena de caracteres
nula).
UNISTR (c)
UPPER(c)
Devuelve c en mayúsculas.
ADD_MONTHS (d,n)
Suma n meses a la fecha d (n puede ser negativo).
CURRENT_DATE
CURRENT_TIMESTAMP
Proporciona la fecha y la hora respecto de la zona horaria de la sesión. Esta función devuelve
un valor de tipo TIMESTAMP WITH TIME ZONE.
DBTIMEZONE
Extrae un elemento (día, mes, año, hora, minutos, segundos...) de un elemento de tipo fecha
o de un intervalo de tiempo calculado con la ayuda de las funciones NUMTODSINTERVAL o
NUMTOYMINTERVAL.
Convierte un valor de tipo TIMESTAMP en un valor de tipo TIMESTAMP WITH TIME ZONE.
LAST_DAY (d)
LOCALTIMESTAMP
Permite conocer la fecha y la hora actuales con respecto a la zona horaria de la sesión. Esta
función devuelve un valor de tipo TIMESTAMP.
MONTHS_BETWEEN (d1,d2)
NEW_TIME (d,z1,z2)
NEXT_DAY (d,j)
NUMTODSINTERVAL (n,formato)
Convierte el número n que se pasa como parámetro a formato de fecha. El segundo argumento
representa la unidad en la que se expresa n. Los posibles valores son: ’DATE’, ’HOUR’,
’MINUTE’ y ’SECOND’.
Redondea la fecha d a la unidad especificada por formato (Año, Mes, Día, Hora...).
SESSIONTIMEZONE
SYSDATE
SYS_EXTRACT_UTC (d)
Convierte una fecha y hora de una zona horaria determinada en una fecha y hora en formato
UTC (Universal Time Coordinate), es decir, la hora de Greenwich.
SYSTIMESTAMP
Permite conocer la fecha y la hora, incluyendo las fracciones de segundo, basándose en la zona
horaria configurada en el servidor de base de datos.
Trunca la fecha d comenzando por el elemento especificado en formato (Año, Mes, Día,
Hora...).
TZ_OFFSET (zona|formato)
Permite conocer la zona horaria correspondiente a la zona que se pasa como parámetro.
Las funciones de conversión (TO_CHAR, TO_DATE) y las funciones que manipulan fechas
(TRUNC, ROUND) utilizan los formatos de fecha. En la siguiente tabla se resumen los principales
indicadores de formato de fecha que pueden emplearse.
D Número de día de la semana (1 a 7). Este indicador se usa únicamente con la función
TO_DATE.
DAY Nombre del día de la semana.
MI Minutos (0 a 59).
SS Segundos (0 a 59).
WW Número de la semana del año. La semana número 1 comienza el primer día del año y dura
siete días.
W Número de la semana en el mes (1 a 5). La primera semana del mes comienza el primer
día del mes y dura siete días.
CHARTOROWID (char)
CONVERT (char,dest[,source])
source o dest
US7ASCII (ASCII 7-bit American), WE8ISO8859P1 (ISO 8859-1 8-bit West European),
WE8ISO8859P9 (ISO 8859-9 8-bit West European & Turkish), WE8ISO8859P15 (ISO 8859-15
8-bit West European), WE8MSWIN1252 (MS Windows Code Page 1252 8-bit West European),
WE8PC850 (IBM-PC Code Page 850 8-bit West European), AL32UTF8 (Unicode 6.2 UTF-8
Universal character set), UTF8 (Unicode 3.0 UTF-8 Universal character set, CESU-8 compliant),
AL16UTF16 (Unicode 6.2 UTF-16 Universal character set), UTFE (EBCDIC form of Unicode 3.0
UTF-8 Universal character set).
HEXTORAW (char)
TO_CHAR (carácter)
TO_CHAR (n,[formato[,’param’]])
formato: cadena de caracteres que representa el formato numérico (los posibles elementos de
esta cadena de caracteres se encuentran en la tabla de formatos de fecha vista
anteriormente).
TO_CLOB (cadena)
TO_DSINTERVAL (cadena)
Convierte una cadena de caracteres en datos de tipo INTERVAL TO DAY SECOND (intervalo
día/segundo).
TO_NCHAR (c)
TO_NCHAR (d,formato)
TO_NCHAR (n)
TO_NCLOB (c)
TO_NUMBER (char)
TO_TIMESTAMP (c[,formato])
TO_TIMESTAMP_TZ (c[,formato])
Convierte una cadena de caracteres en un elemento de tipo TIMESTAMP WITH TIME ZONE
basándose en el formato de fecha indicado por el segundo parámetro.
TO_YMINTERVAL (cadena)
Convierte una cadena de caracteres en datos de tipo INTERVAL YEAR TO MONTH (intervalo
mes/año).
TO_CHAR(SYSDATE,’DAYDDMONTHYYYYHH24:M
-------------------------------------
JUEVES 19 DICIEMBRE 2002 14:27:14
SQL>
Funciones de comparación
Compara la expr1 con la expr2. Si ambas expresiones son iguales, entonces devuelve el valor
NULL, en caso contrario devuelve la expr1. No se puede especificar el valor NULL para expr1.
Efectúa una operación AND entre los dos argumentos, bit a bit.
COALESCE (expr,[,...])
DUMP (exp[,formato[,inicial[longitud]]])
Los argumentos inicial y longitud permiten especificar la parte de la cadena que hay que tratar.
GREATEST (exp[,exp...])
LEAST (exp[,exp......])
Si exp1 es NULL, entonces la función NVL2 devuelve la exp2; en caso contrario, devuelve
exp3. Las expresiones 2 y 3 pueden ser cualquier tipo de datos, excepto el tipo LONG.
UID
USER
USERENV (opción)
VSIZE (exp)
Crea n intervalos equivalentes en el rango comprendido entre min y max e indica en qué
intervalo se encuentra cada expresión.
2. Creación de filas
La adición de una fila a una tabla se lleva a cabo si se cumplen las restricciones. Si no se
especifican los nombres de las columnas a los que debe asignarse un valor, debe proporcionarse
una expresión para cada columna en el orden en que se han definido las columnas durante la
creación de la tabla. No se puede omitir ninguna columna, a excepción de las columnas invisibles.
Sintaxis
Ejemplos
Creación de un cliente (las columnas omitidas tienen valor NULL o son iguales a su valor por
defecto):
1 fila creada.
SQL>
1 fila creada.
SQL>
Asignación de valores a una fila de un pedido, con introducción de una variable mediante
SQL*Plus (primera columna, consulte el capítulo dedicado a SQL*Plus) y una expresión para el
cálculo de la cantidad (última columna):
1 fila creada.
SQL>
Para insertar un valor NULL en una columna es necesario completar todas las columnas para las
que se dispone de un valor, usando la sintaxis indicada en los ejemplos anteriores (las restantes
columnas tendrán el valor NULL).
Para utilizar el valor predeterminado de una columna en una inserción, es posible utilizar la
palabra clave DEFAULT.
1 row created.
SQL>
Si bien la inserción de una fila de datos es el funcionamiento más frecuente, también es posible
agregar varias filas en la tabla. Estas filas insertadas de forma masiva se extraen de la base de
datos mediante una consulta de tipo SELECT.
Sintaxis
Ejemplo
Table created.
SQL> insert into cli4 select numcli
2 from clientes where pobl=’BARCELONA’;
0 rows created.
SQL>
3. Eliminación de filas
Instrucción DELETE
La instrucción DELETE borra todas las filas de una tabla. Si se emplea la cláusula WHERE, solo
se borran las filas para las que la condición sea verdadera.
Sintaxis
Ejemplos
Eliminación de un artículo:
1 fila suprimida.
La siguiente instrucción intenta eliminar los artículos que cuestan entre 1250 y 1750 euros.
Algunos de estos artículos están referenciados en otras tablas, lo que produce un error:
SQL>
1 fila suprimida.
SQL>
La siguiente instrucción elimina los artículos que cuestan entre 1250 y 1750 euros (AB10, AB22):
2 filas suprimidas.
SQL>
La siguiente instrucción elimina los artículos cuya descripción comienza por "Lo" (ZZ01):
La siguiente instrucción elimina los artículos cuya cantidad en almacén no tiene asignado un
valor:
2 filas suprimidas.
Instrucción TRUNCATE
La instrucción TRUNCATE permite eliminar todas las filas de una tabla y reactivar las condiciones
de almacenamiento adoptadas al crear la tabla.
Sintaxis
Ejemplo
Eliminación de artículos:
Tabla truncada.
SQL>
4. Modificación de filas
En una tabla, la instrucción UPDATE permite reemplazar por expresiones el valor de las columnas
especificadas. Si no se especifica ninguna cláusula WHERE, la actualización se lleva a cabo en
todas las filas de la tabla. En caso contrario, solo se actualizarán aquellas filas que cumplan la
condición especificada en la cláusula WHERE.
Sintaxis
Ejemplos
Incremento de un 10% del precio de los artículos cuya referencia comienza por AB:
4 filas actualizadas.
El siguiente ejemplo convierte a mayúsculas la descripción y elimina los espacios que haya al
final de la referencia de todos los artículos:
8 filas actualizadas.
5. Extracción de datos
La instrucción SELECT permite presentar los datos de una tabla, vista o sinónimo.
Sintaxis
Ejemplo
Tabla inicial:
6. Control de transacciones
En un instante determinado solo estará activa una transacción. La transacción termina cuando
se ejecuta una instrucción COMMIT o ROLLBACK. La primera instrucción DML que siga será el
comienzo de una nueva transacción.
Cada transacción también permite asegurar la coherencia de los datos vistos por cada usuario
conectado al sistema de gestión de bases de datos (RDBMS). Todas las modificaciones realizadas
sobre los datos durante una transacción se efectúan respecto al estado de dichos datos al
principio de la misma. Las modificaciones efectuadas sobre los datos por un usuario durante la
transacción no serán visibles para los demás usuarios hasta después de llevar a cabo la validación
(COMMIT) de esta transacción.
a. Validación de transacciones
También es posible poner fin a una transacción con éxito ejecutando simplemente una instrucción
del DDL, como por ejemplo un comando CREATE, ALTER o DROP. En efecto, las instrucciones del
DDL no pueden participar de la transacción. La transacción en curso termina, por tanto, con éxito
y, a continuación, se ejecuta la instrucción DDL y empieza una nueva transacción. Esta nueva
transacción afectará a las instrucciones DML siguientes. Esta validación de transacción se hace
de forma implícita y puede ser origen de errores en la comprensión del mecanismo de las
transacciones.
Sintaxis
COMMIT;
b. Anulación de modificaciones
Sintaxis
Un punto de control permite memorizar el estado de los datos durante la transacción. La inclusión
de un punto de grabación (SAVEPOINT) permite deshacer las modificaciones realizadas después
del punto de grabación establecido.
Sintaxis
SAVEPOINT punto_grabación;
Ejemplo
8 filas seleccionadas.
5 filas suprimidas.
1 fila creada.
Rollback terminado.
Rollback terminado.
SQL> commit;
Validación terminada.
SQL>
Cuando varias transacciones acceden a los mismos datos (tablas), Oracle garantiza la coherencia
de los datos de la transacción respecto de los valores iniciales existentes al comienzo de la
misma. Mientras una transacción no se valide mediante una instrucción COMMIT, las
modificaciones realizadas en los datos no serán visibles para los demás usuarios.
Ejemplo
Se abren dos sesiones (sesión 1 y sesión 2) con el mismo nombre de usuario. Sesión 1: inserción
de una fila en la tabla PEDIDOS. La fila insertada se ve en la transacción.
1 fila creada.
SQL>
1 fila creada.
SQL>
Sesión 1: COMMIT
SQL> select NUMPED, NUMCLI, FECHAPED, ESTADOPED from PEDIDOS;
SQL> commit;
Validación terminada.
SQL> select NUMPED, NUMCLI, FECHAPED, ESTADOPED from PEDIDOS;
SQL>
SQL> commit;
Validación terminada.
SQL> select NUMPED, NUMCLI, FECHAPED, ESTADOPED from PEDIDOS;
NUMPED NUMCLI FECHAPED ES
---------- ---------- -------- -
1210 15 12/11/02 SE
1301 15 20/11/02 EC
1250 35 14/11/02 EC
1230 35 14/11/02 EC
2000 35 23/12/02 EC
2001 15 23/12/02 EC
6 filas seleccionadas.
SQL>
En ciertos casos puede ser necesario verificar las restricciones de integridad al final de la
transacción. Para poder aprovechar esta funcionalidad es necesario precisar, al implementar la
restricción de integridad, si su verificación se difiere hasta finalizar la transacción (INITIALLY
DEFERRED) o bien si, por el contrario, es posible pedir en ciertos casos la validación de la
restricción al finalizar la transacción (DEFERRABLE). De modo predeterminado, las restricciones
de integridad se verifican tras la inserción de los valores en las tablas y no es posible mover esta
validación al final de la transacción.
De este modo, en el ejemplo que se presenta a continuación, es necesario contar con una
suscripción para poder ser miembro y cada suscripción debe estar en posesión de un único
miembro.
La implementación de esta relación 1-1 entre las 2 tablas se efectuará implementando una
restricción de referencia entre las 2 tablas. Cada caso de suscripción referencia un único caso de
miembro y cada caso de miembro se refiere a un único caso de suscripción.
Table created.
Table created.
SQL>
Table altered;
SQL>
Inserción de datos:
1 row created.
1 row created.
SQL> commit;
Commit complete.
SQL>
1. Operaciones
a. Restricción
La restricción permite extraer solo aquellas filas que cumplan una condición.
Ejemplo
Restricción sobre el número de pedido en la tabla PED = PEDIDOS (NUMPED = 100):
SQL>
Ejemplo
8 filas seleccionadas.
SQL>
c. Proyección
La proyección tiene por objetivo eliminar las columnas inútiles. En SQL, esto se hace enumerando
solo aquellas columnas deseadas en la instrucción SELECT.
Ejemplo
Las proyecciones de agrupación se pueden efectuar con la ayuda de dos posibles sintaxis:
La primera sintaxis (DISTINCT) permite mostrar solo una fila en el caso en que la consulta
devuelva varias filas idénticas. La segunda sintaxis (GROUP BY) se emplea cuando se desea
realizar una proyección de grupo, calculando valores agregados sobre las filas agrupadas.
La palabra clave DISTINCT solo permite mostrar valores diferentes, mientras que la palabra
clave GROUP BY efectúa primero una agrupación. Esta operación de agrupación hace posible
calcular valores agregados pero, lógicamente, precisa de más tiempo de procesador del servidor.
Ejemplos
NOMCLI
------------------------------
Martín Juan
Gómez S.A.
M. García
Martín P.
LACALLE
PLAZA S.A.
Martín Juan
7 filas seleccionadas.
NOMCLI
------------------------------
Gómez S.A.
LACALLE
M. García
Martín Juan
Martín P.
PLAZA S.A.
SQL> select NOMCLI from CLIENTES group by NOMCLI;
NOMCLI
------------------------------
Gómez S.A.
LACALLE
M. García
Martín Juan
Martín P.
PLAZA S.A.
SQL>
NOMCLI CIUDAD
------------------------------ ------------------------------
LACALLE PONTEVEDRA
M. García TOLEDO
Martín P. ORENSE
Gómez S.A. ORENSE
PLAZA S.A. PONTEVEDRA
Martín Juan MADRID
Martín Juan ORENSE
7 filas seleccionadas.
SQL>
d. Cálculo de valores agregados
Las proyecciones del cálculo de valores agregados permiten realizar cálculos estadísticos sobre
las agrupaciones especificadas mediante GROUP BY.
La lista de columnas proyectadas (las que siguen a la instrucción SELECT) tiene que ser idéntica
a la lista de columnas de agrupación (las que siguen a la cláusula GROUP BY). Los nombres de
las columnas pueden aparecer en campos calculados elementales; en tal caso, la agrupación
debe hacerse sobre las mismas expresiones.
e. Funciones de grupo
coln
Columna numérica.
col
AVG (coln)
Para cada agrupación, número de filas agrupadas en las que la columna no tiene el valor NULL.
Si la palabra DISTINCT no está presente, cuenta el número de valores distintos no NULL en la
columna.
APPROX_COUNT_DISTINCT (columna)
Para cada agrupación, número aproximado de filas agrupadas que contienen valores distintos
no NULL de columna. Esta funcionalidad apareció en la versión 12.
COUNT (*)
MAX (columna)
MIN (columna)
Valor mínimo de columna para cada agrupación.
STDDEV (coln)
SUM (coln)
VARIANCE (coln)
Distribución acumulativa.
DENSE_RANK (col)
Devuelve la primera (última) fila, ordenada con respecto a un criterio elegido (por ejemplo,
DENSE_RANK).
GROUP_ID
Diferencia los grupos duplicados que aparecen después de aplicar la cláusula GROUP BY.
GROUPING (expr)
Permite identificar las filas de acumulación cuando se ejecutan las instrucciones ROLLUP o
CUBE.
GROUPING_ID (expr)
Al igual que la función GROUPING, permite identificar si la fila está contenida o no en el
resultado de un comando ROLLUP o CUBE.
MEDIAN (expr)
PERCENT_RANK (expr)
Similar a CUME_DIST.
RANK (expr)
REGR_(expr)
STDDEV_POP (expr)
STDDEV_SAMP (expr)
VAR_POP (expr)
VAR_SAMP (expr)
Oracle dispone de algunas otras funciones para calcular valores agregados específicas para el
cálculo estadístico.
Ejemplos
Número de clientes por ciudad. El atributo ciudad se ha definido como un tipo de dato CHAR(30);
es necesario eliminar los posibles espacios incluidos a la derecha de los nombres de ciudades,
con el fin de que la agrupación se realice sobre los caracteres significativos del valor de la
columna.
RTRIM(CIUDAD) COUNT(*)
------------------------------ ----------
MADRID 1
ORENSE 3
PONTEVEDRA 2
TOLEDO 1
SQL>
Precios más elevado y medio de las cantidades disponibles en el almacén para cada familia de
artículos (los dos primeros caracteres de la referencia):
SU MAX(PRECIO) AVG(CANTALM)
-- ------------- -------------
AA 0 8
AB 1650 33,25
CD 735,4 13,5
ZZ 500 12,5
SQL>
f. Funciones analíticas
Las funciones analíticas permiten extraer resultados a partir de una agrupación de filas realizada
mediante la instrucción GROUP BY.
AVG
Media.
CORR
Coeficiente de correlación.
COVAR_POP
COVAR_SAMP
COUNT
Contador.
CUME_DIST
Distribución acumulativa.
DENSE_RANK
FIRST
LAST
FIRST_VALUE
LAST_VALUE
LAG
LEAD
LISTAGG
Concatenación.
MAX
MIN
NTH_VALUE
NTILE
Permite dividir una fila de resultados en pequeños grupos perfectamente identificados por su
número de orden.
PERCENT_RANK
Distribución acumulativa.
PERCENTILE_CONT
PERCENTILE_DISC
RANK
RATIO_TO_REPORT
REGR
Regresión lineal.
ROW_NUMBER
STDDEV
Desviación típica.
STDDEV_POP
STDDEV_SAMP
SUM
Suma.
VAR_POP
VARIANCE
Varianza.
En el ejemplo siguiente, la consulta permite enumerar todos los artículos cuya referencia
comienza por AB y mostrar junto a cada uno de ellos la referencia del artículo más barato.
SQL>
Cuando se desea limitar el número de filas devueltas por una consulta que conlleva un cálculo
de valores agregados, se puede usar la cláusula HAVING. La sintaxis es la siguiente:
La condición puede contener una función estadística. Las expresiones usadas en la cláusula
HAVING pueden hacer referencia a criterios de agrupación o a cálculos de valores agregados.
Ejemplo
Presentación de datos estadísticos de las familias de artículos cuyo precio mínimo es mayor de
300 euros:
SU MAX(PRECIO) MIN(PRECIO)
-- ------------- -----------
CD 735,4 735,4
ZZ 500 500
SQL>
h. Producto cartesiano
El producto cartesiano permite asociar cada fila de una tabla con cada fila de otras tablas.
Si las columnas tienen el mismo nombre en ambas tablas, el nombre de la columna va precedido
por el nombre de la tabla.
nombretabla.nombrecolumna.
Ejemplo
Validación terminada.
SQL> select CODIGO,REFART from DEPOSITOS,ARTICULOS;
CO REFA
-- ----
OR ZZZZ
PO ZZZZ
MA ZZZZ
OR ZZ01
PO ZZ01
MA ZZ01
OR AA00
PO AA00
MA AA00
OR CD50
PO CD50
MA CD50
OR AB
PO AB
MA AB
OR AB10
PO AB10
MA AB10
OR AB03
PO AB03
MA AB03
OR AB22
PO AB22
MA AB22
OR CD21
PO CD21
MA CD21
27 filas seleccionadas.
i. Combinaciones
La combinación es una restricción sobre el producto cartesiano que vincula cada fila de una tabla
con filas de otra tabla, de acuerdo con una condición dada.
La operación S JOIN (condición) T se expresa de la siguiente manera:
Ejemplo
SQL>
A partir de la versión 9i, Oracle admite el uso de combinaciones expresadas usando una sintaxis
compatible con el estándar ANSI.
La ventaja de la sintaxis normalizada es, por el contrario, muy clara a la hora de definir
combinaciones naturales entre las tablas, ya que solo es necesario especificar la condición de
combinación.
SQL>
j. Combinaciones externas
La combinación externa (outer join) es una extensión de la combinación que permite obtener,
además de las filas que cumplen la condición, las filas de una de las tablas que no la cumplen.
Basta con añadir el operador (+) a la condición después de la columna de la tabla cuyas filas
pueden no aparecer en el resultado.
Ejemplo
Lista de los clientes con sus pedidos, en el caso de que tengan alguno:
8 filas seleccionadas.
SQL>
7 filas seleccionadas.
SQL>
t1 LEFT OUTER JOIN t2: conserva todas las filas de la tabla 1 (tabla de la izquierda) incluso si
no hay correspondencia en la tabla 2.
t1 RIGHT OUTER JOIN t2: conserva todas las filas de la tabla 2 (tabla de la derecha) incluso si
no hay correspondencia en la tabla 1.
t1 FULL OUTER JOIN t2: conserva todas las filas de las tablas 1 y 2 incluso si no hay
correspondencia con la otra tabla (LEFT y RIGHT).
Estos operadores permiten obtener en una consulta filas procedentes de consultas diferentes
pero que usan el mismo formato (mismo nombre de columnas, mismo tipo y en el mismo orden).
El operador UNION ALL permite extraer todas las filas procedentes de las consultas, sin eliminar
las duplicadas.
Es posible realizar las operaciones de unión, intersección o diferencia entre datos procedentes
de varias consultas SELECT, pero todas las columnas deben tener la misma lista de columnas
(tipo y longitud) y dichas columnas siempre deben definirse en el mismo orden.
Ejemplo
NUMCLI NOMCLI
---------- ------------------------------
15 Gómez S.A.
20 M. García
35 Martín Juan
100 PLAZA S.A.
128 Martín P.
138 Martín Juan
152 LACALLE
556 Martín Juan
567 STUDIO 4
9 filas seleccionadas.
SQL>
SQL> select NOMCLI from CLIENTES
2 UNION
3 select NOMCLI from CLIVARIOS;
NOMCLI
------------------------------
Gómez S.A.
LACALLE
M. García
Martín Juan
Martín P.
PLAZA S.A.
STUDIO 4
7 filas seleccionadas.
SQL>
Para obtener un resultado ordenado se emplea la cláusula ORDER BY al final del comando
SELECT.
Por omisión, la clasificación se realiza en orden creciente y este orden viene determinado por los
parámetros nacionales del entorno del usuario (parámetro NLS_SORT). La clasificación en orden
decreciente se obtiene con la opción DESC de la cláusula ORDER BY. Si el usuario posee el
privilegio necesario, puede modificar el parámetro NLS_SORT durante la sesión.
Sintaxis
REFA PRECIO
---- ----------
AA00 0
AB
AB10 1500
AB22 1250,1
AB03 150
CD50 735,4
ZZZZ
ZZ01 500
8 filas seleccionadas.
PRECIO SU
---------- --
0 AA
AB
1500 AB
1250,1 AB
150 AB
735,4 CD
ZZ
500 ZZ
8 filas seleccionadas.
SQL>
b. Guardado
Mediante SQL
Es posible guardar el resultado de una consulta en una tabla, con el fin de poder utilizarlo en
otra consulta.
crear en primer lugar la tabla y luego insertar en ella las filas resultantes de la consulta,
crear la tabla a partir de la consulta.
Primer método
Sintaxis
Este método permite seleccionar los tipos de columnas, los valores predeterminados y definir
controles empleando restricciones.
Ejemplo
Tabla creada.
SQL>
SQL> insert into CLI
2 select to_char(NUMCLI, ’009’), substr(NOMCLI, 1, 10)
3 from CLIENTES where CIUDAD like ’MADRID%’;
1 fila creada.
NUMC NOMCLI
---- ----------
138 Martín Jua
SQL> drop table CLI;
Tabla borrada.
SQL>
Segundo método
Sintaxis
Este método es más rápido, ya que los nombres y los tipos de las columnas de la nueva tabla se
derivan de los de las columnas proyectadas en la instrucción SELECT.
Ejemplo
Tabla creada.
NUMCLI NOMCLI
---------- ------------------------------
15 Gómez S.A.
128 Martín P.
35 Martín Juan
SQL> desc CLIORENSE
Name Null? Type
------------------------- -------- --------------
NUMCLI NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
SQL>
Mediante SQLPLUS
Sintaxis
SPOOL nombre_archivo
Ejemplo
Creación de un archivo secuencial ASCII archivo.lst que contenga los datos de la tabla CLIENTES:
Tablas temporales
Además de las tablas permanentes, Oracle ofrece la posibilidad de crear tablas temporales para
almacenar datos durante la sesión o durante una transacción. Los datos almacenados en una
tabla temporal creada mediante la instrucción CREATE GLOBAL TEMPORARY TABLE son
accesibles únicamente desde la sesión que ha creado los datos. De hecho, cada sesión no ve
más que sus propios datos y una instrucción TRUNCATE TABLE aplicada a una tabla temporal
permite eliminar de forma sencilla todos los datos utilizados en la sesión que ejecuta la
instrucción TRUNCATE.
La especificidad de esta tabla temporal reside en el hecho de que los datos insertados en esta
tabla solo se mantienen durante el tiempo de la transacción. Por su parte, la tabla se mantiene
en su sitio y es posible utilizarla en las demás transacciones. Si se quiere que los datos insertados
en esta tabla se guarden de forma más persistente, hay que utilizar la cláusula ON COMMIT
PRESERVE ROWS al crear la tabla temporal global. De este modo, los datos insertados en esta
tabla serán visibles a través de todas las transacciones durante el tiempo de la sesión del usuario
de Oracle que ha insertado los datos en la tabla.
Sintaxis
Ejemplo
Creación de una tabla temporal global para almacenar el número y el nombre de determinados
clientes:
SQL> create global temporary table TCLI(
2 NUMCLI number(4),
3 NOMCLI varchar2(30));
Tabla creada.
SQL>
A continuación, se añaden datos a la tabla temporal. Estos datos son el resultado de ejecutar
una instrucción de tipo SELECT que permite conocer el número y el nombre de los clientes
correspondientes a cada uno de los pedidos.
3 filas creadas.
SQL>
NUMCLI NOMCLI
---------- ------------------------------
1 Alberto
1 Alberto
2 Casimiro
SQL>
Table created.
5 rows created.
SQL> commit;
Commit complete.
COUNT(*)
---------------
5
SQL>
Los cálculos de valores agregados siempre se realizan sobre la agrupación especificada por la
cláusula GROUP BY. A veces, es necesario efectuar una agrupación más grande con el fin de
conocer otros valores. Por ejemplo, se desea conocer el importe de cada pedido y el importe de
todos los pedidos pasados por un cliente. Para llevar a cabo correctamente estos cálculos en un
solo paso, hay que utilizar las palabras claves ROLLUP y CUBE.
CUBE permite realizar el cálculo solicitado sobre todas las agrupaciones posibles.
Sintaxis
El funcionamiento de estas dos palabras clave se explica mediante los ejemplos siguientes.
Ejemplo
En el siguiente ejemplo, ROLLUP permite calcular el total para cada cliente, así como el importe
total de los pedidos de todos los clientes:
SQL>
3. La instrucción MERGE
Esta instrucción permite fusionar, en una única consulta, una operación de actualización
(INSERT, UPDATE, DELETE) en una tabla.
Los datos que sirven de base para la ejecución de la orden DML pueden provenir de una o más
tablas.
Sin embargo, la misma fila de datos no puede participar como origen y destino de la instrucción
MERGE.
Esta función resulta muy interesante cuando se quiere actualizar los datos de una tabla de forma
condicional. Por ejemplo, en la tabla de empleados se quiere actualizar el salario (+4%) de los
empleados de más de 40 años y borrar los de más de 65 años (jubilados).
Al no poder ser una misma fila a la vez origen y destino del comando MERGE, la primera etapa
consistirá en crear una tabla temporal que contendrá los números de empleado y su edad.
Table created.
SQL>
2 rows merged.
SQL>
El uso de esta instrucción permite evitar la ejecución de muchas consultas como INSERT, UPDATE
o DELETE.
No es posible actualizar varias veces una misma fila en el transcurso de una sola instrucción
MERGE.
Sintaxis
INTO
permite especificar la tabla de destino de la instrucción MERGE y por tanto de las operaciones
INSERT, UPDATE y DELETE.
USING
permite especificar cómo se seleccionan los datos que participan en esta instrucción; se trata
de una consulta de tipo SELECT o bien del nombre de una tabla o vista.
ON
permite hacer una unión entre los datos ya presentes en la tabla de destino y los procedentes
del origen. En función de esta unión, la acción será una actualización (WHEN MATCHED) o bien
una inserción (WHEN NOT MATCHED).
WHEN MATCHED
SQL avanzado
El lenguaje SQL permite emplear otros objetos, además de las tablas y los índices, para gestionar
los datos o manipular las consultas.
Por otro lado, la potencia de la instrucción SELECT permite combinar las diferentes cláusulas en
un único comando, así como anidar consultas.
Por último, en un entorno multiusuario, SQL permite bloquear las tablas para preservar la
integridad de los datos.
1. Los objetos
a. Objetos View (vista)
Las vistas son tablas virtuales que presentan el resultado de una instrucción SELECT.
Una de las principales ventajas de utilizar vistas procede del hecho de que la vista no almacena
los datos, sino que hace referencia a una o varias tablas de origen mediante una consulta
SELECT, consulta que se ejecuta cada vez que se hace referencia a la vista. De este modo,
cualquier modificación que se realice sobre los datos de las tablas de origen es inmediatamente
visible en la vista, cuando ésta vuelve a ejecutarse.
Para ocultar a los usuarios determinadas columnas o filas, poniendo a su disposición vistas
de proyección o de restricción. Esto permite proporcionar un nivel de seguridad adicional.
Para simplificar el uso de tablas que incluyan muchas columnas, muchas filas o nombres
complejos, creando vistas con estructuras más sencillas y nombres más explícitos.
Para "salvaguardar" las consultas utilizadas con mayor frecuencia, empleando un nombre
para designarlas.
Para simplificar la introducción de instrucciones SQL por parte de los usuarios,
enmascarando las combinaciones utilizadas con mayor frecuencia.
Una vez creadas, las vistas se emplean como las tablas en las instrucciones DML, INSERT,
SELECT, UPDATE, DELETE. Sin embargo, no es posible realizar actualizaciones si la vista
contiene:
Una vista definida mediante una combinación soporta las instrucciones INSERT, UPDATE,
DELETE, si hace referencia en su definición a una tabla cuya(s) columna(s) de clave primaria
aparecen en la lista de las columnas proyectadas de la combinación y si las instrucciones INSERT,
UPDATE, DELETE se aplican sobre dicha tabla.
Creación
Sintaxis
OR REPLACE
FORCE | NO FORCE
Permite forzar o impedir la creación de la vista si alguno de los elementos subyacentes (tabla o
vista) no está definido.
columnas
Nombres asignados a las columnas de la vista. Si esta cláusula se omite, los nombres de las
columnas de la vista se convierten en nombres de columnas o alias de columnas usadas en la
sentencia de definición de la vista.
[VISIBLE | INVISIBLE]
Compilación
Sintaxis
La compilación de la vista permite validar la consulta asociada y detectar cuanto antes posibles
referencias incorrectas que pueda contener. Esto es especialmente útil después de modificar la
estructura de alguna de las tablas subyacentes de la vista. Si la compilación de la vista da lugar
a un error, los restantes objetos de la base de datos dependientes de esta vista dejarán de ser
válidos.
Ejemplo
Vista que devuelve los clientes de ORENSE. La opción WITH CHECK OPTION impide cualquier
inserción de cliente que no pertenezca a esta provincia:
1 fila creada.
8 filas seleccionadas.
SQL>
Vista creada.
Vista creada.
Tabla borrada.
SQL>
Vista creada.
1 fila creada.
SQL>
Eliminación
Sintaxis
Los objetos que hacen referencia a una vista eliminada se convierten en objetos no válidos.
Vistas interactivas
Se puede definir una vista directamente en una consulta sin ser necesario utilizar un comando
CREATE VIEW. Esta posibilidad es interesante, ya que permite definir de forma simple una vista
cuyo uso sea limitado.
Ejemplo
La vista interactiva permite conocer el importe de cada pedido. En la consulta se hace referencia
a dicha vista mediante el alias de tabla LPED. La consulta muestra los datos relativos a cada
cliente.
NOMCLI IMPORTE
------------------------------ ----------
Alberto 3000
Alberto 500
Casimiro 300
SQL>
Un esquema es un conjunto de tablas, vistas y privilegios agrupados bajo un mismo nombre (el
del usuario).
Sintaxis
Ejemplo
Instrucción CREATE SCHEMA AUTHORIZATION ejecutada sin errores. Todas las instrucciones
DDL especificadas han sido ejecutadas.
Vista borrada.
Tabla borrada.
Tabla borrada.
Tabla borrada.
Tabla borrada.
Esquema creado.
SQL>
Una de las instrucciones DDL especificadas (CREATE VIEW) contiene un error (nombre de
columna incorrecto en la línea 18) y no se ha podido terminar la ejecución. La otra instrucción
(CREATE TABLE) especificada en CREATE SCHEMA AUTHORIZATION ha sido anulada.
Tabla borrada.
Vista borrada.
SQL>
SQL> select * from LINPED;
select * from LINPED
*
ERROR en línea 1:
ORA-00942: la tabla o vista no existe
SQL>
Los sinónimos proporcionan una mayor flexibilidad en la gestión de los nombres de objetos:
Creación
Sintaxis
PUBLIC incluye el sinónimo en el esquema PUBLIC, haciendo de este modo que sea visible para
cualquier usuario definido en la base de datos (sin hacer referencia a un esquema). En caso
contrario, el sinónimo es local al esquema del usuario propietario.
Los sinónimos ofrecen la posibilidad de atribuir varios nombres a un mismo objeto, lo que permite
la simplificación de la escritura de consultas, sobre todo cuando debe emplearse la misma tabla
varias veces en la misma instrucción SELECT.
Los sinónimos públicos (PUBLIC) resultan muy útiles, ya que ofrecen a una aplicación la
posibilidad de trabajar con tablas sin tener en cuenta el esquema en el que se han creado los
objetos. Con este tipo de elemento, la aplicación cliente es totalmente independiente de la
estructura de la base de datos y del propietario de los elementos.
Eliminación
Sintaxis
Ejemplo
6 filas seleccionadas.
Sinónimo creado.
SQL> select COMPOSICION.REFART,COMPOSICION.DESCRIPCION,
2 NOMENCLATURA.NUM,
3 NOMENCLATURA.DESCRIPCION
4 from NOMENCLATURA, COMPOSICION
5 where NOMENCLATURA.COMPONENTE=COMPOSICION.REFART
6 order by COMPOSICION.REFART;
SQL>
Las secuencias se emplean para generar numeraciones de forma automática, en concreto para
la creación de valores de clave primaria.
El uso de un objeto secuencia es más flexible y proporciona mejores resultados que la gestión
manual de contadores por medio de una tabla.
Sintaxis
Parámetros
START WITH n
Valor inicial.
INCREMENT BY n
MINVALUE n/NOMINVALUE
MAXVALUE n/NOMAXVALUE
Establece un valor límite máximo o que no existe dicho valor máximo.
CYCLE/NOCYCLE
CACHE n/NOCACHE
ORDER/NOORDER
Garantiza un orden de asignación de números según el orden de las solicitudes. Esta opción no
tiene mayor interés salvo en el caso de usar la opción PARALLEL OPTION en modo PARALLEL
en el nivel de la instancia de Oracle.
GLOBAL/SESSION
Permite definir una secuencia global (por defecto) o a nivel sesión. Esta funcionalidad apareció
en la versión 12 y una secuencia global corresponde a la secuencia tradicional de las versiones
anteriores. Con una secuencia de nivel sesión, los valores generados son únicos para cada
sesión, y no se comparten entre sesiones. Además, cuando la sesión termina, el estado actual
de la secuencia se pierde. Esta funcionalidad es particularmente útil con las tablas temporales
que tienen una visibilidad a nivel de sesión.
pseudo-columnas
nomseq.CURRVAL
nomseq.NEXTVAL
Ejemplo
SQL> create sequence C_NUMCLI start with 1000 maxvalue 9999 nocycle;
Secuencia creada.
1 fila creada.
1 fila creada.
2. Consultas complejas
a. Elementos de la sintaxis
Alias
Sintaxis
Ejemplos
SQL>
9 filas actualizadas.
9 filas seleccionadas.
SQL>
Any
Compara, teniendo en cuenta el operador especificado (=,<>,<,<=,>, >=), los valores de las
columnas especificadas con cada uno de los valores de la lista. La expresión es verdadera si al
menos una comparación es verdadera. La lista de valores puede ser una lista de constantes
literales o los valores devueltos por una subconsulta.
Sintaxis
La subconsulta o la lista de valores debe proporcionar los valores con los que hay que comparar.
Ejemplo
Presentación de los artículos que tienen el mismo precio que el artículo ZZ01:
All
Compara, teniendo en cuenta el operador especificado (=,<>,<,<=,>, >=), los valores de las
columnas especificadas con cada uno de los valores contenidos en la lista. La expresión es
verdadera si todas las comparaciones son verdaderas. La lista de valores puede ser una lista de
constantes literales o de valores devueltos por una subconsulta.
Sintaxis
Exists
Sintaxis
Ejemplo
NUMCLI NOMCLI
---------- ------------------------------
1000 GARCÍA y GARCÍA
1001 GÓMEZ y GÓMEZ
15 Gómez S.A.
20 M. García
35 Martín Juan
152 LACALLE
138 Martín Juan
36 DEL PINO S.A.
8 filas seleccionadas.
SQL>
b. Subconsultas
Al escribir una consulta compleja, hay que diferenciar entre la consulta externa y la consulta
interna, es decir, la subconsulta.
Subconsultas anidadas
En una subconsulta anidada, no existe ningún vínculo explícito entre la consulta interna y la
consulta externa. La consulta interna se ejecuta una sola vez para construir la lista de valores,
antes de ejecutar la consulta externa (independientemente del número de filas devueltas por
aquélla).
Ejemplo
Lista de los clientes que viven en la misma ciudad que el cliente "Martín Juan".
SQL>
Subconsultas correlacionadas
En una subconsulta correlacionada, la condición especificada en la cláusula WHERE de la consulta
interna hace referencia a una o varias columnas de la consulta externa. La consulta interna se
ejecuta, por tanto, para cada fila devuelta por la consulta externa.
Ejemplo
NUMCLI NOMCLI
---------- ------------------------------
15 Gómez S.A.
20 M. García
35 Martín Juan
36 DEL PINO S.A.
37 E. LACALLE
152 LACALLE
138 Martín Juan
7 filas seleccionadas.
SQL>
En el caso del uso de la cláusula EXISTS, la subconsulta correlacionada se ejecuta por cada fila
procedente de la consulta externa. Esta solución será pues mejor si la tabla de la consulta
externa es relativamente pequeña y si cuenta con buenos índices sobre la tabla de la subconsulta
sobre las columnas que participan de la unión.
Se implementa un índice sobre la columna NUMCLI de la tabla de pedidos para acelerar los
tiempos de unión.
c. Consultas jerárquicas
En ocasiones, es necesario solicitar datos que siguen un orden jerárquico preciso. Para ello,
Oracle dispone de comandos o instrucciones que permiten extraer datos en un determinado
orden. Estos comandos son CONNECT BY PRIOR y START WITH. Durante la ejecución de una
consulta de este tipo, Oracle procede de la siguiente forma:
Oracle selecciona como raíz del árbol las filas que satisfacen la condición especificada en
la cláusulaSTART WITH.
Oracle selecciona los objetos hijo de cada objeto padre. Todos deben satisfacer la
condición especificada en la cláusula CONNECT BY.
Todos los elementos descendientes se seleccionan uno tras otro.
Si la consulta contiene una cláusula WHERE, Oracle elimina de la jerarquía todas las filas
que no cumplen la cláusula WHERE.
Para saber en qué nivel de la jerarquía se encuentra, Oracle pone a disposición del usuario la
pseudo-columna LEVEL.
Ejemplo
Creación de la tabla EMPLEADOS. Cada empleado puede depender de un jefe cuyo número se
conoce. El jefe de un empleado también es un empleado. Se desea conocer el organigrama de
la empresa.
SQL>
8 filas seleccionadas.
SQL>
8 filas seleccionadas.
SQL>
Ejemplo
8 rows selected.
SQL>
La extracción de datos de forma jerárquica se hace a menudo etapa por etapa. Para saber si un
elemento es terminal o no, hay que efectuar una consulta jerárquica a partir de dicho elemento.
Con la función CONNECT_BY_ISLEAF, que devuelve 0 si el elemento no es hoja y 1 en caso
contrario, es posible identificar los elementos que poseen un detalle.
Ejemplo
En el ejemplo siguiente se puede distinguir entre los empleados que administran un equipo y los
que no lo hacen.
8 rows selected.
SQL>
A partir de la versión 11 es posible, de una manera muy sencilla, pivotar los datos del resultado
de una consulta para visualizarlos en formato de tabla cruzada.
Como ejemplo, supongamos que tenemos una tabla que almacena las ventas detalladas por
código de país, código de producto y año:
Podemos consultar esta tabla para generar un informe que permita visualizar las ventas
acumuladas por país y año:
8 filas seleccionadas.
Para visualizar el resultado en formato de tabla cruzada, es necesario modificar la codificación
de la consulta y utilizar la cláusula PIVOT.
Ejemplo
Sintaxis simplificada
La cláusula FOR permite indicar la columna del resultado de la consulta origen cuyos valores
deben visualizarse en columnas y enumerar los valores que se desean visualizar. Estos valores
deben conocerse previamente; no es posible definirlos dinámicamente. En la lista de valores es
posible definir alias para modificar el título de la columna visualizada.
Ejemplo
9 )
10 order by AÑO;
Existe una variante de la sintaxis que permite generar el resultado en formato de documento
XML. Con esta variante, la lista de valores puede no conocerse inicialmente.
También existe una cláusula UNPIVOT que permite realizar la operación inversa: transformar
una tabla cruzada en una tabla plana.
Supongamos que tenemos una tabla de ventas que almacena los datos en formato de tabla
cruzada (lo que, desde un punto de vista conceptual, resulta extraño):
Ejemplo:
9 filas seleccionadas.
Sintaxis simplificada
La cláusula INCLUDE NULLS permite incluir en el resultado las filas con valores nulos; por
defecto, estas filas no se incluyen.
3 (
4 CANTIDAD
5 for CODIGOPAIS in (FRANCIA, ESPAÑA, ITALIA)
6 )
7 order by AÑO, CODIGOPAIS;
10 filas seleccionadas.
Desde la versión 12, Oracle soporta la sintaxis ANSI que permite limitar el número de filas
devueltas por una consulta y especificar la fila de inicio del resultado.
Sintaxis
SELECT ...
FROM ...
[WHERE ...]
[ORDER BY ...]
[cláusula_OFFSET] [cláusula_FETCH]
Para obtener un resultado coherente, es necesario especificar una cláusula ORDER BY para
asegurar un orden determinista.
La cláusula OFFSET permite definir el número de filas (n) que hay que saltar antes de volver al
resultado. Si esta cláusula se omite, no se salta ninguna fila (equivalente a OFFSET 0). Las
palabras clave ROW y ROWS son equivalentes.
La cláusula FETCH permite definir el número de filas (m) o el porcentaje de filas (m PERCENT) a
devolver. Si se omite esta cláusula, se devuelven todas las filas desde la fila n+1. Las palabras
clave FIRST y NEXT, así como ROW y ROWS, son equivalentes. Con la palabra clave ONLY, se
devuelve el número exacto de filas o el porcentaje exacto del número de filas. Con WITH TIES,
las filas iguales desde un punto de vista del criterio de ordenación con la última fila seleccionada
también se devuelve.
Ejemplo
Table creada.
1 fila creada.
1 fila creada.
1 fila creada.
1 fila creada.
1 fila creada.
1 fila creada.
1 fila creada.
1 fila creada.
1 fila creada.
SQL> commit;
Validación realizada.
NUMERO NOMBRE
---------- --------------------
1 Ángel
2 Valeria
3 David
4 Tomás
5 Ana
6 Felipe
7 Raquel
8 Pablo
9 Juan
10 Lucas
10 filas seleccionadas.
SQL>
SQL> -- Selección de los 5 "primeros" empleados
SQL> -- (clasificación utilizando el número del empleado).
SQL> select * from EMPLEADOS
2 order by NUMERO
3 fetch first 5 rows only;
NUMERO NOMBRE
---------- --------------------
1 Ángel
2 Valeria
3 David
4 Tomás
5 Ana
SQL>
SQL> -- Selección de los 5 empleados siguientes.
SQL> select * from EMPLEADOS
2 order by NUMERO
3 offset 5 rows fetch next 5 rows only;
NUMERO NOMBRE
---------- --------------------
6 Felipe
7 Raquel
8 Pablo
9 Juan
10 Lucas
SQL>
SQL> -- Selección del 20% de los empleados
SQL> -- (clasificación por el nombre del empleado).
SQL> select * from EMPLEADOS
2 order by NOMBRE
3 fetch first 20 percent rows only;
NUMERO NOMBRE
---------- --------------------
5 Ana
3 David
Antes de la versión 12, era posible hacer lo mismo usando la función analítica ROW_NUMBER y
una subconsulta:
NUMERO NOMBRE
---------- ---------------
1 Ángel
2 Valeria
3 David
4 Tomás
5 Ana
SQL>
SQL> -- Selección de los 5 empleados siguientes.
SQL> select
2 NUMERO,
3 NOMBRE
4 from
5 (
6 select
7 e.*,
8 row_number() over(order by e.NUMERO) r
9 from
10 EMPLEADOS e
11 )
12 where
13 r <= 10
14 AND r > 5;
NUMERO NOMBRE
---------- ---------------
6 Felipe
7 Raquel
8 Pablo
9 Juan
10 Lucas
3. Bloqueo de tablas
En las transacciones concurrentes (acceso a los mismos datos desde transacciones diferentes),
es necesario conservar la coherencia de los datos.
En un determinado instante, solo se autoriza a una transacción a modificar un dato (una fila).
Las restantes transacciones que deseen modificar la misma fila tienen que esperar (serialización
de solicitudes) a que la primera transacción se complete.
Para permitir esta forma de operación, Oracle gestiona simultáneamente un bloqueo en el nivel
de cada fila que está siendo modificada y un bloqueo en el nivel de tabla. El bloqueo aplicado en
el nivel de fila (bloqueo TX: Row exclusive) es un bloqueo de tipo exclusivo: si una transacción
ha aplicado este bloqueo, ninguna otra podrá hacerlo antes de que el bloqueo sea liberado por
la primera transacción (COMMIT o ROLLBACK).
Los bloqueos de tabla pueden ser aplicados automáticamente por Oracle durante la ejecución de
las instrucciones DML INSERT, UPDATE, DELETE y la instrucción PL/SQL SELECT ... FOR UPDATE
o bien explícitamente por los usuarios mediante la instrucción LOCK TABLE.
Tipos de bloqueo
EXCLUSIVE (X)
La aplicación de este tipo de bloqueo sobre una tabla impide que cualquier otra transacción
aplique explícitamente un bloqueo sobre dicha tabla y que acceda a dicha tabla en proceso de
modificación.
SHARE (S)
La aplicación de este tipo de bloqueo sobre una tabla impide que cualquier otra transacción
aplique un bloqueo que no sea de tipo SHARE (compartir) sobre la tabla y que acceda a dicha
tabla en proceso de modificación.
La aplicación de este tipo de bloqueo sobre una tabla permite el acceso concurrente a la misma
(modificación de filas diferentes en cada una de las transacciones) e impide que cualquier otra
transacción aplique sobre esta tabla un bloqueo de tipo exclusivo. Se trata de un bloqueo
tentativo.
La aplicación de este tipo de bloqueo sobre una tabla indica que hay filas de la misma que han
sido modificadas por una instrucción DML. Impide la aplicación de un bloqueo exclusivo por
parte de otra transacción.
La aplicación de este tipo de bloqueo sobre una tabla impide que una transacción aplique un
bloqueo que no sea un bloqueo tentativo RS.
Las instrucciones DML INSERT, UPDATE y DELETE aplican automáticamente un bloqueo de tipo
RX sobre la tabla que se está modificando. Una instrucción SELECT... FROM ... FOR UPDATE en
un bloque PL/SQL da lugar a la aplicación de un bloqueo de tipo S sobre la tabla.
Lock
Sintaxis
LOCK TABLE {tabla / vista} IN{EXCLUSIVE / SHARE / ROW SHARE / ROW EXCLUSIVE /
SHARE ROW EXCLUSIVE} MODE [NOWAIT / WAIT n];
Ejemplo
Tabla(s) bloqueada(s).
SQL>
Sesión 2: Intento de actualizar una fila de la tabla PEDIDOS. La instrucción espera a que la tabla
quede desbloqueada.
1 fila creada.
SQL> commit;
Validación terminada.
SQL>
Sesión 2: La instrucción de inserción se ejecuta, pero se genera un error, ya que el mismo dato
acaba de ser insertado en la otra sesión.
SQL>
4. Comentarios
Con el fin de facilitar las operaciones de actualización de la base de datos, se pueden incluir
comentarios acerca de las tablas y las vistas, así como sobre cada columna que forma parte de
dichas tablas y vistas. La inclusión de comentarios constituye una etapa indispensable, ya que
permite conocer de forma exacta el significado y la función de cada elemento de la base de
datos. Todos estos comentarios se almacenan en un diccionario de datos y están accesibles a
través de determinadas vistas del diccionario.
Para añadir un comentario sobre las columnas no es imprescindible haber incluido anteriormente
un comentario sobre la tabla o la vista.
COMMENT
Sintaxis
Ejemplo
Comentario creado.
SQL>
A continuación se especifica un comentario sobre la columna direccli, con el fin de explicar qué
datos contiene dicha columna:
Comentario creado.
SQL>
COMMENTS
--------------------------------------------------------------
Clientes de la empresa
SQL>
El diccionario de datos contiene muchas vistas que proporcionan información detallada sobre los
diferentes elementos presentes en el esquema.
ALL_OBJECTS, USER_OBJECTS
ALL_CATALOG, USER_CATALOG
ALL_TABLES, USER_TABLES
ALL_TAB_COLUMNS, USER_TAB_COLUMNS
ALL_TAB_COMMENTS, USER_TAB_COMMENTS
ALL_COL_COMMENTS, USER_COL_COMMENTS
ALL_VIEWS, USER_VIEWS
ALL_INDEXES, USER_INDEXES
ALL_IND_COLUMNS, USER_IND_COLUMNS
ALL_SEQUENCES, USER_SEQUENCES
ALL_SYNONYMS, USER_SYNONYMS
ALL_DEPENDENCIES, USER_DEPENDENCIES
Todas estas vistas pueden recuperarse realizando una consulta sobre la vista DICT, la cual
enumera todas las vistas que constituyen el diccionario, junto con un comentario que indica su
papel.
Ejemplo
La vista USER_TABLES se utiliza para saber cuáles son todas las tablas del usuario actual.
TABLE_NAME
-------------------------
ARTICULOS
CLIENTES
CLIVARIOS
DEPOSITO
EMPLEADOS
EXCEPTIONS
FACTURA
NOMENCLATURA
PEDIDOS
PRODUCTOS
10 filas seleccionadas.
SQL>
6. Funcionalidades específicas
NLS
Hay determinadas funciones que responden de forma diferente dependiendo del idioma
seleccionado en el servidor de Oracle. En Oracle, todos estos criterios vienen determinados por
los parámetros NLS (National Language Support). Estos parámetros afectan fundamentalmente
a la presentación de los datos de tipo fecha (date) y de tipo numérico.
Todas las funciones SQL que dependen de NLS permiten tener en cuenta un parámetro NLS
determinado. Estas funciones son: TO_CHAR, TO_DATE, TO_NUMBER, NLS_UPPER,
NLS_LOWER, NLS_INITCAP, NLSSORT.
Ejemplo
Uso de parámetros NLS en una función. Para comparar dos fechas, el siguiente ejemplo convierte
la fecha de referencia, que se proporciona como cadena de caracteres, en un dato de tipo fecha
(Date). Para llevar a cabo esta conversión se utiliza la función TO_DATE. Además de la cadena
de caracteres que contiene la fecha, esta función recibe otros dos parámetros: el formato de
fecha y el parámetro de tipo NLS que indica el idioma en el que se expresa la fecha.
NUMPED
----------
3
8
10
11
SQL>
Lista de los diferentes parámetros NLS disponibles para las funciones SQL:
TO_DATE NLS_DATE_LANGUAGE
NLS_CALENDAR
TO_NUMBER NLS_NUMERIC_CHARACTERS
NLS_CURRENCY
NLS_DUAL_CURRENCY
NLS_ISO_CURRENCY
TO_CHAR NLS_DATE_LANGUAGE
NLS_NUMERIC_CHARACTERS
NLS_CURRENCY
NLS_DUAL_CURRENCY
NLS_ISO_CURRENCY
NLS_CALENDAR En el
NLS_UPPER NLS_SORT
NLS_LOWER NLS_SORT
NLS_INITCAP NLS_SORT
siguiente listado se ilustran diferentes ejemplos de uso de los parámetros NLS:
TO_CHAR(fechaped,’DD/MON/YYYY’,’NLS_DATE_LANGUAGE=FRENCH’)
TO_NUMBER(’15.999,80’,’9G999D99’,’NLS_NUMERIC_CHARACTERS=’’,.’’’)
TO_CHAR(precio,’9G999D99F’,’NLS_NUMERIC_CHARACTERS=’’,.’’
NLS_ISO_CURRENCY=Japan’)
NLS_UPPER(nomcli, ’NLS_SORT=SWISS’)
NLSSORT(nomcli,’NLS_SORT=GERMAN’)
Case
El principal interés de esta instrucción es facilitar la presentación y dar formato a los resultados
directamente en las consultas SELECT. La instrucción CASE también permite limitar el número
de veces que es necesario llamar a un bloque PL/SQL para resolver el problema.
La instrucción CASE tiene un límite de 128 opciones. Para poder sobrepasar este límite, es
necesario anidar las instrucciones.
Sintaxis
CASE expresión
WHEN expresión_comparación1 THEN expresión_devuelta1
WHEN expresión_comparación2 THEN expresión_devuelta2
....
[ELSE expresión_devuelta]
END
CASE
WHEN condición1 THEN expresión_devuelta1
WHEN condición2 THEN expresión_devuelta2
....
[ELSE expresión_devuelta]
END
Ejemplo
El siguiente ejemplo permite saber el nombre de la región de los clientes a partir del código
postal:
7 filas seleccionadas.
SQL>
En este otro ejemplo, se realiza la conversión del código postal dentro de la cláusula WHEN:
7 filas seleccionadas.
SQL>
Las expresiones regulares representan una potente herramienta para trabajar con las cadenas
de caracteres. Esta funcionalidad está ya presente en muchos lenguajes de programación y en
Unix.
Las consultas de extracción de datos con criterios muy precisos de selección sobre los datos de
tipo carácter podrán escribirse más fácilmente.
Para poder trabajar con las expresiones regulares, Oracle propone un operador REGEXP_LIKE y
cuatro funciones: REGEXP_INSTR, REGEXP_SUBSTR, REGEXP_REPLACE y REGEXP_COUNT.
Las expresiones regulares describirán mediante metacaracteres la estructura que debe poseer
la cadena de caracteres con la que se quiere trabajar.
Las anclas
Los cuantificadores
? corresponde a 0 o 1 carácter.
Por ejemplo, la expresión regular a.l puede corresponder a las cadenas de caracteres apl, agl...
pero también tabla, estable, allí. En efecto, en la expresión regular solo se estipula que las letras
a y l deben ir separadas por un carácter exactamente. En ningún caso se dice que la cadena de
caracteres deba empezar por la letra a y terminar por la letra l. Si se quiere este escenario, hay
que utilizar las anclas para precisar el carácter que marca el principio de la cadena. La expresión
regular ˆa.l precisa que la cadena de caracteres buscada debe empezar obligatoriamente por la
letra a, como por ejemplo apl, agl, allí...
De modo predeterminado, los caracteres presentes en la expresión regular solo deben estar
presentes una vez en la cadena de caracteres. Así, la expresión regular ˆa.*e$ significa que se
busca una cadena que empieza por la letra a y termina por la letra e. Entre el primer y el último
carácter es posible tener entre 0 y n caracteres. Las cadenas ae, ane, anime... responden a esta
expresión.
Para permitir la construcción de expresiones aún más complejas, Oracle soporta las clases de
caracteres POSIX (Portable Operating System Interface). Gracias a esta clase de caracteres será
posible escribir expresiones regulares extremadamente precisas para encontrar solo la
información deseada.
[:digit:] número
[:space:] espacio
Estas diferentes clases de caracteres permiten cubrir todos los caracteres presentes en la tabla
ASCII.
Para poder utilizar las clases de caracteres POSIX en las expresiones regulares, es necesario
posicionarlas entre corchetes [].
Por ejemplo, la expresión [[:upper:]] permite buscar una cadena de caracteres escrita
únicamente en mayúsculas mientras que [[:lower:]]{5} corresponde a palabras de 5 letras en
minúsculas.
Para afinar las búsquedas, es posible citar una lista de caracteres que se quiere ver aparecer en
una ubicación en particular. Por ejemplo la expresión ˆpla[tc]a$ permite identificar tanto plata
como placa.
El carácter ˆ cuando se ubica como primer carácter de una expresión marca el inicio de la
expresión, por el contrario cuando aparece como primer carácter de una lista de valores marca
la negación.
Por ejemplo, ˆA[[:lower:]] corresponde a las cadenas Ana, Anillo, Arbóreo, Aviso... Por el
contrario, la expresión ˆA[ˆnop][[:lower:]] permite simplemente extraer Arbóreo, Amigo,
Aviso...
Por el contrario, si se encuentra como primer carácter de una lista, señala que los caracteres
siguientes no pueden participar de la cadena final.
REGEXP_LIKE
Este operador permite el uso de expresiones regulares para la búsqueda en las cláusulas WHERE
o bien al construir restricciones de integridad.
Sintaxis simplificada
REGEXP_LIKE(columna, expresión_regular)
Ejemplo
En el ejemplo siguiente, se busca los clientes cuyo nombre empiece por B seguido de caracteres
en minúsculas:
NUMCLI NOMCLI
-------------------------
36 Bernardo S.A.
SQL>
Pero el operador REGEXP_LIKE puede utilizarse también para definir restricciones de integridad
muy precisas.
Por ejemplo, si se quiere que los 2 primeros caracteres de una referencia de artículo sean siempre
caracteres alfabéticos en mayúsculas, es posible agregar la restricción de integridad siguiente a
la tabla de artículos:
Table altered.
SQL>
REGEXP_REPLACE
La función REPLACE en SQL permite sustituir una cadena de caracteres por otra. Pero el uso de
esta función requiere conocer exactamente la cadena a reemplazar, cosa que no siempre ocurre.
La función REGEXP_REPLACE por su parte se sirve simplemente de una descripción de la cadena
a reemplazar.
Sintaxis simplificada
REGEXP_REPLACE(cadena, expresión_regular,
cadena_de_reemplazo)
Ejemplo
Por ejemplo cuando se quiere eliminar los espacios inútiles en una cadena de caracteres, la única
certeza que se tiene es que si hay más de un espacio (2, 3 o más) entonces es posible eliminar
los espacios inútiles:
NOMCLI
----------------------------------------------------------
GOMEZ S.A.
M. GARCIA
MARTÍN Juan
Bernardo S.A.
PLAZA S.A.
MARTÍN Juan
LACALLE
7 rows selected.
SQL>
En el ejemplo anterior, los espacios inútiles se suprimen del nombre del cliente.
REGEXP_INSTR
Esta función, cuyo objetivo es el mismo que INSTR, permite localizar la ubicación de partida de
una subcadena dentro de una cadena. La ventaja reside en el hecho de que no es necesario citar
la subcadena, sino que basta con describirla mediante una expresión regular para localizarla.
Sintaxis simplificada
REGEXP_INSTR(cadena, expresión_regular)
Ejemplo
NOMCLI POSICION
-------------------------- ---------------
GOMEZ S.A. 7
M. GARCIA 0
MARTÍN Juan 0
Bernardo S.A. 10
PLAZA S.A. 7
MARTÍN Juan 0
LACALLE 0
7 rows selected.
SQL>
REGEXP_SUBSTR
Como para la función SUBSTR, el objetivo de REGEXP_SUBSTR es extraer una subcadena a partir
de una cadena de caracteres, pero describiendo la subcadena extraída mediante una expresión
regular. Esto permite extraer la subcadena sin conocer su posición exacta, ni siquiera su longitud.
Sintaxis simplificada
REGEXP_SUBSTR(cadena, expresión_regular)
Ejemplo:
En el ejemplo siguiente, se extraen los apellidos de clientes que empiezan por LA:
NOMCLI REGEXP_SUBSTR(NOMCLI,’LA.*’)
---------------------- ---------------------------------------
GOMEZ S.A.
M. GARCIA
MARTÍN Juan
Bernardo S.A.
LA PLAZA LA PLAZA
MARTÍN Juan
LACALLE LACALLE
7 rows selected.
SQL>
REGEXP_COUNT
REGEXP_COUNT indica el número de veces que se encuentra una expresión regular en una
cadena. Si la expresión regular no se encuentra en la cadena, entonces la función devuelve 0.
Sintaxis simplificada
REGEXP_COUNT(cadena, expresión_regular)
Ejemplo:
SQL> select
2 regexp_count(’érase una vez’,’[[:alnum]]+’) numero_palabras
3 from dual;
NUMERO_PALABRAS
-------------------
3
Uso de SQL*Plus
Para utilizar una base de datos Oracle y acceder a ella pueden utilizarse diversas herramientas,
entre las que se encuentran las siguientes.
Este programa permite a los usuarios finales, desarrolladores y administradores llevar a cabo las
siguientes operaciones:
1. Conexión y desconexión
Para poder usar SQL hay que conectarse a la base de datos, es decir, proporcionar un nombre
de usuario y, en ocasiones, una contraseña.
Sintaxis
sqlplus[[-S] [nombreusuario[/contraseña][@cadena_de_conexión]]
-S
modo silencioso.
nombreusuario
contraseña
cadena_de_conexión
nombre de servicio definido en el archivo TNSNAMES.ORA que hay que usar para conectarse
con el servidor de Oracle.
Los distintos comandos que permiten configurar SQL*Plus se detallan más adelante.
Si desea disponer siempre del mismo entorno de trabajo, puede almacenar sus preferencias en
el archivo login.sql. El archivo login.sql del directorio actual se ejecuta al conectarse por primera
vez a SQL*Plus.
Ejemplos
$sqlplus thisUser/Segura2012
SQL>
Ejecución del programa de modo que éste solicite los datos para establecer la conexión (la
contraseña no se muestra al escribirla):
$sqlplus
Conectado a:
............
SQL>
Sintaxis
Ejemplo
La cadena de conexión solo es necesaria si desea conectarse a un servidor Oracle que no sea
local. Por tanto, la cadena de conexión puede omitirse cuando SQL*Plus se ejecuta directamente
en el servidor Oracle.
PASSWORD
Sintaxis
PASSWORD [nombreusuario]
Ejemplo
SQL> PASSWORD
Cambiando la contraseña para SCOTT
Contraseña antigua: *****
Contraseña nueva: *****
Confirmar contraseña nueva: *****
Contraseña cambiada
SQL>
d. Desconexión
DISCONNECT
Sintaxis
DISCONNECT
Ejemplo
SQL> DISCONNECT
Desconectado de ...
...........
SQL>
EXIT
Sintaxis
SUCCESS/FAILURE/WARNING/n/variable/:variable_acoplada
COMMIT/ROLLBACK
Ejemplo
SQL> EXIT
$.
2. Ejecución de instrucciones
Después de establecer la conexión, el usuario puede emplear SQL*Plus para introducir comandos
SQL, bloques PL/SQL o comandos de SQL*Plus en el símbolo del sistema.
Los comandos SQL y PL/SQL pueden ocupar varias líneas (un final de línea queda definido por
la tecla [Intro]) y el carácter de fin de comando es el punto y coma (;). Para mejorar la
legibilidad, pueden incluirse en la sintaxis tantos espacios o tabulaciones como se desee. No se
diferencia entre mayúsculas y minúsculas (salvo cuando se emplean comillas).
Ejemplo
Creación de filas en la tabla CLIENTES:
Los comandos SQL*Plus no necesitan el carácter de fin de comando: es suficiente con la marca
de fin de línea (tecla [Intro]). Si es necesario que un comando ocupe varias líneas, se debe
emplear el carácter de guión (-).
Ejemplo
LIST
La línea actual se indica mediante un asterisco (*). Es posible cambiar la línea actual
especificando solo una línea (se necesita conocer su número). La línea especificada pasa
entonces a ser la nueva línea actual.
Sintaxis
n, m número de línea
* línea actual
También es posible listar una sola línea (que pasará a ser la línea actual) escribiendo
directamente el número de la misma.
Ejemplo
SQL> l
1 SELECT numped, sum(cantped * precio) as total
2 from lineasped, articulos
3 where lineasped.refart=articulos.refart
4* group by numped
SQL> l 2 3
2 from lineasped, articulos
3* where lineasped.refart=articulos.refart
SQL> l 2 LAST
2 from lineasped, articulos
3 where lineasped.refart=articulos.refart
4* group by numped
SQL> l 2
2* from lineasped, articulos
SQL> l * LAST
2 from lineasped, articulos
3 where lineasped.refart=articulos.refart
4* group by numped
SQL>
INPUT
Sintaxis
I[NPUT] [texto]
Ejemplo
SQL> select *
2 from clientes
3 where numcli>15
4
SQL> i
4 order by nomcli
5
SQL> l
1 select *
2 from clientes
3 where numcli>15
4* order by nomcli
SQL>
APPEND
Sintaxis
A[PPEND] texto
Ejemplo
SQL> l
1 select * from CLIENTES
2 where NUMCLI>15
3* order by NOMCLI
SQL> 2
2* where NUMCLI>15
SQL> A and NUMCLI<20
2* where NUMCLI>15 and NUMCLI<20
SQL>
CHANGE
Modifica la línea actual.
Sintaxis
Ejemplo
SQL> l
1 select * from CLIENTES
2* order by NUMCLI
SQL> 1
1* select * from CLIENTES
SQL> C/clientes/PEDIDOS
1* select * from PEDIDOS
SQL>
DEL
Sintaxis
n, m número de línea
* línea actual
Si la línea actual se borra, entonces la siguiente línea (si existe) pasa a ser la nueva línea actual.
Ejemplo
SQL> l
1 select * from clientes
2 where NUMCLI>10
3* order by NOMCLI
SQL> del
SQL> l
1 select * from clientes
2* where NUMCLI>10
SQL>
SAVE
Sintaxis
El archivo creado utiliza de forma automática la extensión .sql si no se especifica ninguna otra
extensión.
CREATE
REPLACE
APPEND
GET
Sintaxis
LIST
NOLIST
suprime la presentación.
b. Utilización de scripts
Se pueden almacenar comandos SQL o SQL*Plus en archivos de texto usando el comando SAVE
o el editor del sistema, para después ejecutar estos scripts en SQL*Plus.
EDIT
Sintaxis
[ED]IT [nomarchivo]
El editor al que se llama es el editor del sistema, salvo si se asigna un valor a la variable _EDITOR
(en UNIX, editor predeterminado = vi; en NT, editor predeterminado=notepad.exe).
Si no se especifica ningún nombre de archivo, Edit crea un archivo AFIEDT.BUF y recarga el búfer
con el contenido del archivo al volver a SQL*Plus.
REM
Comentarios.
Sintaxis
REM[ARK] texto
/*... SQL*Plus ignora el texto escrito entre estos dos separadores. El comentario puede ocupar varias
*/ líneas.
START,@,@@
Sintaxis
COPY
Es posible copiar datos de una tabla a otra que se encuentre en la base de datos local o en otra
base de datos. Para ello, se utiliza el comando SQL*Plus COPY y las cláusulas FROM y TO para
indicar la fuente y el destino de los datos. Los datos que se van a copiar se obtienen mediante
una consulta SELECT.
Sintaxis
FROM base
Permite especificar el esquema que contiene los datos que se van a copiar. Si se omite la
cláusula FROM, quiere decir que el origen de los datos es el esquema al que SQL*Plus está
conectado.
TO base
Permite especificar el esquema de destino de los datos. Si se omite la cláusula TO, el destino
de los datos es el esquema al que SQL*Plus está conectado.
base
APPEND
CREATE
INSERT
Los datos procedentes de la consulta se insertan en la tabla de destino. Si la tabla de destino
no existe, COPY devuelve un error.
REPLACE
Los datos procedentes de la consulta reemplazan a los datos de la tabla de destino. Si la tabla
de destino no existe, entonces COPY la crea.
Ejemplo
La tabla DEPT del usuario SCOTT va a copiarse en el esquema del usuario SUMINISTRO. Los dos
esquemas se encuentran en una base de datos remota.
SQL>
DESCRIBE
Sintaxis
DESC[RIBE] objeto
SPOOL
Redirecciona la salida.
Sintaxis
nomarchivo
nombre del archivo que recibe los resultados (la extensión predeterminada es .lst).
CRE[ATE]
REP[LACE]
APP[END]
OFF
cierra el archivo.
OUT
SHOW
Sintaxis
SHO[W] {ALL/parámetro}
SET
Sintaxis
Validación automática.
CMDSEP {;/OFF/ON/c}
FEEDBACK {6/n/OFF/ON}
LONG {80/n}
NULL {texto}
PAUSE {OFF/ON/texto}
SPACE {1/n}
SQLCASE {MIXED/LOWER/UPPER}
SQLCONTINUE {>/texto}
SQLNUMBER {ON/OFF}
SQLPROMPT {SQL/texto}
SQLTERMINATOR {;/c/OFF/ON}
ECHO {OFF/ON}
Muestra los comandos de un script durante la ejecución.
TERMOUT {ON/OFF}
HELP
Sintaxis
HELP [comando]
HOST
Sintaxis
Esto permite emplear de forma más amigable el SQL o el PL/SQL y crear complejos
procedimientos de forma sencilla.
1. Gestión de variables
Sintaxis
DEF[INE] [variable = texto]
Las variables creadas mediante este comando son obligatoriamente de tipo carácter.
_EDITOR
_O_VERSION
Versión de Oracle.
_O_RELEASE
_CONNECT_IDENTIFIER
_DATE
Fecha actual.
USER
_SQLPLUS_RELEASE
Versión de SQL*Plus.
UNDEFINE
Sintaxis
UNDEF[INE] variable
Ejemplo
ACCEPT
Sintaxis simplificada
NUM/CHAR
PROMPT texto
HIDE
Ejemplo
&nombre
Uso de una variable de sustitución.
Sintaxis
&variable
Ejemplo
&&nombre
Sintaxis
&&variable
Ejemplo
SQL> run
1* select * from &&NombreTabla
antiguo 1: select * from &&NombreTabla
nuevo 1: select * from LINPED
SQL>
VARIABLE
Sintaxis
Solo se puede asignar un valor a una variable PL/SQL dentro de un bloque PL/SQL mediante
instrucciones específicas de PL/SQL. PL/SQL la considera como una variable del host (prefijada
por el signo de dos puntos, :) Hay disponibles otros tipos de datos en la definición de la variable.
Sintaxis
PRINT variable
Ejemplo
NCLIENTE
----------
9
SQL>
2. Presentación de resultados
Es posible dar formato al resultado de las consultas de forma sencilla utilizando comandos
SQL*Plus.
Generalmente, estos comandos son declaraciones que deben hacerse antes de las instrucciones
SELECT y que se deben anular o desactivar una vez ejecutada la consulta.
Sintaxis
PAUSE [texto]
PROMPT
Sintaxis
PROMPT [texto]
Sintaxis
COL n
SKIP n
Salta n líneas.
TAB n
Salta n columnas.
LEFT/CENTER/RIGHT
Alineación.
BOLD
Texto en negrita.
FORMAT
MI/PR: MI muestra el signo menos (-) después de un valor negativo, PR muestra los valores
negativos entre corchetes.
Variables predefinidas:
SQL.PNO
Página actual.
SQL.LNO
Línea actual.
SQL.RELEASE
SQL.SQLCODE
SQL.USER
Usuario actual.
c. Interrupción
BREAK
Declara la acción que debe realizarse cuando se produce un cambio de valor en la columna.
Sintaxis
BREAK [ON{columna/expresión/ROW/REPORT}
[{SKIP{n/PAGE}/DUPLICATES}]...]
d. Formato de columna
COLUMN
Sintaxis
ALIAS nombre
Nombre alternativo.
LIKE alias
CLEAR
FOLD_AFTER
FOLD_BEFORE
FORMAT formato
HEADING texto
Encabezado de la columna.
JUSTIFY{LEFT/CENTER/RIGHT}
Tipo de alineación.
NEWLINE
NEW_VALUE variable
OLD_VALUE variable
NULL c
NOPRINT/PRINT
Muestra o no la columna.
WRAPPED/WORD_WRAPPED/TRUNCATED
OFF
Desactivación de la definición.
ON
e. Cálculo estadístico
COMPUTE
Declara el cálculo que hay que realizar al cambiar el valor de una expresión (que debe haber
sido declarado en una instrucción BREAK).
Sintaxis
AVG
COUNT
MAXIMUM
Valor máximo.
MINIMUM
Valor mínimo.
NUMBER
Número de líneas.
STD
Desviación típica.
SUM
VARIANCE
Varianza.
f. Anulación de declaraciones
CLEAR
Sintaxis
CLEAR {BREAKS/COLUMNS/COMPUTES/TIMING/BUFFER/SQL/SCREEN}
Hay disponibles una serie de parámetros de entorno que permiten gestionar el funcionamiento
de los comandos utilizados para dar formato a la página. Generalmente, se asignan valores a
estos parámetros al principio del script y se anulan al final del mismo.
a. Estadísticas de tiempo
TIMING
Sintaxis
b. Tratamiento de errores
Cuando se producen errores, bien del sistema operativo o bien de SQL, SQL*Plus los ignora, lo
que puede resultar perjudicial a la hora de encadenar comandos o para la integridad de los datos.
WHENEVER
Sintaxis
EXIT
CONTINUE
No sale de SQL*Plus.
COMMIT o ROLLBACK
Fuerza una validación o una anulación antes de abandonar o continuar con la ejecución.
NONE
SET ERRORLOGGING
Sintaxis simplificada
Activa o desactiva el registro en una tabla de los errores que se producen en SQL*Plus.
Por defecto, los errores se registran en una tabla llamada SPERRORLOG; si esta tabla no existe,
entonces se crea automáticamente. La cláusula TABLE permite especificar otra tabla.
TRUNCATE
IDENTIFIER
Sintaxis
DEFINE {’&’/c/ON/OFF}
EMBEDDED {OFF/ON}
HEADSEP {|/c/ON/OFF}
LINESIZE {80/n}
Número de caracteres por línea.
NEWPAGE {1/n/NONE}
NUMFORMAT {formato}
NUMWIDTH {10/n}
PAGESIZE {14/n}
SCAN {ON/OFF}
SHOWMODE {ON/OFF}
TAB {OFF/ON}
Uso de tabulaciones.
TIME {OFF/ON}
TIMING {OFF/ON}
TRIMOUT {ON/OFF}
UNDERLINE {-/c/ON/OFF}
Carácter de subrayado.
VERIFY {ON/OFF}
El comando SET posee muchas otras opciones, pero en este libro solo se detallan las más
habituales.
Ejemplo
Script que genera, formatea y guarda en un archivo (confped.lis) un informe de confirmación del
pedido cuyo número especifica el usuario:
spool confped.lis
rem Extracción
select PEDIDOS.NUMPED,NOMCLI,LINEASPED.REFART,DESCRIPCION,
PRECIO,CANTPED,PRECIO*CANTPED "Importe"
from PEDIDOS,LINEASPED,CLIENTES,ARTICULOS
where PEDIDOS.NUMPED = &VPED
and PEDIDOS.NUMCLI = CLIENTES.NUMCLI
and PEDIDOS.NUMPED = LINEASPED.NUMPED
and LINEASPED.REFART = ARTICULOS.REFART
/
spool out
rem Anulación del formato de página
ttitle off
btitle off
clear breaks
clear columns
clear compute
set pagesize 14
set newpage 1
set feed on
set echo on
set term on
Confirmación de pedido
Número : 1210
Cliente : Gómez S.A.
Referencia
artículo Descripción Precio Cantidad Importe
--------- --------------------- -------------- --------- ----------
AB10 Alfombra china 1500 3 4500
CD50 Cadena HIFI 735,4 4 2941,6
------
7441,6
Página 1
SQL*Plus ofrece la posibilidad de crear un informe en formato HTML utilizando los comandos SET
MARKUP y SPOOL. Los datos del informe se insertan entre las etiquetas HTML <PRE>, y por
tanto la presentación en el explorador de Internet es exactamente igual que la que se visualiza
en SQL*Plus.
Sintaxis
SET MARK[UP] HTML [ON|OFF] [HEAD ’texto’] [BODY ’texto’] [TABLE ’texto’]
[ENTMAP {ON|OFF}] [SPOOL {ON|OFF}] [PRE[FORMAT]{ON|OFF}]
El comando SET MARKUP permite a SQL*Plus generar un resultado en formato HTML, en lugar
de un texto sin formato. El interés de proporcionar los datos directamente en formato HTML se
encuentra simplemente en que este formato permite obtener una presentación sencilla y
cuidada, independientemente de la herramienta que se emplee para visualizar el resultado.
HTML
(OFF, valor predeterminado) Elegir el valor ON para esta opción permite activar la generación
de resultados en formato HTML.
HEAD
Permite personalizar la cabecera de la página HTML, como cuando se define un título con las
etiquetas <TITLE> y </TITLE>. También es aquí donde se pueden definir los estilos de los
diferentes títulos.
BODY
La opción BODY permite definir los atributos del texto del cuerpo (BODY). Por omisión, no se
selecciona ningún atributo, aunque puede hacerse utilizando esta opción.
TABLE
Permite especificar los atributos de tabla. Por omisión, la tabla se define con una anchura del
90% (WIDTH=’90%’) y una anchura de borde de 1 (border=’1’).
ENTMAP
(ON, valor predeterminado) Cuando se selecciona el valor OFF para esta opción se pueden
interpretar correctamente los caracteres HTML, como en el caso de los caracteres <, >," y &.
Cuando se aplica esta opción, estos caracteres no se reemplazan por sus respectivas entidades
<, >," y &.
SPOOL
(OFF, valor predeterminado) Cuando se selecciona el valor ON para esta opción se pueden
añadir las etiquetas <HTML> y <BODY>, así como las correspondientes etiquetas de cierre al
principio y al final del archivo. Este parámetro no es en ningún caso equivalente al comando
SPOOL que permite redirigir los datos mostrados por pantalla a un archivo.
PREFORMAT
(OFF, valor predeterminado) Indica a SQL*Plus que los resultados deben mostrarse en forma
de tabla. Si se selecciona el valor ON para esta opción, se pueden especificar los datos
indicados después de una etiqueta <PRE>.
Con el fin de presentar lo más claramente posible un script SQL*Plus que contenga el comando
SET MARKUP es recomendable escribir este comando utilizando varias líneas, teniendo cuidado
de no olvidar el carácter de continuación (-) de las instrucciones SQL*Plus.
El siguiente script ilustra cómo generar un resultado en formato HTML desde SQL*Plus:
SQL Developer
Oracle SQL Developer es una aplicación gráfica que permite ejecutar consultas o scripts SQL,
gestionar los objetos de una base de datos (tablas, vistas, etc.) y desarrollar y personalizar
programas PL/SQL.
Oracle SQL Developer es gratuito y puede descargarse directamente en el sitio OTN (Oracle
Technology Network). La página de bienvenida de Oracle SQL Developer se encuentra en la
siguiente dirección:http://www.oracle.com/technetwork/developer-tools/sql-
developer/overview/index.html
Desde la versión 11, Oracle SQL Developer se instala por defecto con el servidor Oracle y el
cliente Oracle.
En las plataformas Windows, Oracle SQL Developer puede iniciarse mediante la opción de
menú Inicio - Programas - Oracle -nombre_oracle_home - Desarrollo de Aplicaciones -
SQL Developer.
En las plataformas Unix o Linux, Oracle SQL Developer puede iniciarse mediante el shell
script$ORACLE_HOME/sqldeveloper/sqldeveloper.sh ($ORACLE_HOME hace
referencia al directorio de instalación de Oracle). La aplicación necesita un entorno gráfico.
En las plataformas Windows, cuando se inicia Oracle SQL Developer por primera vez, es posible
que la herramienta solicite la ruta de acceso de la aplicación java.exe. Puede utilizar la
proporcionada por
Oracle: %ORACLE_HOME%\jdk\bin\java.exe (%ORACLE_HOME% hace referencia al
directorio de instalación de Oracle).
En la parte izquierda de la ventana, una estructura en forma de árbol permite navegar por los
objetos de una o varias bases de datos. En la parte derecha de la ventana, la sección de trabajo
permite editar y ejecutar las consultas SQL y visualizar el resultado.
El botón Probar permite verificar la conexión. El botón Conectar permite registrar la nueva
conexión y conectarse.
Una vez creada la conexión, existen dos opciones para conectarse utilizando esta conexión:
puede pulsar el pequeño símbolo + situado a la izquierda del icono de la conexión, o puede
pulsar con el botón secundario del ratón en el nombre de la conexión y seleccionar el
menú Conectar.
Cuando la conexión se ha establecido con éxito, se abre una sección de trabajo en la parte
derecha de la ventana:
Para abrir las secciones de trabajo SQL suplementarias, puede pulsar el botón de la barra de
herramientas (o seleccionar el nombre de una conexión de la lista desplegable). También puede
pulsar con el botón secundario del ratón en el nombre de una conexión, en el panel de conexiones,
y seleccionar el menú Abrir hoja de trabajo.
Es posible ejecutar una única consulta, o varias consultas en forma de script, pulsando el botón o
bien pulsando la tecla [F5]; el resultado se visualiza en la pestaña Salida de Script, como en
SQL*Plus.
Puede seleccionar una conexión para esta nueva sección de trabajo mediante la lista desplegable
presentada previamente.
Una vez abierto, es posible modificar y, a continuación, ejecutar el script (botón o pulsando la
tecla [F5]); durante la primera ejecución, si no se ha seleccionado ninguna conexión con
anterioridad, se muestra un cuadro de diálogo para seleccionar una.
Para actualizar los datos también puede utilizar el editor de datos de la tabla.
Para ello, seleccione la tabla que desee en el panel de conexiones y pulse la pestaña Datos.
Los datos pueden modificarse directamente en las celdas correspondientes. Dispone también de
varios botones para actuar sobre los datos:
En la primera columna, el número de filas modificadas está precedido de un símbolo: + para una
fila nueva, - para una fila eliminada y * para una fila modificada. Ejemplo:
En el panel de conexiones, puede navegar de manera muy sencilla entre los diferentes tipos de
objetos de un esquema y visualizar su definición.
Para crear un objeto nuevo, seleccione la carpeta correspondiente al tipo de objeto que desee
(tabla, vista, etc.), pulse el botón secundario del ratón y después seleccione el
menú Nuevo (Nueva tabla..., Nueva vista..., Nuevo índice..., etc.). Se abre un cuadro de
diálogo específico del tipo de objeto seleccionado.
Este cuadro de diálogo permite modificar las diferentes características del objeto seleccionado.
De manera general, pulsando con el botón secundario del ratón sobre un objeto, se despliega
un menú contextual que ofrece diferentes acciones sobre el objeto.
Los datos visualizados en las diferentes celdas de Oracle SQL Developer pueden exportarse de
manera muy sencilla en diferentes formatos (CSV, XML, HTML, etc.).
Para ello, pulse el botón secundario del ratón sobre la celda y, a continuación, seleccione uno de
los submenús del menú Exportar...:
Oracle SQL Developer ofrece la posibilidad de exportar la definición (y los datos) de todo o parte
de los objetos de un esquema.
Para ello, seleccione el menú Herramientas - Exportar una base de datos. Se inicia
el Asistente de Exportación:
La segunda pantalla del asistente permite seleccionar los tipos de objecto que se van a exportar:
La tercera pantalla del asistente permite seleccionar de manera más precisa los objetos que se
van a exportar:
La cuarta pantalla del asistente permite definir filtros sobre los datos que se van a exportar:
Cuando la exportación termina, el script con las sentencias SQL de definición de los objetos se
abre en una nueva zona de trabajo. Si la exportación va a ser larga, puede dejar el proceso en
segundo plano y acceder directamente al archivo que la contiene:
Introducción
1. ¿Qué es el PL/SQL?
PL/SQL es el lenguaje procedimental de Oracle. Es una extensión de SQL, el cual es, por su
parte, un lenguaje estándar basado en la teoría de conjuntos.
El interés del lenguaje PL/SQL reside en poder mezclar la potencia de las instrucciones SQL con
la flexibilidad de un lenguaje procedimental en un mismo programa.
Estos programas pueden ser ejecutados directamente por las herramientas de Oracle (bloques
anónimos) o a partir de objetos de la base de datos (procedimientos almacenados y paquetes).
PL/SQL no interpreta un solo comando cada vez, sino un conjunto de comandos contenidos en
un "bloque" PL/SQL.
El motor PL/SQL del producto Oracle concreto o de la base de datos compila y ejecuta este
bloque.
DECLARE
(declaración de variables, constantes, excepciones y
cursores)
BEGIN
(instrucciones SQL, PL/SQL, estructuras de control)
EXCEPTION
(tratamiento de errores)
END ;
Las etiquetas (label), con el formato <<nombreetiqueta>>, permiten marcar ciertas partes de
un bloque.
La sección DECLARE, que permite declarar las variables que van a utilizarse en el bloque PL/SQL,
solo es necesaria cuando es preciso definir variables en el bloque. Del mismo modo, la sección
EXCEPTION solo existirá si, en los bloques, se van a tratar los errores.
Gestión de variables
Las variables son zonas de memoria nominadas que permiten almacenar un valor.
Al igual que el lenguaje SQL, PL/SQL no distingue entre mayúsculas y minúsculas. Los nombres
de las variables pueden especificarse indistintamente en mayúsculas o minúsculas.
1. Variables locales
Declaración
PL/SQL dispone de un conjunto de tipos que pueden utilizarse en la definición de las columnas
de las tablas con el fin de facilitar los intercambios de datos entre las tablas y los bloques de
código. Sin embargo, el ámbito de los posibles valores para cada uno de estos tipos puede ser
diferente del ámbito en SQL.
También dispone de un determinado número de tipos propios, principalmente para gestionar los
datos numéricos.
Por último, PL/SQL permite definir tipos complejos basados en estructuras basadas en las tablas
o en descripciones proporcionadas por el usuario.
Sintaxis
nombre-de-variable [CONSTANT]
type [[NOT NULL]:=expresión];
CONSTANT
NOT NULL
Impide que se asigne el valor NULL a la variable, debiendo proporcionarse una expresión.
expresión
Valor inicial asignado a la variable durante la ejecución del bloque.
2. Tipos predefinidos
a. Tipos de caracteres
CHAR[(n)]
VARCHAR2[(n)]
LONG
RAW[(n)]
LONG RAW
Por regla general, un byte es suficiente para codificar todos los caracteres de un idioma, pero
determinados idiomas, como el japonés, el chino... poseen demasiados caracteres y resulta
imposible codificarlos con un solo byte. Oracle ofrece una solución para codificar estos
caracteres utilizando varios bytes. El número de bytes depende del idioma establecido por el
servicio NLS (National Language Support).
NCHAR[(n)]
NVARCHAR2[(n)]
UROWID, ROWID
Permite definir variables cuyo valor representa la dirección absoluta de almacenamiento de una
fila dentro de una tabla, en forma de cadena de caracteres.
OOOOOO Especifica el número del objeto que posee dicha fila. En la práctica, es necesario conocer
el objeto al que pertenece la fila de información, ya que, en el caso de un clúster, varios
objetos pueden compartir el mismo segmento.
FFF Especifica el número del archivo que contiene la fila de información. El número de archivo
es unívoco dentro de la base de datos.
BBBBBB Especifica el número de bloque que contiene la fila de información. El número de bloque
es relativo al archivo y no al espacio de tablas.
Oracle utiliza el tipo de datos UROWID en las tablas que no tienen ROWID físico (por ejemplo,
las tablas organizadas con un índice).
b. Tipos numéricos
NUMBER[(p,s)]
Números reales con p cifras significativas almacenadas y redondeo a la derecha del punto
decimal a s cifras.
BINARY_INTEGER
Número entero comprendido entre -2 147 483 647 y +2 147 483 647.
PLS_INTEGER
Número entero comprendido entre -2 147 483 647 y +2 147 483 647.
Las variables declaradas con los siguientes tipos permiten almacenar datos no estructurados
(cuya estructura no gestiona PL/SQL) de gran tamaño.
BFILE
Permite almacenar la referencia a un archivo del sistema operativo que contiene los datos
físicos.
BLOB
CLOB
Permite almacenar un conjunto de caracteres, codificados utilizando desde un byte hasta 128
TB.
NCLOB
Permite almacenar un conjunto de caracteres, codificados utilizando desde uno o varios bytes
hasta 128 TB.
BOOLEAN
DATE
Almacena una fecha en formato de longitud fija. El rango de fechas válidas va desde el 1 de
enero de 4712 a.C. al 31 de diciembre de 9999 d.C.
TIMESTAMP
Permite ampliar el tipo de datos DATE almacenando fracciones de segundo además de los
datos de año, mes, día, hora, minuto y segundo. Por omisión, la precisión de las fracciones de
segundo se expresa con 6 cifras, pero pueden utilizarse entre 0 y 9 cifras.
e. Subtipos
PL/SQL proporciona diversos subtipos sinónimos, indicados en la siguiente tabla. Estos subtipos
permiten asegurar la compatibilidad con los tipos estándar ANSI/ISO e IBM.
CHAR CHARACTER
3. Tipos definidos por el usuario
PL/SQL permite definir nuevos tipos de datos que sean propios de una aplicación. Estos tipos
estructurados permiten definir variables que agrupan bajo un mismo nombre varios valores del
mismo tipo o de tipo diferente.
Para cada tipo de datos, se define un posible rango de valores y se especifica el conjunto de
operaciones que pueden aplicarse a dicho tipo de datos. Los subtipos permiten utilizar las mismas
operaciones, pero el rango de valores está limitado. Por tanto, se puede decir que los subtipos
no introducen nuevos tipos de datos sino que, por el contrario, permiten establecer restricciones
sobre tipos de datos existentes.
Después de definir los subtipos en la sección DECLARE del bloque PL/SQL, se pueden definir en
él variables del mismo modo que se definen variables pertenecientes a tipos de la base de datos.
Sintaxis
Ejemplo
SQL> declare
2 subtype fechanacimiento is date;
3 nacido_el fechanacimiento;
4 begin
5 -- poner la fecha del día en la variable nacido_el
6 nacido_el:=sysdate;
9 end;
10 /
SQL>
4. Colecciones y registros
Las colecciones y los registros tienen el objetivo de facilitar la programación en PL/SQL. Estos
tipos de datos solo existen en PL/SQL y no tienen equivalente en la base de datos Oracle. No es
posible almacenar directamente un registro en la base de datos, pero, sin embargo, sí se puede
almacenar cada elemento que compone el registro en la base datos.
a. Colecciones
Una colección es un conjunto ordenado de elementos del mismo tipo. Una colección puede
compararse con las matrices que pueden definirse en ciertos lenguajes de programación, con la
diferencia de que las colecciones solo pueden tener una dimensión y los elementos de la misma
se indexan mediante un valor de tipo numérico o cadena de caracteres.
Entre las colecciones se distinguen dos tipos diferentes: las tablas (TABLE) de tipo index by
table (índice por tabla) o nested table (tabla anidada), que amplían las funcionalidades ofrecidas
por las tablas de tipo índice, y las tablas de tipo VARRAY.
Tras su declaración, las colecciones nested table y VARRAY tienen que ser inicializadas. Para ello,
existe una función específica, denominada constructor, que usa el mismo nombre que la
colección y recibe como parámetros los valores que debe contener inicialmente la colección.
Preste atención: Oracle no asigna implícitamente un nombre a este constructor.
Estas colecciones tienen un tamaño dinámico y no existen forzosamente valores para todas las
posiciones.
Como muestra el esquema anterior, las colecciones son mucho más flexibles que las tablas, ya
que se pueden eliminar determinados elementos de la colección.
Las colecciones de tipo tabla anidada presentan la particularidad de que los datos que contienen
pueden almacenarse directamente en una columna de la tabla, de ahí su nombre. Además, las
colecciones no inicializadas toman el valor nulo (NULL).
Las colecciones de tipo índice por tabla representan el método más rápido para transferir datos
entre un bloque PL/SQL y la base de datos. Las colecciones de tipo index-by table también se
llaman tablas asociativas (Associative Arrays).
Sintaxis
Ejemplo
Declaración y uso de colecciones: en el siguiente ejemplo se definen dos colecciones y, a
continuación, se emplean para validar su definición (el uso de colecciones se describe con detalle
más adelante en este capítulo).
SQL> declare
2 -- colección de tipo tabla anidada
3 type cuadricula is table of number;
4 -- colección de tipo tabla organizada por índice (index by)
5 type citas is table of date index by binary_integer;
6 -- variables
7 loteria cuadricula;
8 agenda citas;
9 begin
10 -- números a los que jugar
11 loteria:=cuadricula(44,37,25,17);
12 -- anotar una cita
13 agenda(2):=to_date(’27/05/2003 11:30’,’DD/MM/YYYY HH24:MI’);
14 end;
15 /
SQL>
Una colección de tipo VARRAY tiene una dimensión máxima que debe especificarse al declarar la
colección. Estas colecciones tienen una longitud fija y, por tanto, la eliminación de elementos no
permite ahorrar espacio en memoria. Los elementos se numeran a partir del valor 1.
Sintaxis
nombre_tipo
tamaño_max
tipo_elemento
Representa el tipo de datos de los elementos que constituyen la colección.
Ejemplo
SQL> declare
2 type calendario is varray(366) of date;
3 -- declaración e inicialización de la colección
4 año calendario:=calendario(to_date(’01/01/2003’,’DD/MM/YYYY’));
5 begin
6 -- modificación del valor
7 año(1):=to_date(’02/02/2003’,’DD/MM/YYYY’);
8 end;
9 /
SQL>
b. Registros
Para poder crear un registro, es necesario definir previamente el tipo de registro en la sección
DECLARE del bloque PL/SQL.
Record
Sintaxis
Ejemplo
Definición de un registro (RECORD) de cliente que almacena los datos relativos a un cliente:
SQL> declare
2 type T_CLIREC is record (
3 NUMCLI number(4),
4 NOMBRE char(20),
5 DIRECC char(20),
6 CODPOST number(5));
7 UNCLIENT T_CLIREC;
8 begin
9 -- Instrucciones
10 UNCLIENT.NUMCLI := 1024;
11 -- Instrucciones
12 end;
13 /
SQL>
5. Tipos derivados
Cuando se declara una variable, se puede hacer referencia a una entidad existente: columna,
tabla, cursor o variable.
Esta característica resulta interesante ya que simplifica la escritura y la posible evolución de las
estructuras de datos.
%TYPE
El atributo %TYPE permite hacer referencia a una columna de una tabla o a una variable que se
haya definido anteriormente.
Sintaxis
nombre-de-variable nombredetabla.nombredecolumna%TYPE;
nombre-de-variable2 nombredevariable1%TYPE;
Ejemplo
-- Declaración de una variable del mismo tipo que el nombre del cliente.
DECLARE
V_nombre FLORENCIO.CLIENTES.NOMCLI%TYPE ;
-- Declaración de dos variables del mismo tipo.
x NUMBER(10,3);
y x%TYPE;
%ROWTYPE
Es posible hacer referencia a estructuras completas de tabla o de cursor con el fin de crear
variables que tengan la misma estructura.
Sintaxis
Ejemplo
Estas variables se declaran fuera del bloque y pueden utilizarse dentro del mismo.
Ejemplo
Uso de una variable de acoplamiento SQL*Plus (x):
7. Uso de variables
Las variables se utilizan para asignarles un valor, o en expresiones usadas para establecer
condiciones o modificar los datos.
a. Asignación de un valor
:=
Sintaxis
nombre-de-variable := expresión;
La expresión puede ser una constante, una variable o un cálculo realizado usando constantes y
variables.
operador de concatenación ||
x := 0 ;
Vnombre := ’Señor’|| Vnombre;
y := (x + 5) * y;
INTO
La cláusula INTO de las instrucciones SELECT y FETCH de PL/SQL permite asignar valores a
variables a partir de una fila (y solo una fila) procedente de una consulta.
Sintaxis
Ejemplo
DECLARE
Vref CHAR(10);
Vprecio ARTICULOS.PRECIO%TYPE;
Cli CLIENTES%ROWTYPE;
BEGIN
select REFART,PRECIO into Vref, Vprecio from Articulos
where DESCRIPCION = ’Regalo’;
select * into Cli from CLIENTES where NUMCLI = 10;
b. Uso
Los valores almacenados en las variables pueden utilizarse igual que una expresión en los
comandos SQL o PL/SQL.
Ejemplo
DECLARE
Vnumcli CLIENTES.NUMCLI%TYPE:= 10;
Vnombre CLIENTES.NOMCLI%TYPE;
BEGIN
Vnombre := ’Torres’;
UPDATE CLIENTES SET NOMCLI = Vnombre where NUMCLI = Vnumcli;
Vnumcli := Vnumcli + 1;
INSERT INTO CLIENTES (NUMCLI,NOMCLI) VALUES (Vnumcli,Vnombre);
COMMIT;
END;
c. Visibilidad
Una variable es visible dentro del bloque en el que ha sido declarada y en los bloques anidados
del mismo, siempre que no se la redefina.
Ejemplo
SQL> declare
2 a integer;
3 b integer;
4 c integer;
5 begin
6 a:=3;
7 b:=4;
8 c:=a+b;
9 --a=3, b=4 y c=7
10 declare
11 a integer; -- la variable a del bloque de nivel superior queda enmascarada
12 begin
13 a:=5;
14 b:=10;
15 c:=a+b;
16 -- a=5, b=10 y c=15
17 end;
18 -- a=3, b=10 y c=15
19 end;
20 /
Procedimiento PL/SQL terminado correctamente.
SQL>
Se puede emplear una variable de tipo estructurado en una operación de inserción (INSERT)
para añadir datos a una tabla de la base de datos desde un bloque PL/SQL.
Ejemplo
declare
vcli clientes%rowtype;
begin
-- asignar un valor a los diferentes campos de la variable estructurada
vcli.numcli :=100;
vcli.nomcli :=’MOORE’;
vcli.direccli :=’Calle de la Alegra,13’;
vcli.codpostal:=’28004’;
vcli.ciudad:=’MADRID’;
Ejemplo
Ejemplo
El siguiente ejemplo permite conocer el valor del precio de un artículo después de incrementarlo
en un 10%:
declare
type reg_art_info is record(
refart char(4),
precio number(8,2)
);
art_info reg_art_info;
begin
update articulos set precio=precio*1.1
where refart=’AB01’
returning refart, precio into art_info;
-- art_info contiene los valores después de la actualización
end;
/
structuras de control
Las estructuras de control permiten elegir la forma en que se van a ejecutar las diferentes
instrucciones.
Sintaxis
Los operadores utilizados en las condiciones son los mismos que en SQL: =; >, <, !, >=, <=,
IS NULL, IS NOT NULL, BETWEEN, LIKE, AND, OR, etc.
Ejemplo
Si se trata del cliente número 10, se actualiza; en caso contrario, la transacción se anula:
if Vnumcli = 10 THEN
UPDATE CLIENTES SET NOMCLI = ’Torres’ where NUMCLI = Vnumcli;
COMMIT;
else
ROLLBACK;
end if;
CASE
La instrucción CASE permite realizar una ejecución condicional, al igual que la instrucción IF. Sin
embargo, la instrucción CASE se adapta especialmente bien a las condiciones que implican
numerosas opciones diferentes. Proporciona una presentación que hace que el código se lea
mejor y, por tanto, disminuye el riesgo de cometer errores. Además, el uso de CASE puede
mejorar el rendimiento durante la ejecución.
Sintaxis
[<<etiqueta>>]
CASE elemento_de_selección
WHEN valor1 THEN instrucciones1;
WHEN valor2 THEN instrucciones2;
...
[ELSE instrucciones;]
END CASE [etiqueta];
[<<etiqueta>>]
CASE
WHEN condición1 THEN instrucciones1;
WHEN condición2 THEN instrucciones2;
...
[ELSE instrucciones;]
END CASE [etiqueta];
La condición ELSE es opcional y solo se ejecuta si ninguna de las condiciones WHEN anteriores
se ejecuta. Si no se define la condición ELSE, PL/SQL añade implícitamente la siguiente condición
ELSE: ELSE RAISE CASE_NOT_FOUND (lo que genera una excepción).
La instrucción CASE puede presentar dos formas. En la primera de ellas, el valor que debe
comprobarse sigue inmediatamente a CASE y se hace una comprobación de igualdad con cada
valor que sigue a las instrucciones WHEN para determinar si hay que ejecutar o no las
instrucciones PL/SQL asociadas. En su segunda forma, cada instrucción WHEN va seguida de una
condición y cuando esta condición es verdadera se ejecutan las instrucciones PL/SQL asociadas.
En cualquier caso, las instrucciones WHEN se evalúan de forma secuencial y solo se ejecuta la
primera que es verdadera.
Ejemplos
El siguiente ejemplo permite comparar el valor contenido en la variable provincia con cada uno
de los valores que siguen a las cláusulas WHEN:
declare
provincia number:=32;
nomprov varchar2(40);
begin
case provincia
when 32 then nomprov:=’Orense’;
when 36 then nomprov:=’Pontevedra’;
when 27 then nomprov:=’Lugo’;
when 15 then nomprov:=’La Coruña’;
else nomprov:=’Fuera de la comunidad’;
end case;
end;
/
En el siguiente ejemplo se evalúa la condición de cada cláusula WHEN para saber si es necesario
ejecutar o no las instrucciones que siguen a la palabra clave THEN:
declare
provincia number:=32;
comunidad varchar2(40);
begin
case
when provincia in (02,13,16,19,45)
then comunidad:=’Castilla-La Mancha’;
when provincia in (04,11,14,18,21,23,29,41)
then comunidad:=’Andalucia’;
when provincia in (15,27,32,36)
then comunidad:=’Galicia’;
end case;
end;
/
Este último ejemplo demuestra la posibilidad de anidar las instrucciones CASE. Con este tipo de
anidamiento hay que tener en cuenta los problemas de legibilidad del código.
set serveroutput on
declare
provincia number:=32;
comunidad varchar2(80);
nomprov varchar2(80);
begin
case
when provincia in (02,13,16,19,45) then
comunidad:=’Castilla - La Mancha’;
when provincia in (04,11,14,18,21,23,29,41) then
comunidad:=’Andalucia’;
when provincia in (15,27,32,36) then
comunidad:=’Galicia’;
case provincia
when 32 then nomprov:=’Orense’;
when 36 then nomprov:=’Pontevedra’;
when 27 then nomprov:=’Lugo’;
when 15 then nomprov:=’La Coruña’;
else nomprov:=’Fuera de la comunidad;
end case;
end case;
dbms_output.put_line(’provincia:’||provincia);
end;
/
2. Procesamientos repetitivos
Son conjuntos de instrucciones que se escriben una única vez y se ejecutan varias veces.
LOOP
Sintaxis
[<<ETIQUETA>>]
LOOP
instrucciones;
.......
END LOOP [ETIQUETA];
donde ETIQUETA es el nombre del bucle y condición es la condición que se debe cumplir
para poder salir del bucle.
Ejemplo
Inserción de 10 filas en la tabla CLIENTES:
x := 0;
<<INCREMENTO>>
LOOP
x := x + 1;
exit INCREMENTO when x > 10;
insert into CLIENTES (NUMCLI) VALUES (x);
END LOOP INCREMENTO;
COMMIT;
donde LABEL es el nombre del bucle y condición la condición que debe cumplirse para que
la ejecución pase a la iteración siguiente.
Ejemplo
X :=0;
<<INCREMENTO>>
LOOP
X := X + 1;
exit INCREMENTO when x > 10;
continue INCREMENTO when mod(x,2) = 0;
insert into CLIENTES (NUMCLI) VALUES (x);
END LOOP INCREMENTO;
COMMIT;
FOR
El bucle FOR permite ejecutar las instrucciones especificadas dentro del bucle haciendo variar
un índice.
El índice se puede utilizar en las instrucciones como una variable (en modo lectura).
Sintaxis
[<<ETIQUETA>>]
FOR índice IN [REVERSE] exp1..exp2 LOOP
instrucciones;
....
END LOOP [ETIQUETA];
Si no se usa la opción REVERSE, el parámetro índice varía entre exp1 y exp2, con un
incremento igual a 1.
Si se usa la opción REVERSE, el parámetro índice varía entre exp2 y exp1, con un
incremento igual a -1.
Ejemplo
WHILE
Sintaxis
[<<ETIQUETA>>]
WHILE condición LOOP
instrucciones;
......
END LOOP [ETIQUETA];
La condición es una combinación de expresiones relacionadas mediante los operadores: <, >,
=, !=, AND, OR, LIKE, ...
Ejemplo
Creación de 11 clientes consecutivos:
x := 200;
while x <= 210 LOOP
insert into CLIENTES (NUMCLI) values (x);
x := x + 1;
end loop;
COMMIT;
Uso de cursores
1. Definición
El cursor es una zona de memoria de tamaño fijo, utilizada por el motor de la base de datos de
Oracle para analizar e interpretar cualquier comando SQL.
Cursor implícito: cursor SQL generado y gestionado por Oracle para cada sentencia SQL.
Cursor explícito: cursor SQL generado y gestionado por el usuario para tratar una
instrucción SELECT de varias líneas.
2. Etapas en el uso de un cursor explícito
a. Declaración
Cualquier cursor explícito utilizado en un bloque PL/SQL debe declararse en la sección DECLARE
del bloque, especificando:
su nombre,
la instrucción SELECT asociada.
Sintaxis
b. Apertura
Después de haber declarado el cursor, es preciso "abrirlo" para ejecutar la instrucción SELECT.
Sintaxis
OPEN nombre_cursor;
Después de ejecutar la instrucción SELECT, las filas devueltas se tratan una por una; el valor de
cada columna especificada en la instrucción SELECT debe almacenarse en una variable.
Sintaxis
La instrucción FETCH extrae una única fila cada vez; para tratar n filas es necesario utilizar un
bucle.
d. Cierre
Después de tratar las filas, se cierra el cursor para liberar el espacio en memoria.
Sintaxis
CLOSE nombre_cursor;
e. Cursor for
En los casos en los que el uso principal de un cursor es recorrer un conjunto de filas extraídas
por la ejecución de una instrucción SELECT asociada puede resultar interesante utilizar una
sintaxis más simple para abrir el cursor y recorrer el bucle.
Oracle proporciona una variante para el bucle FOR que declara implícitamente la variable de
recorrido, abre el cursor, ejecuta las extracciones (FETCH) sucesivas y cierra el cursor.
Sintaxis
Ejemplo
Definición y recorrido de un CURSOR sobre la tabla CLIENTES. Presentación del último cliente
leído de la tabla:
NUM_CLIENTE
-----------
100
NOMBRE_CLIENTE
---------------
Newton
SQL>
SQL> begin
2 for V_CLI in (select NUMCLI, NOMCLI from CLIENTES) LOOP
3 :NUM_CLIENTE := V_CLI.NUMCLI;
4 :NOMBRE_CLIENTE := V_CLI.NOMCLI;
5 end loop ;
6 end;
7 /
NUM_CLIENTE
-----------
100
NOMBRE_CLIENTE
--------------
Newton
SQL>
3. Atributos de un cursor
Los atributos de un cursor (implícito o explícito) son indicadores del estado del mismo.
%FOUND
%NOTFOUND
Es un atributo de tipo booleano.
%ISOPEN
Siempre toma el valor FALSE, ya que ORACLE vuelve a cerrar los cursores después de utilizarlos.
%ROWCOUNT
Contiene el número de filas tratadas por la última instrucción INSERT, UPDATE o DELETE.
Por supuesto, no todos los atributos pueden comprobarse en todas las situaciones. La siguiente
tabla detalla el valor que se puede esperar cuando se comprueba uno de estos atributos.
OPEN
4. La
antes FALSO error error error
primer
FETCH
VERDADERO NULL NULL 0
antes
VERDADERO VERDADERO FALSO 1
después
FETCH
último
FETCH
VERDADERO VERDADERO FALSO según los
antes datos
VERDADERO FALSO VERDADERO
después según los
datos
CLOSE
variable ROWNUM
Ejemplo
Uso de ROWNUM: en el siguiente ejemplo, la variable ROWNUM se usa para extraer los tres
primeros clientes:
SQL>
Es necesario reservar previamente las filas en la declaración del cursor mediante un bloqueo de
intención (... FOR UPDATE OF nom_col...).
Esta funcionalidad es muy importante, ya que la cláusula FOR UPDATE permite aplicar un bloqueo
de intención, es decir, especificar que los datos no puedan ser modificados por otro usuario entre
el momento de lectura y el de su modificación. Sin este bloqueo de intención, podrían tener lugar
modificaciones entre la lectura y la actualización, lo que podría tener consecuencias desastrosas.
Ejemplo
Declare
CURSOR C1 is
Select REFART, PRECIO from ARTICULOS
FOR UPDATE OF PRECIO;
ART C1%ROWTYPE;
BEGIN
Open C1;
fetch C1 into ART;
while C1%FOUND loop
update ARTICULOS set PRECIO = ART.PRECIO * 2
where current of C1;
fetch C1 into ART;
end loop;
commit;
close C1;
END;
6. Paso de parámetros
Los cursores se pueden definir con parámetros con el fin de hacer su uso lo más flexible posible.
El paso de parámetros se efectúa al abrir el cursor con el comando OPEN.
Sintaxis
Ejemplo
SQL> declare
2 cursor c1(numero number) is
3 select numped,fechaped
4 from pedidos
5 where numcli=numero;
6 vc1 c1%rowtype;
7 begin
8 -- abrir el cursor
9 open c1(1);
10 -- procesar los datos
11 fetch c1 into vc1;
12 --cerrar el cursor
13 close c1;
14 end;
15 /
Gestión de errores
Durante la ejecución pueden producirse muchos errores. Dichos errores pueden ser consecuencia
del hardware, de fallos de programación o pueden tener cualquier otro origen. En determinados
lenguajes de programación no es posible gestionar cualquier clase de error, como por ejemplo
la división por cero.
El lenguaje PL/SQL proporciona un mecanismo de detección de errores que permite dar una
respuesta desde el software a cualquier tipo de error. Por supuesto, no todos los errores podrán
ser tratados, pero es posible prever una salida correcta del programa cuando se producen.
El tratamiento de errores tiene lugar en la sección EXCEPTION del bloque PL/SQL. Esta sección
es opcional y solo debe definirse cuando el bloque deba capturar los errores.
La sección EXCEPTION permite definir un tratamiento apropiado para los posibles errores que
puedan producirse durante la ejecución del bloque PL/SQL.
Las ventajas de este modo de tratamiento de errores son muchas. La más importante de ellas
es que, para gestionar un determinado tipo de error, solo tiene que escribirse el código una vez.
En los lenguajes de programación en los que no existe este mecanismo de detección de errores,
la llamada a la función que trata el error debe especificarse cada vez que el error pueda
producirse.
Reglas
Definir y proporcionar un nombre a cada error (diferente para los errores de usuario y los
errores de Oracle).
Asociar una entrada en la sección EXCEPTION para cada nombre de error definido en la
sección DECLARE.
Definir el tratamiento que hay que realizar en la sección EXCEPTION.
Sin embargo, al basarse en la definición de subbloques dentro de los que se administran las
excepciones, es posible ejecutar una serie de instrucciones incluso si se activa una excepción en
el transcurso de la ejecución de un subbloque.
1. Errores predefinidos
Todos los errores de Oracle poseen un número de identificación exclusivo. Sin embargo, solo es
posible detectarlos en un bloque PL/SQL si tienen asociado un nombre al número de error de
Oracle. En el lenguaje PL/SQL, los errores de Oracle más corrientes se asocian a un nombre con
el fin de facilitar su detección en los bloques PL/SQL.
La lista de estas excepciones predefinidas se proporciona en la siguiente tabla. Para tratar los
restantes errores de Oracle siempre es posible utilizar la palabra clave OTHERS e identificar la
excepción al principio del tratamiento llamando a las funciones SQLCODE y SQLERRM.
DUP_VAL_ON_INDEX ORA-00001 -1
Las excepciones se tratan en la sección EXCEPTION del bloque PL/SQL. En esta sección, las
cláusulas WHEN permiten saber qué código hay que ejecutar como respuesta a la excepción que
se haya generado.
Ejemplo
SQL> declare
2 vnombre clientes.nomcli%type;
3 begin
4 select nomcli into vnombre from clientes;
5 exception
6 when too_many_rows then
7 rollback;
8 end;
9 /
SQL>
Si el programador piensa que puede producirse una anomalía durante el procesamiento (error
lógico o error de datos), puede evitarlo con una excepción que permita tratarla en caso de que
se produzca.
A diferencia de las excepciones predefinidas, las excepciones definidas por el usuario deben
declararse y generarse explícitamente mediante el comando RAISE.
Las excepciones únicamente pueden definirse en la sección DECLARE del bloque PL/SQL. Una
excepción se define especificando su nombre seguido de la palabra clave EXCEPTION.
DECLARE
Sobrepasar EXCEPTION
...
En el ejemplo anterior se ha definido la excepción Sobrepasar.
Sintaxis
DECLARE
...
nombre_error EXCEPTION;
...
BEGIN
...
IF(anomalía)
THEN RAISE nombre_error;
...
EXCEPTION
WHEN nombre_error THEN
(tratamiento);
END;
=> Salida del bloque después de ejecutar el tratamiento.
Ejemplo
DECLARE
CURSOR C1 ...
ART ...
Sobrepasar EXCEPTION;
NVPRECIO NUMBER;
BEGIN
....
while C1%FOUND LOOP
NVPRECIO := ART.PRECIO * 2;
if NVPRECIO > 10000 then raise sobrepasar;
update ARTICULOS set PRECIO = NVPRECIO ...
fetch ...
end loop;
...
EXCEPTION
When sobrepasar then
rollback;
END;
La palabra clave RAISE permite, claro está, generar errores de usuario en la sección de
procesamiento del bloque, pero también puede emplearse para propagar las excepciones hacia
el bloque que ha hecho la llamada, después de un tratamiento parcial o total de la excepción.
Ejemplo
Uso de la instrucción RAISE para propagar un error: en el ejemplo siguiente, el bloque PL/SQL y
su subbloque se encargan de borrar un pedido.
SQL> declare
2 vnumped pedidos.numped%type;
3 begin
4 vnumped:=1;
5 --¿contiene líneas el pedido?
6 -- en caso afirmativo, borrarlas
7 declare
8 vnumero integer;
9 begin
10 select count(*) into vnumero
11 from lineasped where numped=vnumped;
12 -- vnumero contiene el número de líneas del pedido
13 if vnumero>0 then
14 -- generar una excepción predefinida
15 raise too_many_rows;
16 end if;
17 exception
18 when too_many_rows then
19 -- borrar las líneas del pedido
20 delete from lineasped where numped=vnumped;
21 -- generar una excepción para pasarla al bloque superior
22 raise no_data_found;
23 end;
24 exception
25 when no_data_found then
26 delete pedidos where numped=vnumped;
27 end;
28 /
Procedimiento PL/SQL terminado correctamente.
SQL>
3. Errores de Oracle
Para capturar un error de Oracle no predefinido es necesario trabajar con la cláusula WHEN
OTHERS del bloque de tratamiento de excepciones o bien asociar un nombre al número del error
de Oracle que se desea capturar. Esta asociación, nombre de la excepción y número de error de
Oracle, es posible gracias a la directiva de compilación PRAGMA EXCEPTION_INIT.
El nombre asociado al error de Oracle debe definirse previamente como nombre de excepción.
Sintaxis
Ejemplo
SQL> declare
2 interbloqueo exception;
3 pragma exception_init(interbloqueo, -60);
4 begin
5 -- procesamiento
6 update clientes set nomcli=upper(nomcli);
7 exception
8 -- tratamiento de la excepción
9 when interbloqueo then
10 rollback;
11 end;
12 /
SQL>
Todos los errores SQL o PL/SQL tienen un código asociado. Se puede asociar este código con un
nombre de excepción para realizar el tratamiento del error a nivel de bloque.
Sintaxis
DECLARE
...
nombre_error EXCEPTION;
PRAGMA EXCEPTION_INIT(nombre_error, cod_error);
...
BEGIN
...
=>Cuando se produce un error de Oracle, se pasa automáticamente a la
sección EXCEPTION para ejecutar el tratamiento correspondiente al error
...
EXCEPTION
WHEN nombre_error THEN
(tratamiento);
[WHEN OTHERS THEN (tratamiento);]
END;
=> Salida del bloque después de la ejecución del tratamiento
Ejemplo
El error 1401 indica un valor demasiado grande para una columna. Si este error se produce, se
puede cancelar la transacción de manera adecuada:
Declare
...
Demasiado_grande EXCEPTION ;
PRAGMA EXCEPTION_INIT (Demasiado_grande, -1401);
Begin
...
...
Exception
When Demasiado_grande then rollback;
end;
El subbloque no puede generar la excepción definida en el bloque de nivel superior, ya que está
enmascarada por la definición local. Si el bloque de nivel superior dispone de una etiqueta, es
posible generar la excepción definida en dicho bloque utilizando la siguiente
sintaxis:nombre_del_bloque.nombre_excepción
En el ejemplo anterior, las dos excepciones Sobrepasar son totalmente diferentes y no existe
ninguna relación entre ellas.
5. Uso de raise_application_error
Sintaxis
número_error
Representa el número del error de usuario. Este número debe estar comprendido entre -20000
y -20999.
mensaje
Cadena de caracteres con una longitud máxima de 2048 bytes, que contiene el mensaje
asociado al error.
El tercer parámetro, que es opcional, permite saber si el error debe incluirse en la pila de errores
(TRUE) o si debe reemplazar a los restantes errores. Por omisión, se adopta esta última opción.
Ejemplos
SQL> begin
2 for vcli in (select numcli, ciudad from clientes) loop
3 if (vcli.ciudad=’Orense’) then
4 raise_application_error(-20001,’ENCONTRADO’);
5 end if;
6 end loop;
7 end;
8 /
begin
*
ERROR en línea 1:
ORA-20001: ENCONTRADO
ORA-06512: línea 4
SQL>
SQL> declare
2 vnumped pedidos.numped%type;
3 begin
4 select numped into vnumped
5 from pedidos
6 where numcli=1;
7 exception
8 when no_data_found then
9 -- puede eliminarse el cliente
10 delete from clientes where numcli=1;
11 when others then
12 raise_application_error (-20002,’Imposible eliminarlo’);
13 end;
14 /
declare
*
ERROR en línea 1:
ORA-20002: Imposible eliminarlo
ORA-06512: línea 12
SQL>
Ejemplo resumen
El siguiente ejemplo muestra la sintaxis utilizada para la gestión de variables, cursores y
estructuras de control en un programa completo.
En el caso de que la cantidad en almacén del artículo pase a ser negativa, las actualizaciones
para dicho pedido se anulan.
Para cada artículo para el que existan problemas (que no pueda ser suministrado) y para cada
pedido que se entregue totalmente se actualiza una tabla testigo.
2. Ejemplo
Script actsum.sql:
/
rem Consulta de la tabla testigo
select * from testigo;
drop table testigo;
3. Ejecución en SQL*Plus
SQL> select * from articulos;
9 filas seleccionadas.
SQL> @actsum
SQL> select * from testigo;
NUMPED TEXTO
---------- ------------------------------------------------------------
1230 Problema en el artículo: AB10 CD50
1250 Problema en el artículo: AB10
1301 Pedido suministrado
1301 Pedido suministrado
Tabla borrada.
SQL> select * from articulos;
9 filas seleccionadas.
El bloque PL/SQL que constituye el trigger puede ejecutarse antes o después de la actualización
y, por lo tanto, antes o despues de la verificación de las restricciones de integridad.
Los triggers ofrecen una solución procedimental para definir restricciones complejas o que
tengan en cuenta datos procedentes de varias filas o de varias tablas, como por ejemplo para
garantizar el hecho de que un cliente no pueda tener más de dos pedidos no pagados. Sin
embargo, los triggers no deben emplearse cuando sea posible establecer una restricción de
integridad. En efecto, las restricciones de integridad se definen en el nivel de tabla y forman
parte de la estructura de la propia tabla, por lo que la verificación de estas restricciones es mucho
más rápida. Además, las restricciones de integridad garantizan que todas las filas de las tablas
respetan dichas restricciones, mientras que los triggers no tienen en cuenta los datos ya
contenidos en la tabla en el momento de definirlos.
El bloque PL/SQL asociado a un trigger se puede ejecutar para cada fila afectada por la
instrucción DML (opción FOR EACH ROW), o una única vez para cada instrucción DML ejecutada
(opción predeterminada).
Ejecución antes o después de la comprobación de las restricciones de integridad para cada fila
o cada sentencia
En los triggers BEFORE y FOR EACH ROW se pueden modificar los datos que van a insertarse en
la tabla, de modo que respeten las restricciones de integridad. También es posible ejecutar
consultas de tipo SELECT sobre la tabla a la que se aplica la instrucción DML, aunque únicamente
en el marco de un trigger BEFORE INSERT. Todas estas operaciones no se pueden realizar en
los triggers AFTER, ya que después de la verificación de las restricciones de integridad no es
posible modificar los datos y, dado que la modificación (adición o eliminación) de la fila no se ha
terminado, no es posible ejecutar consultas de tipo SELECT sobre la tabla.
También se pueden incluir triggers en las vistas (VIEW) con el fin de capturar las instrucciones
DML que se pueden ejecutar sobre ellas. Estos triggers permiten controlar todas las operaciones
realizadas sobre las vistas y, para el usuario final, la vista es completamente similar a una tabla,
ya que puede realizar sobre ella operaciones INSERT, UPDATE y DELETE. Estos triggers son de
tipo INSTEAD OF, es decir, que su ejecución va a reemplazar a la instrucción DML a la que estén
asociados. Este tipo de trigger solo puede definirse en vistas y es el único tipo de trigger que
puede implementarse en ellas.
Sintaxis
OR REPLACE
BEFORE
AFTER
INSTEAD OF
Instrucción asociada a la activación del trigger. Varias instrucciones pueden activar un mismo
trigger y se combinan mediante el operador OR.
FOLLOWS nombre_otro_trigger[,...]
Oracle permite definir varios triggers para la misma tabla y el mismo evento. En este caso, el
orden relativo de ejecución de estos triggers es indeterminado. Si el orden de ejecución de
estos triggers es importante en su aplicación, puede utilizar la cláusula FOLLOWS disponible a
partir de la versión 11. Esta cláusula permite indicar que el trigger debe ejecutarse después de
los triggers enumerados.
ENABLE/DISABLE
Esta cláusula permite indicar si el trigger está o no activo desde el momento de su creación;
por defecto, un trigger de nueva creación está activo. Crear un trigger desactivado permite
verificar que se compila correctamente antes de ponerlo realmente en servicio. Un trigger
creado desactivado puede activarse más adelante utilizando una sentencia ALTER
TRIGGER...ENABLE.
WHEN (condición)
Los datos de la tabla a la que está asociado el trigger son inaccesibles desde las instrucciones
del bloque. Solo la fila que se está modificando es accesible a través de dos variables de tipo
RECORD: OLD y NEW, las cuales poseen la estructura de la tabla o de la vista asociada. Estas
variables pueden utilizarse en la cláusula WHEN del trigger o en el bloque de instrucciones. En
este último caso se referencian como variables host mediante el prefijo
":" (:OLD.nombre_campo, :NEW.nombre_campo).
La palabra OLD permite conocer qué fila se va a eliminar en un trigger DELETE o la fila que se
va a modificar en un trigger UPDATE. La palabra NEW permite conocer cuál es la nueva fila
insertada en un trigger INSERT o la fila tras su modificación en un trigger UPDATE.
Los nombres OLD y NEW están definidos de manera predeterminada, aunque es posible utilizar
otros nombres empleando la cláusula REFERENCING OLD AS nuevo_nombre NEW AS
nuevo_nombre. Esta cláusula se incluye justo antes de la cláusula FOR EACH ROW (si existe)
en la definición del trigger.
Ejemplo
Ejecución de un bloque PL/SQL antes de una eliminación en la tabla CLIENTES por parte del
usuario FLORENCIO:
Ejecución de un bloque PL/SQL después de actualizar cada fila de la tabla ARTICULOS cuando el
precio antiguo es mayor que el nuevo:
Para cada pedido, se desea conocer el nombre del usuario de Oracle que lo ha introducido. La
primera etapa consiste en añadir una nueva columna a la tabla de pedidos. Esta columna debe
aceptar el valor NULL ya que, para las filas de los pedidos existentes, el nombre del usuario de
Oracle es desconocido.
Tabla modificada.
SQL>
Trigger creado.
SQL>
Se desea saber el número de pedidos introducido por el usuario de Oracle. Para evitar escribir
una consulta que recorra la tabla de pedidos completa, operación que puede resultar muy
pesada, el trigger se limita a actualizar una tabla de estadísticas.
Tabla creada.
SQL>
SQL>
La escritura de un trigger puede complicarse cuando existen ciertos tratamientos comunes, por
ejemplo, las instrucciones INSERT y UPDATE mientras que otros son específicos de la inserción
o bien de la actualización de los datos. Una primera solución consiste en escribir dos triggers,
uno para la instrucción INSERT y otro para la instrucción UPDATE. De ello resulta entonces una
cierta redundancia de codificación nada deseable (mantenimiento más pesado del código). Oracle
propone los predicados INSERTING, UPDATING y DELETING que permiten saber dentro del
trigger si el código PL/SQL se ejecuta tras una instrucción INSERT, UPDATE o DELETE. Estos
predicados devuelven un valor booleano y se utilizan en la condición de test de una instrucción
IF. De este modo, es posible escribir un trigger común a las instrucciones INSERT y UPDATE, por
ejemplo, conservando la ejecución condicional de ciertas instrucciones.
Ejemplos
En el ejemplo siguiente, el trigger será común para las instrucciones INSERT y DELETE para
mantener al día el atributo CALCULA que representa el número de pedidos de un cliente:
Trigger created.
SQL>
El siguiente ejemplo muestra el interés de los triggers de tipo instead of. Previamente, se crea
la vista CLIORENSE. Esta vista permite saber qué clientes viven en Orense. A continuación, a
través de esta vista se añade un cliente, pero es posible recuperarlo.
Vista creada.
1 fila creada.
SQL>
Debe definirse por tanto un trigger de tipo INSTEAD OF para resolver este fallo y garantizar que
los elementos insertados en una vista estén visibles a través de la misma.
Trigger creado.
1 fila creada.
SQL> select * from cliorense;
SQL>
Trigger de tipo INSTEAD OF asociado a una vista (VIEW) sobre las tablas PEDIDOS y LINEASPED:
SQL> create or replace view vpedlin (numped, fechaped, numlin,
refart, cantped) as
2 select l.numped, fechaped, numlin, refart, cantped
3 from pedidos c, lineasped l
4 where c.numped=l.numped;
Vista creada.
Trigger creado.
SQL>
Sintaxis
Las cláusulas FOLLOWS, ENABLE/DISABLE y WHEN son las mismas que para un trigger
simple.
El código del trigger tiene hasta cuatro secciones de código, cada una de ellas correspondiente
a un instante de activación; cada sección tiene la estructura siguiente:
instante_activación IS
[declaraciones_locales]
BEGIN
instrucciones
END instante_activación
Como ejemplo, vamos a crear un trigger que audita las modificaciones de salario de los
empleados:
Trigger creado.
Este trigger compuesto define dos declaraciones comunes: una variable acumulado, para
almacenar la cantidad acumulada de las modificaciones de salario y un procedimiento mostrar,
para visualizar la información por pantalla.
En la sección after each row el trigger calcula la variación de salario para la fila actual,
almacena este valor en una variable local a la sección ( incremento) y, a continuación, la
muestra antes de añadirla a la variable global acumulado.
NUMEROEMPLEADO SALARIO
----------------------------- ----------
1 1200
2 1800
SQL> update EMPLEADO set SALARIO=SALARIO * 1.01;
1: 12
2: 18
Total: 30
2 filas actualizadas.
Los sucesos del sistema son el arranque y la desconexión de la instancia de Oracle (startup y
shutdown) y el tratamiento de los errores. Los triggers de arranque y de desconexión tienen
como ámbito el conjunto de la instancia de Oracle, mientras que el trigger de tratamiento de
errores puede definirse en el nivel de esquema o en el nivel de base de datos.
En el caso de sucesos de usuario, pueden existir triggers para las operaciones de inicio y cierre
de sesión (logon y logoff), y para supervisar y controlar la ejecución de las instrucciones DDL
(CREATE, ALTER y DROP) y DML (INSERT, UPDATE y DELETE).
Los triggers DML se asocian a una tabla y a una instrucción DML. Su definición y uso se ha
detallado anteriormente en este capítulo.
Al escribir estos triggers, es posible emplear atributos para identificar de forma precisa el origen
del suceso y adaptar el tratamiento necesario en consecuencia.
1. Atributos
ora_client_ip_address
Permite conocer la dirección IP del equipo cliente que actúa como origen de la conexión.
ora_database_name
ora_des_encrypted_password
Permite conocer las descripciones cifradas de contraseñas del usuario que se hayan creado o
modificado.
ora_dict_obj_name
ora_dict_obj_name_list
Permite conocer la lista de todos los nombres de objetos que se han modificado.
ora_dict_obj_owner
ora_dict_obj_owner_list
Permite conocer la lista de todos los propietarios de los objetos que se han modificado.
ora_dict_obj_type
ora_grantee
ora_instance_num
Número de la instancia.
ora_is_alter_column
ora_is_creating_nested_table
ora_is_drop_column
ora_is_servererror
Devuelve TRUE si el número de error que se pasa como parámetro se encuentra en la pila de
errores.
ora_login_user
ora_privileges_list
ora_revokee
ora_server_error
Devuelve el número de error de Oracle que se encuentra en la pila, cuya posición se ha pasado
como parámetro (la parte superior de la pila corresponde a la posición 1).
ora_server_error_depth
Número de errores en la pila de errores.
ora_server_error_msg
ora_server_error_num_params
ora_server_error_param
ora_sql_text
ora_sysevent
ora_with_grant_option
ora_space_error_info
Si el error es relativo a una falta de espacio, da información acerca del objeto afectado.
STARTUP
SHUTDOWN
Este suceso se activa justo antes de que el servidor inicie el proceso de desconexión de la
instancia. Si se produce una desconexión inesperada del servidor de base de datos, este
suceso no se ejecutará.
SERVERERROR
Este suceso se activa cuando se produce un error de Oracle. No obstante, este trigger no se
activa para los errores ORA-1034, ORA-1403, ORA-1422, ORA-1423 y ORA-4030, ya que son
demasiado graves como para que el proceso pueda continuar ejecutándose.
Sintaxis
Para los sucesos STARTUP y SERVERERROR solo están disponibles los triggers de tipo AFTER y
para el suceso SHUTDOWN solo está disponible el trigger de tipo BEFORE.
Ejemplo
Trigger creado.
SQL>
3. Sucesos de usuario
AFTER LOGON
BEFORE LOGOFF
Debe consultar la lista anterior para saber si el suceso puede tratarse mediante un trigger de
tipo BEFORE o AFTER.
Ejemplo
Trigger creado.
SQL>
Sintaxis
Ejemplo
Trigger modificado.
Trigger modificado.
Tabla modificada.
Tabla modificada.
SQL>
Para obtener información sobre los triggers, es necesario consultar el diccionario de datos. Las
tres vistas del diccionario que hay que utilizar son: USER_TRIGGERS, ALL_TRIGGERS
y DBA_TRIGGERS.
La columna BASE_OBJECT_TYPE permite saber si el trigger está basado en una tabla, una vista,
un esquema o en la base de datos completa.
SQL>
Procedimientos almacenados
Un procedimiento almacenado es un bloque de código PL/SQL nominado, almacenado en la base
de datos y que se puede ejecutar desde aplicaciones u otros procedimientos almacenados. En
un bloque PL/SQL, basta con hacer referencia al procedimiento por su nombre para ejecutarlo.
En SQL*Plus, se puede utilizar la instrucción EXECUTE.
Sintaxis
OR REPLACE
parámetro
Especifica una variable pasada como parámetro que puede utilizarse en el bloque.
IN
OUT
tipo
Ejemplo
Procedimiento creado.
SQL>
Uso en SQL*Plus:
DECLARE
x char;
BEGIN
...
elim_art(x);
...
END;
Funciones almacenadas
Al igual que los procedimientos, una función es un fragmento de código PL/SQL, pero la función
devuelve un valor. Estas funciones almacenadas se utilizan como las funciones de Oracle.
Sintaxis
OR REPLACE
parámetro
Especifica un parámetro que se pasa como dato de entrada y que se usa como una variable
dentro del bloque.
tipo
RETURN tipo
Ejemplo
Función factorial:
FACTORIAL(5)
------------
120
SQL>
A partir de la versión 11, es posible indicar a Oracle que conserve en memoria el resultado de la
llamada a una función. Cuando se activa esta funcionalidad para una función, cada vez que se
llama a esta función con valores diferentes de los parámetros, Oracle almacena en caché el valor
de los parámetros y el resultado de la función. Cuando más adelante se llama de nuevo a esta
función con los mismos valores de los parámetros, se recupera el resultado de la caché en lugar
de calcularlo de nuevo.
Para activar esta funcionalidad para una función, es suficiente con incluir la
cláusula RESULT_CACHE en la definición de la función.
Sintaxis
La cláusula opcional RELIES_ON permite especificar una o varias tablas o vistas de las que
depende la función. Cuando se modifican los datos de las tablas afectadas, la caché se invalida
y se reconstruye en el momento de las llamadas posteriores a la función.
Ejemplo
4 is
5 resultado varchar2(40);
6 fin timestamp;
7 begin
8 -- código que simula un tiempo de ejecución largo
9 fin:= systimestamp + 2/24/60/60;
10 while systimestamp fin
11 loop
12 null;
13 end loop;
14 -- seleccionar y devolver el valor solicitado
15 select valor into resultado from parametros where codigo = n;
16 return resultado;
17 end;
18 /
Función creada.
VALOR_PARAMETRO(1)
--------------------------------------
ENI
Terminado: 00:00:01.62
SQL> select valor_parametro(1) from dual;
VALOR_PARAMETRO(1)
--------------------------------------
ENI
Terminado: 00:00:00.15
SQL> insert into parametros(codigo,valor)
2 values(123,’UNO DOS TRES’);
1 fila creada.
Terminado: 00:00:00.12
SQL> commit;
Validación efectuada.
Terminado: 00:00:00.10
SQL>select valor_parametro(1) from dual;
VALOR_PARAMETRO(1)
--------------------------------------
ENI
Terminado: 00:00:01.60
SQL>select valor_parametro(1) from dual;
VALOR_PARAMETRO(1)
--------------------------------------
ENI
Terminado: 00:00:00:17
En la primera llamada con 1 como valor del parámetro, la función devuelve el resultado en poco
más de 1,5 segundos. En la segunda llamada con el mismo valor del parámetro, la función solo
utiliza 15 centésimas de segundo para ejecutarse. Después de la modificación de los datos de la
tabla, una nueva llamada con 1 como valor del parámetro, se ejecuta de nuevo en poco más de
1,5 segundos: la caché del resultado se ha invalidado, ya que la función depende de la tabla
modificada (clausula RELIES_ON).
Desde la versión 12, es posible añadir la directiva UDF en la definición de una función para indicar
al compilador que esta función se destina principalmente para su uso en sentencias SQL. El
compilador PL/SQL optimiza la compilación para mejorar el rendimiento de la función en este
contexto.
Ejemplo
Función creada.
Tiempo transcurrido: 00:00:00.02
SQL>
SQL> -- Llamada a esta función en una sentencia SQL
SQL> select count(distinct may(nombre)) from employees;
COUNT(DISTINCTMAY(NOMBRE))
-----------------------
43092
Función creada.
COUNT(DISTINCTMAY(NOMBRE))
-----------------------
43092
En este ejemplo, vemos que la llamada a la función compilada con la directiva UDF es mucho
más rápida.
Adicionalmente, desde la versión 12, es posible definir una función en la cláusula WITH de una
consulta SELECT. Esta función se comporta como una función local a la consulta que la puede
llamar. En este caso, incluso la llamada repetida a esta función local es más rápida que la llamada
a una función almacenada.
Elemplo
COUNT(DISTINCTMAY(NOMBRE))
-----------------------
43092
Paquetes
Un paquete es un objeto del esquema que agrupa de forma lógica elementos PL/SQL relacionados
tales como tipos de datos, funciones, procedimientos y cursores.
Los paquetes se dividen en dos partes: una cabecera o especificación y un cuerpo (body). La
cabecera permite describir el contenido del paquete y conocer el nombre y los parámetros de
llamada de las funciones y procedimientos. Pero el código no forma parte de la cabecera o
especificación, sino que se incluye en el cuerpo del paquete. Esta separación de especificaciones
y código permite implantar un paquete sin que el usuario pueda visualizar el código y permite,
además, adaptar el código de forma sencilla para cumplir nuevas reglas.
Modularidad
El hecho de agrupar de forma lógica elementos PL/SQL relacionados hace más fácil la
comprensión de los diferentes elementos del paquete y su uso se simplifica enormemente.
Durante el proceso de definición de una aplicación, los paquetes hacen posible definir en la
primera etapa del diseño únicamente la cabecera de los paquetes y realizar así las
compilaciones. El cuerpo del paquete solo será necesario para ejecutar la aplicación.
Datos ocultos
Con un paquete es posible hacer que determinados elementos no sean visibles para el usuario
del paquete. Esto permite crear elementos que solo pueden utilizarse dentro del paquete y que
por tanto simplifican la escritura del mismo.
Adición de funcionalidades
Las variables y cursores públicos del paquete existen durante toda la sesión, por lo que es un
modo de compartir información entre los diferentes subprogramas en una misma sesión.
El paquete se encuentra en memoria desde que se produce una llamada a un elemento que
forma parte de él. El acceso a los diferentes elementos del paquete es entonces mucho más
rápido que la llamada a funciones y procedimientos independientes.
1. Cabecera
El ámbito de todos los elementos definidos en la especificación del paquete es global para el
paquete y local para el esquema del usuario.
La sección de especificación permite precisar qué recursos del paquete podrán emplear las
aplicaciones. En esta sección de especificación deben aparecer todos los datos que permitan
saber cómo usar los recursos del paquete (parámetros de llamada, tipo del valor devuelto).
Sintaxis
Ejemplo
Paquete creado.
SQL>
La especificación del cuerpo del paquete no es necesaria si la cabecera del mismo solo contiene
definiciones de tipos y declaraciones de variables.
Para asegurarse de que en el cuerpo del paquete todos los elementos necesarios en la
especificación están bien definidos, PL/SQL realiza una comparación punto por punto. De este
modo, con la excepción de los espacios, la declaración hecha en la especificación debe encontrar
su equivalente exacto en el cuerpo. Si no es así, se generará una excepción durante la
compilación.
El cuerpo del paquete puede, además, contener definiciones locales de cursores, variables, tipos,
funciones y procedimientos que se emplearán de manera interna en el paquete. Estos elementos
no serán accesibles desde fuera del paquete.
Sintaxis
Ejemplo
SQL>
3. Uso
Ejemplo
SQL> begin
2 :V_NUMCLI := GESTION_CLIENTES.CRE_CLI
3 (’CESAR’,’Cava Baja’,13000,’MARBELLA’);
4 end;
5 /
V_NUMCLI
----------
2003
SQL> select NUMCLI, ltrim(NOMCLI) NOMCLI, CIUDAD
2 from CLIENTES order by NUMCLI
3 /
10 filas seleccionadas.
SQL> begin
2 GESTION_CLIENTES.ELIM_CLI(152);
3 end;
4 /
9 filas seleccionadas.
SQL>
4. Cursores
En el cuerpo del paquete, ahora será obligatorio definir la cláusula SELECT asociada al cursor.
Por supuesto, las columnas especificadas después de SELECT y el tipo de datos indicado para el
valor devuelto en la sección de especificación deben corresponderse de forma exacta.
La definición de los cursores dentro del paquete ofrece una mayor flexibilidad, ya que es posible
cambiar su definición sin estar obligados a modificar la sección de especificación del paquete.
Para utilizar dentro de un bloque PL/SQL un cursor definido en un paquete, es necesario preceder
el nombre del cursor con el nombre del paquete. La notación es la misma que la empleada para
llamar a funciones o procedimientos definidos en un paquete.
El ámbito de un cursor de paquete no está limitado al bloque en el que se abre, por lo que es
posible mantener abierto el cursor durante toda la sesión y cerrarlo al desconectarse.
Transacciones autónomas
Una transacción es un conjunto de comandos SQL que constituye una unidad lógica de
tratamiento. La totalidad de las instrucciones que definen la unidad deben ejecutarse
correctamente, o no se ejecutará ninguna instrucción. En determinadas aplicaciones es preciso
ejecutar una transacción dentro de otra.
Una transacción autónoma es una transacción independiente que se ejecuta después de otra
transacción, la transacción principal. Durante la ejecución de la transacción autónoma, la
ejecución de la transacción principal se detiene.
Las transacciones autónomas son totalmente independientes; esta independencia permite
construir aplicaciones más modulares. Por supuesto, las transacciones autónomas presentan las
mismas características que las transacciones regulares.
Para definir una transacción autónoma hay que emplear la directiva de compilación
(pragma)AUTONOMOUS_TRANSACTION. Esta directiva debe aparecer en la sección de
declaración de variables de los bloques PL/SQL anónimos, funciones, procedimientos y triggers.
Generalmente, las directivas de compilación se incluyen al principio de la sección de declaración
de variables, lo que facilita la relectura del programa.
Ejemplo
SQL>
Las modificaciones llevadas a cabo por la transacción autónoma son visibles para las restantes
transacciones inmediatamente después de su validación (COMMIT), incluso aunque la
transacción principal que haya llamado a la transacción autónoma no haya terminado. Las
modificaciones también serán visibles para la transacción principal. Para que la transacción
principal no pueda conocer las modificaciones realizadas, es necesario especificar el nivel de
aislamiento de la transacción utilizando el siguiente comando: SET TRANSACTION ISOLATION
LEVEL SERIALIZABLE.
Ejemplo
SQL> begin
2 insert into clientes(numcli,nomcli)
3 values (14,’pablo’);
4 nombre_correcto();
5 rollback;
6 end;
7 /
12 filas seleccionadas.
SQL>
También se pueden definir triggers como transacciones autónomas. Esta opción es interesante
cuando los triggers se usan para llevar un registro de las operaciones que se realizan sobre una
tabla, incluso aunque la operación no sea validada. El hecho de que el trigger sea autónomo
permite asegurar que la operación llevada a cabo se registra en la base de datos, incluso aunque
se anule la operación que dio origen al trigger (ROLLBACK).
Además, a diferencia de los triggers tradicionales, los triggers autónomos pueden ejecutar
instrucciones SQL DDL utilizando instrucciones de SQL dinámico.
La cláusula RETURNING
En el caso en que la instrucción INSERT se utilice para insertar una única línea de datos en la
tabla es posible utilizar la cláusula RETURNING para conocer por ejemplo el valor de una columna
o bien el resultado de un cálculo. Esta funcionalidad resulta especialmente práctica cuando una
secuencia se asocia a la columna y la valoración de la columna a partir de la secuencia se realiza
desde un trigger de base de datos. La cláusula RETURNING permite conocer el valor que se ha
generado e insertado en la tabla. Sin esta cláusula, los accesos a la base se multiplican para
conocer el valor asignado a la columna.
Sintaxis
Ejemplo
En el ejemplo siguiente se implementa una función de creación de clientes. Esta función utiliza
una secuencia de Oracle para fijar el número de clientes. La función devuelve el valor del número
de cliente.
Function created.
SQL>
También es posible utilizar esta cláusula RETURNING en una instrucción DELETE para obtener
uno o más datos sobre la línea borrada.
Sintaxis
Por último, es posible utilizar esta cláusula RETURNING con la instrucción de actualización
UPDATE. Como para las instrucciones INSERT y DELETE, la cláusula RETURNING solo es
concebible en el caso en que la instrucción UPDATE actualice una única fila de información en la
base de datos.
Sintaxis
SQL dinámico
El SQL dinámico es una técnica que permite crear las sentencias SQL de forma dinámica durante
la ejecución del código PL/SQL. El SQL dinámico permite crear aplicaciones más flexibles, ya que
los nombres de objeto utilizados por un bloque PL/SQL pueden ser desconocidos en el momento
de la compilación. Por ejemplo, un procedimiento puede utilizar una tabla cuyo nombre sea
desconocido antes de ejecutar dicho procedimiento.
Debe recordarse que, en el código SQL estático, todos los datos son conocidos en el momento
de la compilación y que, por supuesto, las instrucciones SQL estáticas no cambian de una
ejecución a otra. Esta solución ofrece sus ventajas, ya que el éxito de la compilación garantiza
que las instrucciones SQL hagan referencia a objetos válidos de la base de datos. La compilación
también verifica que se dispone de los privilegios necesarios para acceder y para trabajar con
los objetos de la base de datos. Además, el rendimiento del código SQL estático es mayor que
el del SQL dinámico.
Por estas razones, el SQL dinámico solo debe emplearse si el SQL estático no es capaz de
responder a nuestras necesidades o si la solución con código SQL estático es mucho más
compleja que con SQL dinámico.
No obstante, el SQL estático tiene ciertas limitaciones que se superan mediante el SQL dinámico.
Se utilizará el SQL dinámico si, por ejemplo, no se conocen de antemano las instrucciones SQL
que tienen que ejecutarse en el bloque PL/SQL, o si el usuario debe proporcionar datos para
construir las instrucciones SQL que hay que ejecutar.
Además, utilizando código SQL dinámico es posible ejecutar instrucciones DDL (CREATE, ALTER,
DROP, GRANT y REVOKE), así como los comandos ALTER SESSION y SET ROLE, dentro del
código PL/SQL, lo que no es posible con el código SQL estático.
El SQL dinámico ofrece un mejor rendimiento que el paquete DBMS_SQL y más posibilidades
que éste.
1. EXECUTE IMMEDIATE
El comando EXECUTE IMMEDIATE permite verificar la sintaxis y ejecutar de forma dinámica una
instrucción SQL o un bloque anónimo PL/SQL.
Sintaxis
cadena_dinámica
Representa la instrucción SQL o el bloque PL/SQL. A partir de la versión 11, el tamaño del
código dinámico ya no está limitado a 32 KB ; si es necesario, puede emplearse una variable
de tipo CLOB.
variable
registro
Es una variable estructurada que contendrá una fila seleccionada.
argumento
Especifica los valores que se pasan a la instrucción SQL o al bloque PL/SQL. Estos argumentos
pueden representar valores de lectura/escritura.
Excepto consultas que devuelvan varias filas, es posible ejecutar cualquier instrucción SQL o
bloque PL/SQL. Los argumentos no pueden contener el nombre de objetos de la base de datos
que vayan a utilizarse en las instrucciones SQL o PL/SQL.
El comando INTO solo debe utilizarse para consultas SELECT que devuelvan una sola fila de
valores. A cada columna devuelta por el comando SELECT debe corresponder una variable o un
campo del registro.
Ejemplo
SQL dinámico: el siguiente ejemplo muestra un posible uso del código SQL dinámico y las
diferentes posibilidades de la instrucción EXECUTE IMMEDIATE.
SQL> DECLARE
2 consulta VARCHAR2(200);
3 bloque_pl VARCHAR2(200);
4 vnumcli pedidos.numcli%type:=8;
5 vnumped pedidos.numped%type:=6;
6 vdia date := sysdate();
7 vestado char(2):=’EC’;
8 vclientes clientes%rowtype;
9 vprecio articulos.precio%type;
10 vrefart articulos.refart%type:=’ZZ01’;
11 BEGIN
12 -- ejecución de una instrucción DDL
13 EXECUTE IMMEDIATE ’CREATE TABLE clientes_fieles(numcli number(6), ca
number(8,2))’;
14 -- instrucción DML con paso de argumento de entrada
15 consulta:=’INSERT INTO pedidos(numped, numcli, fechaped, estadoped)
values(:1, :2, :3, :4)’;
16 EXECUTE IMMEDIATE consulta USING vnumcli, vnumped, vdia, vestado;
17 --construcción de un bloque PL/SQL anónimo
18 bloque_pl:=’BEGIN UPDATE articulos set precio=precio*0.99; END;’;
19 EXECUTE IMMEDIATE bloque_pl;
20 -- uso de la palabra clave INTO
21 consulta:=’SELECT * FROM clientes WHERE numcli=:1’;
22 EXECUTE IMMEDIATE consulta INTO vclientes USING vnumcli;
23 -- uso de la cláusula RETURNING INTO
24 consulta:=’UPDATE articulos set precio=200 WHERE refart=:1 RETURNING
precio INTO :2’;
25 EXECUTE IMMEDIATE consulta USING vrefart RETURNING INTO vprecio;
26 END;
27 /
SQL>
Cuando una instrucción INSERT, UPDATE o DELETE incluye una cláusula de tipo RETURNING, los
argumentos de salida se pueden incluir en la cláusula USING o en la cláusula RETURNING INTO.
En las nuevas aplicaciones debe utilizarse la cláusula RETURNING INTO.
SQL> DECLARE
2 consulta VARCHAR2(200);
3 vrefart articulos.refart%type:=’ZZ01’;
4 vdes articulos.descripcion%type;
5 vprecio articulos.precio%type:=150;
6 viva articulos.codiva%type;
7 BEGIN
8 consulta:=’UPDATE articulos set precio=:1 WHERE refart=:2
9 RETURNING descripcion, codiva into :3, :4’;
10 /* uso de la cláusula USING */
11 EXECUTE IMMEDIATE consulta USING vprecio, vrefart, OUT vdes, OUT viva;
12 /* uso de la cláusula RETURNING INTO */
13 EXECUTE IMMEDIATE consulta USING vprecio, vrefart RETURNING INTO vdes,
viva;
14 END;
15 /
SQL>
Procedimiento creado.
SQL>
SQL> DECLARE
2 bloque_pl varchar2(200);
3 vnumped pedidos.numped%type;
4 vnumcli pedidos.numcli%type;
5 BEGIN
6 bloque_pl :=’BEGIN agregar_ped(:a,:b); END;’;
7 EXECUTE IMMEDIATE bloque_pl
8 USING IN OUT vnumped, vnumcli;
9 END;
10 /
SQL>
Estos tres comandos se emplean para tratar las consultas dinámicas que van a ejecutarse sobre
varias filas de datos. Como con los cursores tradicionales, en primer lugar hay que abrir el cursor
con el comando OPEN FOR, que corresponde a una consulta de tipo SELECT. Después, en el
bloque PL/SQL, podrán extraerse todas las filas de datos una por una usando el comando FETCH.
Para terminar, cuando se hayan procesado todas las filas, habrá que cerrar el cursor mediante
el comando CLOSE.
El comando OPEN FOR permite asociar a una variable de tipo cursor una consulta SELECT que
devuelva varias filas de datos. La consulta se ejecuta y el cursor se sitúa en la primera fila de
datos. A diferencia del cursor estático, la instrucción OPEN FOR de los cursores dinámicos dispone
de una cláusula USING opcional que permite pasar argumentos a la consulta.
Sintaxis
Ejemplo
En el siguiente ejemplo se declara una variable de tipo cursor y, a continuación, se asocia a una
instrucción SELECT que va a recuperar datos de una tabla.
declare
type CliCurTyp is ref cursor;
ccli CliCurTyp; -- variable cursor
vnum clientes.numcli%type;
vciudad clientes.ciudad%type:=’Orense’;
begin
open ccli for ’Select numcli, ciudad from clientes where ciudad=:v’
using vciudad;
...
end;
/
Solo cuando el cursor está abierto se evalúan todos los argumentos de la consulta. Por tanto,
para recuperar datos correspondientes a diferentes valores del argumento es necesario abrir de
nuevo el cursor pasándole un nuevo valor para el parámetro.
b. FETCH
El comando FETCH devuelve una fila de datos procedente del conjunto de resultados
correspondiente a la ejecución de la consulta SELECT después de haber abierto el cursor. Para
cada una de las columnas especificadas después del comando SELECT es necesario prever una
variable en el entorno PL/SQL que ejecuta el cursor dinámico.
Sintaxis
FETCH variable_cursor
INTO {variable, ...|registro}
Ejemplo
declare
type CliCurTyp is ref cursor;
ccli CliCurTyp; -- variable cursor
vnum clientes.numcli%type;
vciudad clientes.ciudad%type:=’Orense’;
begin
open ccli for ’Select numcli, ciudad from clientes where ciudad=:v’
using vciudad;
loop
fetch ccli into vnum, vciudad; --extraer la siguiente fila
exit when ccli%notfound; --salir del bucle si no hay más filas
--tratar los datos
end loop;
...
end;
Cada ejecución del comando FETCH extrae una fila del conjunto de resultados y sitúa el cursor
en la siguiente fila.
Si se ejecuta una instrucción FETCH sobre un cursor cerrado o que nunca se ha abierto se genera
la excepción INVALID_CURSOR.
c. CLOSE
El comando CLOSE desactiva una variable de tipo cursor. Después de ejecutar este comando, el
conjunto de resultados creado por el comando OPEN FOR ya no existe.
Sintaxis
CLOSE variable_cursor
Ejemplo
declare
type CliCurTyp is ref cursor;
ccli CliCurTyp; -- variable cursor
vnum clientes.numcli%type;
vciudad clientes.ciudad%type:=’Orense’;
begin
open ccli for ’Select numcli, ciudad from clientes where ciudad=:v’
using vciudad;
loop
fetch ccli into vnum, vciudad; --extraer la línea siguiente
exit when ccli%notfound; --salir del bucle si no hay más filas
--tratar los datos
end loop;
close ccli;
end;
Cuando se intenta cerrar un cursor que ya está cerrado, PL/SQL genera la excepción
INVALID_CURSOR.
Existen algunas reglas que permiten sacar el mejor partido de los cursores dinámicos en términos
de rendimiento y de calidad de programación.
En el fragmento de código que se detalla a continuación, Oracle tiene que establecer un nuevo
cursor para cada nueva apertura. Esta generación de cursores tan similares puede degradar el
rendimiento del servidor.
La conversión del número de cliente contenido en la variable vnumcli como cadena de caracteres
permite construir adecuadamente el comando dinámico SQL.
La mejora del rendimiento se logra usando un argumento. Esta solución permite a Oracle
reutilizar el mismo cursor para diferentes valores del argumento.
El siguiente procedimiento elimina una tabla cualquiera de la base de datos. Utilizando código
SQL dinámico, el fragmento de código sería el siguiente:
Al ejecutarse, este procedimiento genera un error de tipo "nombre de tabla no válido". Esto se
debe al hecho de que los argumentos no pueden utilizarse para pasar nombres de objetos de la
base de datos. En lugar de este código, habría que escribir lo siguiente:
Las variables que se incluyen en las instrucciones de SQL dinámico están asociadas a los
argumentos que siguen a la cláusula USING de acuerdo a su posición y no al nombre que sirve
para identificarlos como argumentos. Por tanto, si la misma variable aparece dos veces en la
instrucción de SQL dinámico, entonces deberá aparecer dos veces el mismo argumento detrás
de la cláusula USING.
Sin embargo, si se emplea un bloque PL/SQL, no es necesario pasar dos veces el mismo
argumento. En efecto, en los bloques PL/SQL las variables se asocian con los argumentos de
acuerdo con su orden de definición, pero si aparece varias veces la misma variable, solo la
primera aparición se asociará con un argumento; por tanto, puede usarse el siguiente código,
que es más sencillo de escribir:
Los cursores explícitos poseen los cuatro atributos siguientes: %FOUND, %NOTFOUND,
%ISOPEN y %ROWCOUNT, que permiten obtener información acerca de la correcta ejecución
del cursor, con independencia de que provenga de una instrucción SQL estática o dinámica. Para
llevar a cabo correctamente sus operaciones, Oracle utiliza cursores implícitos. Es posible
conocer los atributos de estos cursores mediante la palabra clave SQL. De este modo, el atributo
%ROWCOUNT en los cursores implícitos permite conocer el correcto desarrollo, o no, de la última
instrucción SQL dinámica que haya sido ejecutada.
Ejemplo
Función que utiliza el atributo del cursor implícito para comprobar que la instrucción SQL
dinámica se ha ejecutado correctamente. En el siguiente ejemplo, después de la eliminación de
filas se utiliza el atributo %ROWCOUNT para conocer el número de filas que se han visto
afectadas por esta instrucción.
Función creada.
SQL>
Es preciso probar la función desde un bloque PL/SQL, ya que no se puede ejecutar una función
DML desde una consulta SELECT.
En ocasiones, puede ser necesario pasar valores NULL como argumentos a instrucciones SQL
dinámicas. La solución más lógica sería escribir el comando siguiente:
Pero, como ocurre con frecuencia, el valor NULL no se gestiona de manera tan sencilla. En efecto,
no se puede utilizar el literal NULL detrás de la cláusula USING. Para poder salvar esta limitación
debe inicializarse una variable con el valor NULL y utilizarla igual que un parámetro.
declare
c_null char(1); --la variable se inicializa a NULL
begin
execute immediate ’UPDATE clientes set ciudad=:x’ using c_null;
end;
f. Permisos de usuario
Por omisión, un procedimiento almacenado se ejecuta usando los permisos del usuario de Oracle
que define el procedimiento y no con los permisos del usuario que llama al procedimiento.
Determinados procedimientos están vinculados al esquema sobre el que se han definido.
Por ejemplo, supongamos que el procedimiento siguiente está definido sobre el esquema del
usuario scott:
Procedimiento creado.
SQL>
El procedimiento borrar permite eliminar cualquier objeto del esquema simplemente pasando
como parámetro el tipo de objeto que se desea borrar y su nombre. Con el fin de facilitar la
gestión de los objetos en cada esquema, se ha concedido el privilegio EXECUTE al usuario María.
Cuando este usuario desee borrar la tabla CLIENTES de su esquema, tendrá que llamar al
procedimiento borrar de la siguiente forma:
Llamada terminada.
SQL>
Dado que el nombre del objeto se ha pasado sin hacer referencia al esquema, en realidad se ha
hecho referencia a la tabla CLIENTES del esquema scott, que es el creador de este procedimiento
que María intenta utilizar para eliminar la tabla.
Procedimiento creado.
SQL>
Una función llamada desde un comando SQL debe cumplir una determinada serie de reglas que
permitan controlar los efectos colaterales. Para eliminar estas restricciones se puede usar la
directiva de compilación RESTRICT_ REFERENCES. Esta directiva indica que la función no se va
a ejecutar en modo lectura/escritura en una tabla de la base de datos o una variable de un
paquete.
No obstante, si el cuerpo de la función contiene una instrucción dinámica de tipo INSERT, UPDATE
o DELETE, entonces la función viola las reglas de no escritura en la base de datos (Write No
Database State: WNDS) y de no lectura en la base de datos (Read No Database State: RNDS).
Esto ocurre porque las reglas que afectan a las instrucciones dinámicas solo se verifican en
tiempo de ejecución. En un comando EXECUTE IMMEDIATE, solo la cláusula INTO permite
detectar una violación de tipo RNDS en tiempo de compilación.
No es posible eliminar todos los interbloqueos que pueden producirse. Sin embargo, sí es posible
tomar ciertas precauciones con el fin de evitar que el usuario se bloquee a sí mismo. En concreto,
nunca debe intentarse modificar (ALTER) o borrar (DROP) un subprograma o un paquete que se
esté utilizando, como en el ejemplo siguiente.
Además del SQL dinámico, Oracle proporciona el paquete DBMS_SQL, que permite ejecutar de
forma dinámica instrucciones SQL.
Para utilizar el SQL dinámico la base de datos debe ser compatible con la versión 8.1.0 o una
versión superior del servidor de base de datos.
El paquete DBMS_SQL es una biblioteca PL/SQL que permite la ejecución de instrucciones SQL
construidas de forma dinámica.
Las principales ventajas del SQL dinámico con respecto al paquete DBMS_SQL son:
la facilidad de uso,
las mejoras de rendimiento en la ejecución,
el soporte para los tipos de datos definidos por el usuario.
Pero también el paquete DBMS_SQL presenta sus ventajas respecto del SQL dinámico:
Desde la versión 12, este paquete se puede usar para devolver un resultado directamente, de
manera implícita, sin pasar por un parámetro OUT o un resultado de función de tipo REF CURSOR
(Implicit Statement Results). Esta funcionalidad resulta interesante para facilitar la migración a
partir de otras bases de datos que permitan devolver un resultado de esta manera.
Ejemplo
SQL>
SQL> -- Llamada al procedimiento
SQL> EXECUTE lista_articulos
Resultados #1
REFART NOMBRE
------------ ---------------
CD50
AB22 ALFOMBRA PERSA
CD21 Pletina láser
CD50 CADENA HIFI
ZZZZ CANTIMPLORA
AA00 REGALO
ZZ01 LOTE ALFOMBRAS
7 filas seleccionadas.
Los resultados implícitos devueltos de esta manera se pueden explotar en diferentes entornos
de programación (Java, .NET, PHP, etc.).
CAST(COLLECT(DESIGNACION)ASCATALOGO)
---------------------------------------------------------------
CATALOGO(’Tapiz persa’, ’Pletina láser’, ’Artículo chuchería’,
’Alfombra’, ’Lote Alfombras’, ’Alfombra china’)
SQL>
6. Excepciones
En la mayoría de los casos, cuando se intenta acceder a un elemento de una colección que no
existe, PL/SQL genera una excepción predefinida. A continuación se enumeran las principales
excepciones que pueden generarse:
COLLECTION_IS_NULL
NO_DATA_FOUND
SUBSCRIPT_BEYOND_COUNT
SUBSCRIPT_OUTSIDE_LIMIT
VALUE_ERROR
DECLARE
TYPE LaLista IS TABLE OF VARCHAR2(50);
Compras LaLista; -- se inicializa a NULL
BEGIN
Compras(1):=’Zanahorias’; -- excepción COLLECTION_IS_NULL
Compras:=LaLista(’Tomates’,’Melón’,’Lechuga’); --inicializa
la colección
Compras(NULL):=’Patatas’;-- excepción VALUE_ERROR
Compras(0):=’Peras’;-- excepción SUBSCRIPT_OUTSIDE_LIMIT
Compras(4):=’Kiwis’;-- excepción SUBSCRIPT_BEYOND_COUNT
Compras.DELETE(1);-- supresión del elemento 1
IF Compras(1)=’Col’ THEN-- excepción NO_DATA_FOUND
...
END IF;
END;
Copia de datos por bloques
Completamente integrados con el sistema RDBMS de Oracle, el motor procedimental de PL/SQL
procesa todas las instrucciones procedimentales y el motor de SQL procesa todas las
instrucciones SQL. Estos dos motores interaccionan con frecuencia, ya que el código PL/SQL
trabaja con datos procedentes de la base de datos y los extrae mediante instrucciones SQL.
Cuando se pasa del motor PL/SQL al motor SQL, y viceversa, el servidor tiene una carga de
trabajo mayor. Con el fin de mejorar el rendimiento, es importante reducir el número de veces
que es necesario cambiar de motor. Las copias de datos por bloques ofrecen una solución que
permite reducir el número de interacciones entre estos dos motores.
Con la copia por bloques, las instrucciones SQL podrán aplicarse a toda la colección y no solo de
forma sucesiva a cada uno de los elementos.
El ejemplo siguiente, en el que se insertan filas en una tabla, permite comparar el tiempo
invertido con el procesamiento clásico de las instrucciones SQL en los bloques PL/SQL y el
procesamiento por bloques, el cual requiere menos tiempo.
Tabla creada.
SQL>
SQL> DECLARE
2 TYPE tabla_numeros IS TABLE OF NUMBER(4) INDEX BY BINARY_INTEGER;
3 TYPE tabla_nombres IS TABLE OF CHAR(5) INDEX BY BINARY_INTEGER;
4 LosNumeros tabla_numeros;
5 LosNombres tabla_nombres;
6 t1 number(5);
7 t2 number(5);
8 t3 number(5);
9 PROCEDURE top (t out number) IS
10 BEGIN SELECT TO_CHAR(SYSDATE,’SSSSS’) INTO t FROM DUAL; END;
11 BEGIN
12 -- Rellenar las tablas
13 FOR i in 1..5000 LOOP
14 LosNumeros(i):=i; LosNombres(i):=TO_CHAR(i);
15 END LOOP;
16 TOP(t1);
17 FOR i IN 1..5000 LOOP
18 INSERT INTO componentes VALUES(LosNumeros(i), LosNombres(i));
19 END LOOP;
20 TOP(t2);
21 FORALL i IN 1..5000
22 INSERT INTO componentes VALUES(LosNumeros(i), LosNombres(i));
23 TOP(t3);
24 DBMS_OUTPUT.PUT_LINE(’Tiempo de ejecución en segundos’);
25 DBMS_OUTPUT.PUT_LINE(’FOR ’||TO_CHAR(t2-t1));
26 DBMS_OUTPUT.PUT_LINE(’FORALL ’||TO_CHAR(t3-t2));
27 END;
28 /
Tiempo de ejecución en segundos
FOR 11
FORALL 1
Procedimiento PL/SQL terminado correctamente.
SQL>
Para procesar todos los elementos de una colección hay que utilizar la palabra clave FORALL. Su
uso se explica con detalle más adelante.
El uso del paquete DBMS_OUTPUT se aborda más adelante en el libro. Para poder ejecutar este
script correctamente hay que configurar la variable de entorno SERVEROUTPUT a ON en
SQL*Plus usando el siguiente comando: SET SERVEROUTPUT ON.
1. FORALL
La palabra clave FORALL indica al motor de PL/SQL que debe trabajar por bloques con la
colección, antes de enviar el comando SQL al motor SQL. Aunque la palabra clave FORALL realiza
un bucle de principio a fin, no puede incluirse en ella un bucle FOR.
Sintaxis
La instrucción SQL tiene que ser un comando INSERT, UPDATE o DELETE, que se aplique a una
colección. La instrucción SQL puede de hecho trabajar con varias colecciones, como se ha
mostrado en el ejemplo anterior. Deben emplearse los mismos índices para los elementos de las
distintas colecciones.
Ejemplo
En el siguiente ejemplo es posible observar los diferentes casos de uso de la instrucción FORALL.
SQL> DECLARE
2 TYPE tabla_numeros IS TABLE OF NUMBER(4);
3 TYPE tabla_nombres IS TABLE OF CHAR(5);
4 LosNumeros tabla_numeros:=tabla_numeros(1,2,3,4);
5 LosNombres tabla_nombres:=tabla_nombres(’Bici’,’Rueda’,
’Freno’,’Sillín’);
6 BEGIN
7 FORALL i in LosNumeros.FIRST..LosNumeros.LAST
8 INSERT INTO componentes values (LosNumeros(i),
LosNombres(i));
9 FORALL i in LosNumeros.FIRST..LosNumeros.LAST
10 DELETE FROM componentes WHERE numero=2*LosNumeros(i);
11 FORALL i in LosNumeros.FIRST..LosNumeros.LAST
12 INSERT INTO componentes values (100+LosNumeros(i),
LosNombres(i));
13 END;
14 /
SQL>
Las copias de datos por bloques pueden realizarse directamente en las colecciones de registros.
Oracle9i ofrece esta funcionalidad, la cual proporciona una mayor flexibilidad en el uso de los
datos en un bloque PL/SQL.
El siguiente ejemplo muestra los diferentes usos posibles al trabajar con colecciones de registros
y, especialmente, la definición de la colección con datos procedentes de la base de datos
mediante las instrucciones FOR..IN y FORALL.
declare
type tablaReg is table of tabla1%rowtype;
type tablaNumerica is table of number;
type tablaCaracteres is table of char(30);
cursor ctabla2 is select col1, col2 from tabla2;
tabreg tablaReg;
tabnum tablaNumerica:=tablaNumerica(2,3,5);
tabCar tablaCaracteres:=tablaCaracteres(’Godel’,’Escher’,’Bach’);
begin
-- adición de datos a la tabla1
forall i in 1..3
insert into tabla1 values (tabnum(i), tabcar(i));
-- adición de datos a la tabla de registros
select col1,col2 bulk collect into tabreg from tabla1;
-- inserción de datos en la tabla2
forall i in tabreg.first..tabreg.last
insert into tabla2 values tabreg(i);
end;
/
select * from tabla1;
select * from tabla2;
drop table tabla1;
drop table tabla2;
a. Limitaciones
El comando FORALL solo puede utilizarse en los programas del lado del servidor.
Las instrucciones INSERT, UPDATE o DELETE deben hacer referencia a al menos una
colección para poder sacar partido de la instrucción FORALL.
Para todos los valores de índices especificados en el comando FORALL deben existir
elementos en la colección.
No es posible expresar el índice utilizando un campo calculado.
b. Las transacciones y el comando FORALL
Sin embargo, si la excepción generada por una instrucción SQL se trata en el bloque PL/SQL,
entonces las operaciones realizadas en el bucle FORALL se anulan hasta un punto de salvaguarda
(SAVEPOINT) de la transacción que se establece de forma implícita después de cada instrucción
SQL. Es decir, la única instrucción SQL que se anula de forma automática es la que ha originado
la excepción. En el código de tratamiento de la excepción se decidirá si se conservan las
modificaciones ya realizadas (COMMIT) o si se anula la instrucción FORALL completa
(ROLLBACK).
Para permitir a la instrucción FORALL continuar incluso en caso de error hay que añadir la
cláusula SAVE EXCEPTIONS en la instrucción FORALL.
Sintaxis
Si una sentencia SQL falla, no se lanza ninguna excepción y la información relativa al error se
almacena en la colección SQL%BULK_EXCEPTIONS. Cuando la instrucción FORALL termina, se
produce la excepción ORA-24381. Entonces es posible escribir un manejador para esta excepción
que va a poder examinar el contenido de la colección SQL%BULK_EXCEPTIONS para determinar
la naturaleza de los errores y definir cómo terminar la transacción (COMMIT o ROLLBACK).
Para poder recorrer una lista sin necesidad de tener en cuenta el índice del primer y del último
elemento es posible utilizar la cláusula INDICES OF. Esta cláusula resultará mucho más
interesante en la medida en que se encuentren únicamente elementos de la colección aunque
existan ubicaciones sin valor. La cláusula INDICES OF permite garantizar el recorrido completo
de la colección sin que se genere una excepción.
SQL> DECLARE
2 TYPE tabla_numero IS TABLE OF NUMBER(4);
3 TYPE tabla_nombre IS TABLE OF CHAR(5);
4 losNumeros
5 tabla_numero:=tabla_numero(1,2,3,4);
6 losnombres tabla_nombre :=
7 tabla_nombre(’Bici’, ’Rueda’, ’Freno’, ’Sillín’);
8 BEGIN
9 FORALL i IN INDICES OF losNumeros
10 INSERT INTO componentes values(losNumeros(i),
11 losNombres(i));
12 END;
13 /
PL/SQL procedure successfully completed.
SQL>
2. El atributo %BULK_ROWCOUNT
Durante la ejecución de las instrucciones SQL, el motor abre implícitamente un cursor. Pueden
consultarse los atributos %FOUND, %ISOPEN, %NOTFOUND y %ROWCOUNT para asegurarse
del correcto funcionamiento de la instrucción SQL.
El cursor implícito (SQL) posee un atributo más: %BULK_ROWCOUNT, que se usa con la
instrucción FORALL. Este atributo es en realidad una colección de tipo INDEX BY TABLE, para el
que el elemento número i contiene el número de filas afectadas por la ejecución de la instrucción
SQL número i. Si ninguna fila se ha visto afectada por la instrucción número i, entonces el
atributo SQL%BULK_ROWCOUNT(i) devuelve el valor 0.
SQL>
3. BULK COLLECT
La palabra clave BULK COLLECT indica al motor SQL que los datos deben devolverse en una
colección al volver al motor PL/SQL. Este comando puede utilizarse con las cláusulas SELECT
INTO, FETCH INTO y RETURNING INTO.
Sintaxis
Ejemplo
Uso de BULK COLLECT: en el siguiente ejemplo, los datos extraídos de la tabla clientes se
guardan en la colección LosClientes.
SQL>
La cláusula opcional LIMIT, que solo se puede utilizar en operaciones de copia por bloques desde
un cursor, permite limitar el número de filas de datos extraídas en cada instrucción FETCH.
Sintaxis
Ejemplo
SQL> DECLARE
2 TYPE tabla_numeros IS TABLE OF clientes.numcli%type;
3 LosClientes tabla_numeros;
4 CURSOR ccli IS SELECT numcli FROM clientes;
5 BEGIN
6 OPEN ccli;
7 LOOP
8 FETCH ccli BULK COLLECT INTO LosClientes LIMIT 10;
9 EXIT WHEN CCLI%NOTFOUND;
10 END LOOP;
11 END;
12 /
SQL>
El trabajo con una colección es relativamente fácil. Pero, rápidamente, será necesario trabajar
con dos o más colecciones para comparar sus contenidos. Antes de la versión 10g de Oracle,
para poder realizar este tipo de trabajo era necesario escribir funciones propias de comparación.
Este trabajo, además de ser reiterativo, presenta el inconveniente de que la solución óptima se
encuentra raramente de forma rápida, y especialmente el recorrido de listas y los tests de
comparación son fuentes de errores comunes incluso para programadores experimentados. Al
introducir instrucciones que permiten trabajar con las colecciones como conjuntos Oracle facilita
el trabajo con este tipo de estructura.
Las instrucciones introducidas son: MULTISET UNION, MULTISET UNION DISTINCT, MULTISET
INTERSECT,MULTISET EXCEPT y SET. Estas instrucciones representan los operadores
disponibles sobre los conjuntos para efectuar la unión, la intersección, la diferencia y extraer los
elementos distintos.
Para ilustrar el funcionamiento de cada una de estas instrucciones y comprender así su interés
vamos a trabajar sobre un pequeño ejemplo.
Ejemplos
Se creará un paquete pkg_test. Este paquete contendrá dos colecciones y un procedimiento que
permite mostrar el contenido de la colección que se pasa como parámetro.
La primera etapa consiste en definir el tipo que servirá de base para la colección.
Type created.
SQL>
Package created.
SQL>
A continuación, hay que definir el cuerpo del paquete para dar la definición del procedimiento
mostrar. Este procedimiento corresponde a un simple recorrido de colección solicitando la
visualización de cada uno de los valores.
SQL>
Por ejemplo, para conocer el conjunto de nuestros amigos es necesario realizar una unión entre
las dos colecciones. Para ello, se dispone de las instrucciones MULTISET UNION y MULTISET
UNION DISTINCT. La distinción entre ambas instrucciones consiste en que la primera, MULTISET
UNION, devolverá el conjunto de valores contenidos en las dos colecciones sin eliminar los
duplicados, mientras que la segunda, MULTISET UNION DISTINCT, permitirá eliminar los
duplicados en la colección resultante.
SQL> DECLARE
2 nuestrosAmigos Nombres:=Nombres();
3 BEGIN
4 nuestrosAmigos:=pkg_test.misAmigos MULTISET UNION pkg_test.susAmigos;
5 pkg_test.mostrar(nuestrosAmigos);
6 END;
7 /
1-->Damian
2-->Duran
3-->Martin
4-->Damian
5-->Dalmau
6-->Sansos
7-->Luis
8-->Mariano
SQL>
Por el contrario, con la instrucción MULTISET UNION DISTINCT, los duplicados se eliminan.
Esta funcionalidad se ilustra mediante el ejemplo siguiente en el que el nombre Damian solo
aparece una vez.
SQL> DECLARE
2 nuestrosAmigos:=Nombres();
3 BEGIN
4 nuestrosAmigos:=pkg_test.misAmigos
5 MULTISET UNION DISTINCT
6 pkg_test.susAmigos;
7 pkg_test.mostrar(nuestrosAmigos);
8 END;
9 /
1-->Damian
2-->Duran
3-->Martin
4-->Dalmau
5-->Sansos
6-->Luis
7-->Mariano
SQL>
Para conocer los elementos comunes a ambas colecciones hay que utilizar MULTISET INTERSECT
para definir la colección de intersección.
SQL> DECLARE
2 nuestrosAmigos Nombres:=Nombres();
3 BEGIN
4 nuestrosAmigos:=pkg_test.misAmigos
5 MULTISET INTERSECT
6 pkg_test.susAmigos;
7 pkg_test.mostrar(nuestrosAmigos);
8 END;
9 /
1-->Damian
SQL>
Para poder realizar la diferencia entre dos colecciones es preciso utilizar la instrucción MULTISET
EXCEPT.
SQL> DECLARE
2 losAmigos Nombres:Nombres();
3 BEGIN
4 losAmigos:=pkg_test.misAmigos;
5 MULTISET EXCEPT
6 pkg_test.susAmigos
7 pkg_test.mostrar(losAmigos);
8 END;
9 /
1-->Duran
2-->Martin
SQL>
El ejemplo anterior permite conocer de entre la colección misAmigos solo los que no se conocen
en la otra colección (susAmigos).
Es evidente que, en esta instrucción, el orden en el que las colecciones se introducen respecto a
la instrucción posee una influencia directa en el resultado.
Por último, cuando se trabaja con colecciones de gran tamaño, es posible eliminar los duplicados
produciendo una nueva colección mediante la instrucción SET.
SQL> DECLARE
2 nuestrosAmigos Nombres:=Nombres();
3 resultado Nombres:=Nombres();
4 BEGIN
5 nuestrosAmigos:=pkg_test.misAmigos
6 MULTISET UNION
7 pkg_test.susAmigos;
8 resultado:=SET(nuestrosAmigos);
9 pkg_test.mostrar(resultado);
10 END;
11 /
1-->Damian
2-->Duran
3-->Martin
4-->Dalmau
5-->Sansos
6-->Luis
7-->Mariano
SQL>
La colección resultante de la unión de las dos colecciones iniciales posee valores duplicados. La
colección resultante producida por la instrucción SET, por su parte, no posee ninguna
redundancia.
Con el fin de mejorar los tiempos de respuesta de estas funciones que devuelven conjuntos de
datos, la cláusula pipelined indica que los datos deben devolverse conforme se ejecuta la
función. Además, con este tipo de función, la gestión de los conjuntos de valores devueltos es
más sencilla.
Estas funciones pueden aceptar como parámetro de entrada un conjunto de filas en forma de
colección (por ejemplo una tabla de tipo VARRAY) o en forma de una referencia a un cursor, REF
CURSOR.
Ejemplo
El siguiente ejemplo muestra la implementación de una función que devuelve una colección de
cifras en modo pipelined, es decir, conforme se ejecuta la función:
Tipo creado.
Tipo creado.
Función creada.
SQL> -- uso de la extracción en modo pipelined
SQL> select sum(importe) as total
2 from table(LineaVal(CURSOR(select * from lineasped where
numped=1301)));
TOTAL
----------
750
SQL>
La utilidad Wrap
La utilidad Wrap es un programa que permite cifrar el código fuente PL/SQL. De este modo, es
posible distribuir código PL/SQL sin que los usuarios puedan tener acceso al código fuente.
Wrap permite enmascarar el algoritmo utilizado, pero en ningún caso se cifran las cadenas de
caracteres, números, nombres de variables, columnas y tablas. Por tanto, esta utilidad no
permite ocultar las contraseñas o los nombres de las tablas.
iname
oname (opcional)
Permite especificar el nombre del archivo que va a contener la versión codificada del archivo
especificado en iname. Por omisión, este archivo de salida utiliza la extensión plb.
Sintaxis
DBMS_OUTPUT
El paquete DBMS_OUTPUT permite enviar mensajes desde un procedimiento, una función, un
paquete o un trigger de la base de datos.
Los procedimientos PUT y PUT_LINE de este paquete permiten ubicar datos en un búfer que
puede leerse desde otro bloque PL/SQL, que empleará el procedimiento GET_LINE para
recuperar la información.
SQL*Plus dispone del parámetro SERVEROUTPUT que se activa con la instrucción SET
SERVEROUTPUT ON y que permite conocer los datos que se han escrito en el búfer.
1. ENABLE
Este procedimiento permite activar las llamadas a los procedimientos PUT, PUT_LINE,
NEW_LINE, GET_LINE y GET_LINES. Si el paquete DBMS_ OUTPUT no está activado, la llamada
a este procedimiento se ignorará.
Sintaxis
Cuando se especifica, el tamaño máximo del búfer es de 1.000.000 bytes y el mínimo de 2.000
bytes. El valor NULL permite tener un búfer con tamaño ilimitado.
Si se realizan varias llamadas a este procedimiento, el tamaño máximo del búfer se mantiene.
2. DISABLE
Este procedimiento permite desactivar las llamadas a los procedimientos PUT, PUT_LINE,
NEW_LINE, GET_LINE y GET_LINES y elimina todos los datos contenidos en el búfer.
Sintaxis
DBMS_OUTPUT.DISABLE
Este procedimiento no utiliza parámetros.
3. PUT y PUT_LINE
Es posible incluir una fila de datos en el búfer mediante el comando PUT_LINE, o bien se pueden
crear las filas de datos elemento por elemento, colocando los datos unos a continuación de otros
en el búfer mediante el comando PUT. Ambos procedimientos permiten incluir en el búfer datos
de tipo carácter (VARCHAR2), de tipo numérico (NUMBER) o de tipo fecha (DATE).
En todos los casos, los datos se convierten al formato de cadena de caracteres. Los datos de tipo
numérico o de fecha se formatean utilizando la función de conversión TO_CHAR y los formatos
de conversión predeterminados. Si se desean emplear otros formatos de conversión es necesario
convertir dichos datos en cadenas de caracteres antes de incluirlos en el búfer.
Si el volumen de datos que hay que incluir en el búfer es mayor que el tamaño del mismo,
entonces se genera un error.
Sintaxis
DBMS_OUTPUT.PUT(elemento IN VARCHAR2);
DBMS_OUTPUT.PUT_LINE(elemento IN VARCHAR2);
4. NEW_LINE
Sintaxis
DBMS_OUTPUT.NEW_LINE;
5. GET_LINE y GET_LINES
Con el procedimiento GET_LINE se puede leer una línea de datos del búfer y con el procedimiento
GET_LINES se puede extraer una tabla de filas.
Después de leer el búfer mediante los procedimientos GET_LINE o GET_LINES, todas las líneas
que no se han leído y que se encuentran en el búfer al hacer otra llamada a los procedimientos
PUT, PUT_LINE o NEW_LINE se eliminan, con el fin de evitar cualquier posible confusión acerca
de los datos.
Sintaxis
DBMS_OUTPUT.GET_LINE(línea OUT VARCHAR2, estado IN OUT
INTEGER)
DBMS_OUTPUT.GET_LINES(líneas OUT CHARARR, num_líneas IN OUT
INTEGER)
línea
Almacena una única línea de datos procedente del búfer. El marcador de fin de línea no se
incluye en la fila devuelta. La longitud máxima de esta línea es de 32767 caracteres.
estado
líneas
num_líneas
Ejemplo
Procedimiento creado.
SQL>
A continuación, esta función se ejecuta desde SQL*Plus:
SQL> begin
2 cambiar_nombre;
3 end;
4 /
Operación realizada
SQL>
El paquete UTL_FILE
El paquete PL/SQL UTL_FILE permite a los programas PL/SQL llevar a cabo operaciones de
lectura y escritura en archivos de texto del sistema de archivos. El flujo de entrada/salida hacia
el sistema operativo se limita a trabajar únicamente con estos archivos.
En el servidor, la ejecución del programa PL/SQL que hace uso del paquete UTL_FILE debe
realizarse en un modo de seguridad privilegiado, y existen otras opciones de seguridad que
limitan las acciones llevadas a cabo a través del paquete UTL_FILE.
Históricamente, en el lado del servidor, los directorios a los que el paquete UTL_FILE podían
acceder deben especificarse en el archivo de parámetros (INIT.ORA) usando el
parámetro UTL_FILE_DIR.
Sintaxis
UTL_FILE_DIR=c:\temp.
Para hacer que UTL_FILE pueda acceder a todos los directorios del servidor hay que especificar
el siguiente parámetro en el archivo INIT.ORA: UTL_FILE_DIR=*
A partir de la versión 9i, es mejor utilizar el comando CREATE DIRECTORY para gestionar los
directorios accesibles desde el paquete UTL_FILE, en lugar del parámetro de inicialización
UTL_FILE_DIR.
Sintaxis
1. FOPEN, FOPEN_NCHAR
Esta función permite abrir un archivo para llevar a cabo operaciones de lectura o de escritura.
La ruta de acceso al archivo debe corresponderse con un directorio válido, definido con CREATE
DIRECTORY.
La ruta de acceso completa debe existir previamente y el comando FOPEN no puede crear
directorios.
La función FOPEN devuelve un puntero al archivo. Este puntero debe especificarse para el
conjunto de operaciones de lectura/escritura que se realizarán a continuación.
Sintaxis
UTL_FILE.FOPEN(
ruta IN VARCHAR2,
nombre_archivo IN VARCHAR2,
modo_apertura IN VARCHAR2
tamaño_máximo_fila IN BINARY_INTEGER DEFAULT 1024)
RETURN UTL_FILE.FILE_TYPE;
ruta
Nombre del objeto DIRECTORY que corresponde al directorio del sistema operativo que
contiene el archivo que va a abrirse.
nombre_archivo
Nombre del archivo con su extensión, sin incluir ninguna información relativa a la ruta de
acceso.
modo_apertura
Cadena de caracteres que especifica el modo de apertura del archivo. Los valores posibles son
los siguientes:
La letra b se puede añadir al modo de apertura (rb, wb, ab) para trabajar en modo binario con
el archivo.
Cuando se abre un archivo que no existe en modo de adición de datos (a), éste se crea y se abre
en modo de escritura (w).
tamaño_máximo_fila
Longitud máxima de una fila (incluido el carácter de fin de fila). Debe estar comprendida entre
1 y 32767 ; 1024 por defecto.
La función FOPEN_NCHAR, que recibe los mismos parámetros que la función FOPEN, permite
abrir un archivo en modo UNICODE para realizar operaciones de lectura y de escritura. Con este
método, se puede leer y escribir un archivo en formato UNICODE en lugar de utilizar el juego de
caracteres de la base de datos.
2. IS_OPEN
La función IS_OPEN tiene como objetivo comprobar si un puntero de archivo apunta a un archivo
que está abierto y que aún no se ha cerrado. La función IS_OPEN permite comprobar la validez
en el nivel del paquete UTL_FILE y no permite en ningún caso estar seguro de que la operación
se llevará a cabo correctamente en el sistema operativo.
Si el puntero de archivo que se pasa como parámetro apunta a un archivo abierto, entonces la
función IS_OPEN devuelve el valor TRUE; en caso contrario, devuelve el valor FALSE.
Sintaxis
UTL_FILE.IS_OPEN(
ptr_archivo IN FILE_TYPE)
RETURN BOOLEAN;
3. FCLOSE
Este procedimiento permite cerrar de manera correcta el flujo de datos a un archivo y asegurarse
de que los datos que se encuentran en el búfer de escritura están correctamente almacenados
en el archivo antes de cerrar el flujo hacia el mismo. Si todavía se encuentran datos en el búfer
al cerrar el archivo, la función FCLOSE puede generar el error WRITE_ERROR.
Sintaxis
4. FCLOSE_ALL
Este procedimiento permite cerrar todos los flujos de datos hacia archivos que se hayan abierto
durante la sesión actual. Este procedimiento solo debe ejecutarse en determinadas ocasiones,
por ejemplo cuando se sale de un bloque PL/SQL después de que se haya producido.
Además, la función FCLOSE_ALL no afecta al estado de otros punteros de archivo que esté
empleando el mismo usuario. Es decir, la función IS_OPEN seguirá devolviendo el valor TRUE al
comprobar un cierto flujo de datos, aunque cualquier intento de usar este flujo, bien en una
operación de lectura, bien en una operación de escritura, fallará.
Sintaxis
ULT_FILE.FCLOSE_ALL;
Los procedimientos GET_LINE y GET_LINE_NCHAR permiten leer una línea completa de texto
del archivo identificado por el puntero que se ha pasado como parámetro, y devuelve esta línea
de datos en una variable de búfer que también se ha pasado como parámetro. En esta variable
se almacena, por tanto, todo el texto, sin el marcador de fin de línea o de fin de archivo (en el
caso de que se solicite leer la última línea).
Este procedimiento solo se permite si el archivo se ha abierto en modo de lectura (r). En los
demás casos, se genera la excepción INVALID_OPERATION.
Si la línea es demasiado larga como para caber íntegramente en la variable búfer, entonces se
genera una excepción VALUE_ERROR. Por su parte, si se intenta leer el texto que se encuentra
después del carácter de fin de archivo, se genera una excepción de tipo NO_DATA_FOUND.
Dado que el carácter de fin de línea no se almacena en la variable de búfer, durante la lectura,
una línea en blanco se traduce en una cadena vacía.
Sintaxis
UTL_FILE.GET_LINE(
ptr_archivo IN FILE_TYPE,
búfer OUT NVARCHAR2,
bytes_a_leer IN PLS_INTEGER DEFAULT NULL);
Sintaxis
UTL_FILE.GET_NCHAR(
ptr_archivo IN FILE_TYPE,
búfer OUT NVARCHAR2,
bytes_a_leer IN PLS_INTEGER DEFAULT NULL);
UTL_FILE.GET_LINE_RAW(
ptr_archivo IN FILE_TYPE,
búfer OUT NOCOPY RAW,
bytes_a_leer IN PLS_INTEGER DEFAULT NULL);
El procedimiento PUT permite escribir en el archivo el texto contenido en una variable de búfer.
Por supuesto, el archivo debe estar abierto en modo de escritura (w o a). El carácter de fin de
línea no se añade de forma automática. Es necesario llamar al procedimiento NEW_LINE para
añadir dicho carácter o bien al procedimiento PUT_LINE para completar la línea actual.
Sintaxis
UTL_FILE.PUT (
ptr_archivo IN FILE_TYPE,
búfer IN VARCHAR2);
Sintaxis
UTL_FILE.PUT_RAW(
ptr_archivo IN FILE_TYPE,
búfer IN RAW,
vaciadoauto IN BOOLEAN DEFAULT FALSE);
7. NEW_LINE
Este procedimiento permite añadir al archivo uno o más caracteres de fin de línea. Este
procedimiento se emplea para terminar una línea escrita mediante el procedimiento PUT. El
número de caracteres de fin de línea que se añaden de manera predeterminada es uno.
Sintaxis
UTL_FILE.NEW_LINE(
ptr_archivo IN FILE_TYPE,
número IN NATURAL :=1);
8. PUT_LINE, PUT_LINE_NCHAR
A diferencia del procedimiento PUT, PUT_LINE permite añadir una línea de datos y su marcador
de fin de línea al archivo. Este procedimiento se puede utilizar para escribir una línea completa
o para terminar una línea cuya escritura se ha comenzado con el procedimiento PUT.
Sintaxis
UTL_FILE.PUT_LINE(
ptr_archivo IN FILE_TYPE,
búfer IN VARCHAR2),
vaciado_auto IN BOOLEAN DEFAULT FALSE);
vaciado_auto
La función PUT_LINE_NCHAR hace lo mismo pero con una cadena de caracteres UNICODE.
9. PUTF, PUTF_NCHAR
El procedimiento PUTF se corresponde con el procedimiento PUT, pero permite dar formato a los
datos. Su funcionamiento es similar a la función printf del lenguaje C. Permite escribir cualquier
texto en un archivo. Los caracteres siguientes tienen un significado especial:
%s
\n
Sintaxis
UTL_FILE.PUTF(
ptr_archivo IN FILE_TYPE,
búfer_con_formato IN VARCHAR2[,
param1 IN VARCHAR2 DEFAULT NULL,
...
param5 IN VARCHAR2 DEFAULT NULL]);
Los parámetros son opcionales y como máximo pueden ser cinco. El primer parámetro sustituye
a la primera aparición del carácter %s que se encuentre en el búfer, el segundo sustituye a la
segunda aparición, y así sucesivamente.
Ejemplo
create directory directorio_archivo as ’c:\temp’;
DECLARE
-- TYPE ptr_archivo IS RECORD (id BINARY_INTEGER);
f_out UTL_FILE.FILE_TYPE;
BEGIN
-- abrir el archivo
f_out:=UTL_FILE.FOPEN(’directorio_archivo,’prueba.txt’,’w’);
-- escribir una línea
UTL_FILE.PUT(f_out,’Esto es un ejemplo’);
-- incluir un marcador de fin de línea
UTL_FILE.NEW_LINE(f_out);
El nombre del objeto DIRECTORY debe estar escrito en mayúsculas en la llamada a FOPEN.
10. FFLUSH
Este procedimiento permite escribir físicamente los datos en los archivos, especialmente aquellos
que se encuentran en el búfer de escritura. En la práctica, normalmente todas las escrituras en
archivo se hacen a través de un búfer con el fin de optimizar los accesos al disco. El
procedimiento FFLUSH permite vaciar este búfer. Naturalmente, los datos deben terminar con
un carácter de fin de línea.
El procedimiento FSEEK permite desplazarse por el archivo hacia adelante o hacia atrás el
número de bytes que se desee. El desplazamiento puede ser absoluto, tomando el parámetro
offset_absoluto el valor de la posición a la que se desea desplazarse; el valor predeterminado es
null.
Sintaxis
UTL_FILE.FSEEK(
ptr_archivo IN FILE_TYPE,
offset_absoluto IN PLS_INTEGER DEFAULT NULL,
offset_relativo IN PLS_INTEGER DEFAULT NULL);
Sintaxis
UTL_FILE.FGETPOS(ptr_archivo IN FILE_TYPE)
RETURN PLS_INTEGER;
Estos procedimientos permiten realizar una serie de operaciones sobre los archivos del sistema
operativo cuando se ha concedido el acceso al directorio.
Estos procedimientos aportan una cierta flexibilidad en la gestión de archivos externos a la base
de datos y completan el concepto de directorio (DIRECTORY) que se ha introducido a partir de
la versión 9i.
La ubicación es el nombre de un objeto de tipo DIRECTORY que se haya creado con la ayuda del
método CREATE DIRECTORY.
Sintaxis
UTL_FILE.FREMOVE(
ubicación IN VARCHAR2,
nom_archivo IN VARCHAR2);
UTL_FILE.FCOPY(
directorio_origen IN VARCHAR2,
nom_archivo_origen IN VARCHAR2,
directorio_destino IN VARCHAR2,
nom_archivo_destino IN VARCHAR2,
número_línea_inicio IN PLS_INTEGER DEFAULT 1,
número_línea_fin IN PLS_INTEGER DEFAULT NULL);
UTL_FILE_FRENAME(
directorio_origen IN VARCHAR2,
nom_archivo_origen IN VARCHAR2,
directorio_destino IN VARCHAR2,
nom_archivo_destino IN VARCHAR2,
sustituir IN BOOLEAN DEFAULT FALSE);
13. FGETATTR
Sintaxis
UTL_FILE.FGETATTR(
ubicación IN VARCHAR2,
nombre_archivo IN VARCHAR2,
existe OUT BOOLEAN,
tamaño_archivo OUT NUMBER,
tamaño_bloque OUT NUMBER);
14. Excepciones
Las principales excepciones que pueden generarse durante la ejecución de este paquete son:
INVALID_PATH
INVALID_MODE
INVALID_FILEHANDLE
INVALID_OPERATION
READ_ERROR
Se ha producido un error del sistema operativo durante una operación de lectura del archivo.
WRITE_ERROR
Se ha producido un error del sistema operativo durante una operación de escritura en el
archivo.
INTERNAL_ERROR
CHARSETMISMATCH
FILE_OPEN
INVALID_MAXLINESIZE
INVALID_FILENAME
ACCESS_DENIED
INVALID_OFFSET
Posición incorrecta. La posición pasada como parámetro del método FSEEK debe ser mayor que
0 e inferior al número total de bytes del archivo.
DELETE_FAILED
RENAME_FAILED
Los procedimientos del paquete también generan excepciones de Oracle predefinidas, como
NO_DATA_FOUND o VALUE_ERROR.
El paquete DBMS_LOB
La abreviatura LOB (Large OBjet) identifica a los objetos de gran tamaño.
Trabajar con elementos de gran tamaño (BLOB: Binary LOB, CLOB: Character LOB,
NCLOB: uNicode CLOB y BFILE: archivo binario) no es tan sencillo como trabajar con datos de
tipo más clásico (carácter, numérico, fecha). El lenguaje PL/SQL permite trabajar con estos datos
desde el momento en que se encuentran en la base de datos, pero las operaciones de carga
desde un archivo del sistema operativo, de comparación o de modificación solo podrán realizarse
mediante el paquete DBMS_LOB.
1. Constantes
Las siguientes constantes se definen en el paquete DBMS_LOB. Su uso permite aclarar el uso de
las distintas funciones y procedimientos del paquete.
2. APPEND
Este procedimiento permite añadir la totalidad de la variable LOB de origen a la variable LOB de
destino.
Sintaxis
DBMS_LOB.APPEND(
destino IN OUT NOCOPY BLOB,
origen IN BLOB);
DBMS_LOB.APPEND(
destino IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
origen IN CLOB CHARACTER SET destino%CHARSET);
3. CLOSE
Este procedimiento permite cerrar un elemento LOB interno o externo que se haya abierto
anteriormente.
Sintaxis
DBMS_LOB.CLOSE(
{lob_origen IN OUT NOCOPY BLOB
| lob_origen IN OUT NOCOPY CLOB CHARACTER SET ANY CS
| archivo_origen IN OUT NOCOPY BFILE);
4. COMPARE
Esta función permite comparar dos objetos LOB en su totalidad o parcialmente. Únicamente es
posible comparar objetos LOB del mismo tipo (BLOB, CLOB o BFILE). Con archivos (BFILE), antes
de llevar a cabo la operación de comparación, los elementos deben abrirse con FILEOPEN.
La función COMPARE devuelve 0 si los dos elementos que hay que comparar son completamente
idénticos o un valor diferente de cero en caso contrario.
Sintaxis
DBMS_LOB.COMPARE(
lob1 IN {BLOB|CLOB CHARACTER SET ANY_CS|BFILE},
lob2 IN {BLOB|CLOB CHARACTER SET ANY_CS|BFILE},
número_bytes_que_comparar NUMBER :=DBMS_LOB.LOBMAXSIZE,
byte_origen1 IN INTEGER:=1,
byte_origen2 IN INTEGER:=1);
5. COPY
Este procedimiento permite realizar la copia total o parcial desde un objeto LOB de origen a un
objeto LOB de destino. En el caso de una copia parcial, es posible especificar la longitud (número
de bytes) que se va a copiar, así como las posiciones en el objeto LOB de origen y de destino.
Sintaxis
DBMS_LOB.COPY(
lob_destino IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
lob_origen IN{BLOB|CLOB CHARACTER SET lob_destino%CHARSET},
bytes_que_copiar IN INTEGER,
direcc_destino IN INTEGER:=1,
direcc_origen IN INTEGER:=1);
Sintaxis
DBMS_LOB.CREATETEMPORARY(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
caché IN BOOLEAN,
validez IN VARIOS_INTEGER:=DBMS_LOB.SESSION);
El procedimiento FREETEMPORARY permite liberar un objeto temporal de tipo CLOB o BLOB que
haya sido creado con CREATETEMPORARY. Por supuesto, no es recomendable esperar a que
termine la sesión o la llamada para eliminar el objeto temporal, sino que es mejor liberar el
espacio que ocupa en el espacio de tablas temporal lo antes posible mediante el procedimiento
FREETEMPORARY.
Sintaxis
DBMS_LOB.FREETEMPORARY(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS});
Por último, la función ISTEMPORARY, que devuelve un valor booleano, permite saber si el
elemento LOB que se pasa como parámetro es temporal o no.
Sintaxis
DBMS_LOB.ISTEMPORARY(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS})
return INTEGER;
Ejemplo
El siguiente ejemplo muestra la implementación de estos tres métodos relativos a los objetos
LOB temporales:
SQL> declare
2 b blob;
3 c clob;
4 begin
5 -- creación de los elementos temporales
6 dbms_lob.createtemporary(b, true);
7 dbms_lob.createtemporary(c,true);
8 -- prueba y eliminación
9 if (dbms_lob.istemporary(b)=1) then
10 dbms_lob.freetemporary(b);
11 end if;
12
13 if (dbms_lob.istemporary(c)=1) then
14 dbms_lob.freetemporary(c);
15 end if;
16 end;
17 /
7. ERASE
Sintaxis
DBMS_LOB.ERASE(
lob IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
bytes_que_borrar IN OUT NOCOPY INTEGER,
direcc_inicio IN INTEGER:=1);
El tamaño de un LOB no se reduce al realizar un borrado parcial. Para reducir su tamaño debe
utilizarse el procedimiento TRIM.
El procedimiento FILEOPEN permite abrir un archivo con el fin de llevar a cabo operaciones de
lectura. No es posible escribir en un archivo abierto con este procedimiento.
Sintaxis
DBMS_LOB.FILEOPEN(
ptr_archivo IN OUT NOCOPY BFILE,
modo_apertura IN BINARY_INTEGER:=file_readonly);
Sintaxis
Por último, la función ISOPEN, que devuelve un número entero, permite saber si un objeto LOB
está abierto o no.
Sintaxis
DBMS_LOB.ISOPEN(
elemento_lob IN {BLOB|CLOB CHARACTER SET ANY_CS|BFILE})
RETURN INTEGER;
9. FILEEXISTS, FILEISOPEN
La función FILEEXISTS devuelve un valor entero que indica si el archivo existe o no. Es
aconsejable llamar a esta función antes de comenzar a trabajar con el archivo ya que, de este
modo, se puede evitar generar algunas excepciones. Esta función simplemente verifica la
existencia física del archivo.
Sintaxis
Sintaxis
10. FILEGETNAME
Sintaxis
DBMS_LOB.FILEGETNAME(
archivo IN BFILE,
directorio OUT VARCHAR2,
nombrearchivo OUT VARCHAR2);
Sintaxis
DBMS_LOB.FRAGMENT_DELETE(
lob_loc IN OUT NOCOPY {BLOB | CLOB CHARACTER SET ANY_CS},
número_bytes IN INTEGER,
dir_inicio IN INTEGER);
DBMS_LOB.FRAGMENT_INSERT(
lob_loc IN OUT NOCOPY {BLOB | CLOB CHARACTER SET ANY_CS},
número_bytes IN INTEGER,
dir_inicio IN INTEGER,
buffer {RAW | VARCHAR2 CHARACTER SET lob_loc%CHARSET);
DBMS_LOB.FRAGMENT_MOVE(
lob_loc IN OUT NOCOPY {BLOB | CLOB CHARACTER SET ANY_CS},
número_bytes IN INTEGER,
dir_inicio IN INTEGER,
dir_destino IN INTEGER);
DBMS_LOB.FRAGMENT_REPLACE(
lob_loc IN OUT NOCOPY {BLOB | CLOB CHARACTER SET ANY_CS},
número_bytes_antiguo IN INTEGER,
número_bytes_nuevo IN INTEGER,
dir_inicio IN INTEGER,
buffer {RAW | VARCHAR2 CHARACTER SET lob_loc%CHARSET);
La función GETLENGTH permite conocer el tamaño del elemento LOB, BLOB o BFILE que se pasa
como parámetro. El tamaño es un número entero que se corresponde con el número de bytes
del elemento que se pasa como parámetro.
Sintaxis
DBMS_LOB.GETLENGTH(
{lob_loc IN BLOB
| lob_loc IN CLOB CHARACTER SET ANY_CS
| file_loc IN BFILE}) RETURN INTEGER;
La función GETCHUNKSIZE permite conocer el tamaño real utilizado para almacenar los datos
del objeto LOB en los segmentos (CHUNK) de espacio físico asignados al objeto LOB. Este tamaño
se expresa en bytes.
Sintaxis
DBMS_LOB.GETCHUNKSIZE(
{lob_loc IN BLOB
| lob_loc IN CLOB CHARACTER SET ANY_CS
| file_loc IN BFILE}) RETURN INTEGER;
13. INSTR
Esta función devuelve el valor entero correspondiente a la enésima aparición del elemento
objetivo de la búsqueda. El número de aparición se indica mediante el parámetro enésima y el
objeto de la búsqueda se especifica en el parámetro objeto_búsqueda. La búsqueda se inicia
en el elemento LOB a partir de la dirección absoluta de inicio especificada en el
parámetro direcc_inicio y que define el número de bytes o caracteres de acuerdo con la
naturaleza del elemento LOB.
Sintaxis
DBMS_LOB.INSTR(
elemento_lob IN BLOB,
objeto_búsqueda IN RAW,
direcc_inicio IN INTEGER:=1,
enésima IN INTEGER:=1);
DBMS_LOB.INSTR(
elemento_lob IN CLOB CHARACTER SET ANY_CS,
objeto_búsqueda IN VARCHAR2 CHARACTER SET elemento_lob%CHARSET,
direcc_inicio IN INTEGER:=1,
enésima IN INTEGER:=1);
DBMS_LOB.INSTR(
elemento_lob IN BFILE,
objeto_búsqueda IN RAW,
direcc_inicio IN INTEGER:=1,
enésima IN INTEGER:=1);
Estos procedimientos permiten cargar elementos LOB contenidos en archivos en elementos LOB
de la base de datos. Se pueden especificar las direcciones absolutas donde iniciar el proceso de
copia, en el caso de una carga parcial, mediante los
parámetros dir_inicio_origen y dir_inicio_destino. Estas direcciones se
expresan en bytes.
En cualquier caso, es necesario especificar el número de bytes que se van a leer del archivo para
crear el elemento LOB en memoria.
Sintaxis
DBMS_LOADFROMFILE(
lob_destino IN OUT NOCOPY BLOB,
archivo_origen IN BFILE,
número_bytes IN INTEGER,
dir_inicio_destino IN INTEGER:=1,
dir_inicio_origen IN INTEGER:=1);
DBMS_LOADBLOBFROMFILE(
lob_destino IN OUT NOCOPY BLOB,
archivo_origen IN BFILE,
número_bytes IN INTEGER,
dir_inicio_destino IN OUT INTEGER:=1,
dir_inicio_origen IN OUT INTEGER:=1);
DBMS_LOADCLOBFROMFILE(
lob_destino IN OUT NOCOPY BLOB,
archivo_origen IN BFILE,
número_bytes IN INTEGER,
dir_inicio_destino IN OUT INTEGER:=1,
dir_inicio_origen IN OUT INTEGER:=1,
juego_caracteres_org IN NUMBER,
contexto_idioma IN OUT INTEGER,
aviso OUT INTEGER);
Ejemplo
El siguiente ejemplo ilustra cómo utilizar los diferentes métodos del paquete para cargar
imágenes en una tabla:
Tabla creada.
Secuencia creada.
SQL>
SQL> -- definición del directorio
SQL> create or replace directory directorio_imagen as ’C:\imagen’;
Directorio creado.
SQL>
SQL> -- carga de los datos
SQL> declare
2 archivo_in BFILE;
3 tamaño number;
4 dest_blob BLOB;
5 vid number;
6 begin
7 archivo_in:= bfilename(’DIRECTORIO_IMAGEN’,’BPR.gif’);
8
9 -- abrir el archivo
10 dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);
11
12 if (dbms_lob.fileexists(archivo_in)=1) then
13
14 -- tamaño del archivo
15 tamaño:=dbms_lob.getlength(archivo_in);
16 insert into misfotos values (seq_id_fotos.nextval, empty_blob())
17 return id,img into vid,dest_blob;
18
19 -- leer los datos y almacenarlos en una variable
20 dbms_lob.loadfromfile(dest_blob,archivo_in, tamaño);
21
22 -- insertar en la tabla
23 update misfotos set img=dest_blob where id=vid;
24 commit;
25
26 -- cerrar el archivo
27 dbms_lob.fileclose(archivo_in);
28
29 end if;
30
31 exception
32
33 when dbms_lob.invalid_argval then
34 raise_application_error(-20001,’Argumento erróneo’);
35
36 when dbms_lob.access_error then
37 raise_application_error(-20002,’Capacidad sobrepasada’);
38
39 when dbms_lob.noexist_directory then
40 raise_application_error(-20003,’El directorio no existe’);
41
42 when dbms_lob.nopriv_directory then
43 raise_application_error(-20004,’Privilegios insuficientes sobre
el directorio’);
44
45 when dbms_lob.unopened_file then
46 raise_application_error(-20007,Archivo no abierto’);
47
48 when others then
49 dbms_lob.fileclose(archivo_in);
50 raise_application_error(-20008,’ERR’||SQLCODE||’ ’||SQLERRM);
51
52 end;
53 /
15. OPEN
Sintaxis
DBMS_LOB.OPEN(
lob_origen IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
modo_apertura IN BINARY_INTEGER);
16. READ
Este procedimiento permite leer todo o parte de un elemento LOB y escribir el resultado de dicha
lectura en el búfer.
Sintaxis
DBMS_LOB.READ(
lob_origen IN {BLOB|BFILE},
número_bytes IN OUT NOCPY BINARY_INTEGER,
direcc_inicio INT INTEGER,
búfer OUT RAW);
DBMS_LOB.READ(
lob_origen IN CLOB CHARACTER SET ANY_CS,
número_bytes IN OUT NOCPY BINARY_INTEGER,
direcc_inicio INT INTEGER,
búfer OUT VARCHAR2 CHARACTER SET lob_origen%CHARSET);
17. SUBSTR
Esta función ofrece la posibilidad de extraer una subcadena del elemento LOB. Se trata del
conjunto de bytes leídos a partir de la dirección de inicio que se pasa como parámetro; también
hay que pasar como parámetro el número de bytes que hay que leer y que se devuelven.
Sintaxis
DBMS_LOB.SUBSTR(
lob_origen IN BLOB,
número_bytes IN INTEGER:=32767,
direcc_inicio IN INTEGER:=1) RETURN RAW;
DBMS_LOB.SUBSTR(
lob_origen IN CLOB CHARACTER SET ANY_CS,
número_bytes IN INTEGER:=32767,
direcc_inicio IN INTEGER:=1)
RETURN VARCHAR2 CHARACTER SET lob_origen%CHARSET;
18. TRIM
Sintaxis
DBMS_LOB.TRIM(
lob_origen IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
nuevo_tamaño IN INTEGER);
El procedimiento WRITE permite escribir una serie de bytes en un elemento LOB interno a partir
de la dirección de inicio especificada. El procedimiento WRITE reemplaza todos los datos que ya
existen en el elemento LOB objetivo a partir de la dirección de inicio.
Sintaxis
DBMS_LOB.WRITE(
lob_destino IN OUT NOCOPY BLOB,
número_bytes IN BINARY INTEGER,
direcc_inicio IN INTEGER,
búfer IN RAW);
DBMS_LOB.WRITE(
lob_destino IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
número_bytes IN BINARY_INTEGER,
direcc_inicio IN INTEGER,
búfer IN VARCHAR2 CHARACTER SET lob_origen%CHARSET);
El procedimiento WRITEAPPEND permite escribir los datos del LOB que actualmente se encuentra
en el búfer al final del objeto LOB de destino.
Sintaxis
DBMS_LOB.WRITEAPPEND(
lob_destino IN OUT NOCOPY BLOB,
número_bytes IN BINARY_INTEGER,
búfer IN RAW);
DBMS_LOB.WRITEAPPEND(
lob_destino IN OUT NOCOPY CLOB CHARACTER SET ANY_CS,
número_bytes IN BINARY_INTEGER,
búfer IN VARCHAR2 CHARACTER SET lob_origen%CHARSET);
20. Excepciones
INVALID_ARGVAL
Los argumentos de las funciones y procedimientos esperaban valores no nulos, pero algún
argumento ha tomado un valor nulo (NULL) o un valor que se encuentra fuera del dominio de
definición del argumento.
ACCESS_ERROR
NOEXIST_DIRECTORY
NOPRIV_DIRECTORY
El usuario no posee los permisos necesarios sobre el directorio (DIRECTORY) o sobre los
archivos para llevar a cabo las operaciones.
INVALID_DIRECTORY
OPERATION_FAILED
La operación ha fallado.
UNOPENED_FILE
OPEN_TOOMANY
La máquina virtual Java integrada en el motor de Oracle es totalmente compatible con el JDK
(Java Development Kit, kit de desarrollo Java) de Sun.
Esta máquina virtual se ejecuta en el mismo proceso y comparte el mismo espacio de memoria
que el motor de la base de datos. Esta solución ofrece un excelente tiempo de acceso a los datos.
La máquina virtual es un entorno de ejecución Java que soporta todas las estructuras, métodos
y mecanismos de tratamiento de errores propios de Java.
Elegir Java para desarrollar el código del lado del servidor permite obtener una solución escrita
completamente en Java y limitar así el número de lenguajes diferentes que es necesario
aprender.
Las ventajas de los procedimientos almacenados son numerosas. Las más importantes son:
Para cargar las clases Java en la base de datos usaremos la utilidad de la línea de
comandos loadjava.
1. Generalidades
Para cada clase cargada en la base de datos por loadjava, se crea un objeto y el nombre de
dicho objeto hace referencia al nombre completo de la clase Java. En este objeto se almacena
el código fuente, el código ejecutable y los diferentes recursos necesarios para la correcta
ejecución de la clase. Loadjava también almacena los diferentes valores de las opciones en una
tabla.
El programa Java puede crearse mediante una herramienta de desarrollo externa a la base de
datos y, a continuación, loadjava permite cargar el archivo .class. Pero también es posible cargar
el archivo fuente (.java) y luego compilar el código en la base de datos.
El nombre del objeto creado recibe el nombre completo de la clase Java, es decir, el nombre del
paquete seguido del nombre de la clase. Estos nombres pueden tener una longitud máxima de
4000 caracteres en la base de datos. Sin embargo, Oracle solo admite identificadores con una
longitud máxima de 30 caracteres para los objetos de la base de datos. Por tanto, es necesario
implementar un método de resolución de nombres con el fin de poder manipular estos objetos
desde PL/SQL.
2. Permisos de uso
Por omisión, los procedimientos almacenados Java utilizan los privilegios concedidos al usuario
de Oracle que ejecuta el procedimiento. Este tipo de resolución de permisos permite personalizar
los privilegios concedidos a cada usuario. Además, el código puede centralizarse en un
determinado punto de la base de datos y utilizarse de distintas maneras.
3. La utilidad loadjava
Sintaxis
-cleargrants
-debug
-d | -definer
{-e | -encoding juego
-f | -force
{-g | -grant} usuario [,...]
-help
-o | -oci | -oci8
-r | -resolve
{-R | -resolver } "especificación"
{-S | -schema } esquema
-s | -synonym
-t | -thin
-v | -verbose
-cleargrants
Revoca todos los permisos antes de asignarlos de nuevo con la opción -grant.
-resolve
Con esta opción, la clase se carga en la base de datos después de efectuar una resolución para
saber si todas las clases Java utilizadas existen en la base de datos. Si es así, entonces la clase
cargada se marca como válida.
-resolver
Esta opción permite especificar una ruta (conjunto de esquemas) que debe emplearse para
localizar los objetos referenciados en la clase que se acaba de cargar. Esta opción es similar a
la variable CLASSPATH que se utiliza en los programas clásicos Java.
-debug
-definer
Permite utilizar el método con los permisos del usuario que ha creado el método y no con los
concedidos al usuario que utiliza el método.
-encoding
Esta opción permite establecer la tabla de caracteres utilizada por el JDK para codificar los
archivos. Por omisión, la página de caracteres empleada es latin1.
-force
La clase se cargará en la base de datos incluso aunque ya exista en ella. Sin esta opción, la
acción de carga se rechazará cuando la clase ya exista. Esta opción es especialmente
interesante en las operaciones de actualización de clases.
-grant
-oci | -oci8
Permite a loadjava comunicarse con la base de datos utilizando el controlador OCI JDBC. Es el
modo de comunicación predeterminado.
-thin
En este caso, loadjava utiliza el controlador simple (thin) de JDBC para establecer la
comunicación con la base de datos.
-schema
Los objetos Java de nueva creación se asignan al esquema especificado mediante este
parámetro. Por omisión, se crean en el esquema del usuario actual.
-synonym
Crea un sinónimo público para hacer que las clases sean más fácilmente accesibles.
-verbose
Ejemplo
El código fuente:
import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;
4. La utilidad dropjava
Al revés que la utilidad loadjava, dropjava permite suprimir un objeto Java de la base de datos.
Esta herramienta también permite eliminar archivos de código fuente (.java), archivos .class o
recursos .jar o .zip.
Sintaxis
-debug
-o | -oci | -oci8
{-S | -schema} esquema
-s | -synonym
-t | -thin
-v | -verbose
Las opciones disponibles para esta herramienta tienen el mismo significado que en la utilidad
loadjava.
Ejemplo
La compilación del archivo SQLJ puede realizarse en el equipo cliente sobre el que se haya
desarrollado el código Java o en el servidor. Es preferible realizar la compilación en el equipo de
desarrollo, ya que permite una depuración más sencilla si se producen errores de compilación.
Los archivos .class o .jar pueden cargarse en el servidor mediante el comando loadjava.
a. JDBC
En este libro, muchos ejemplos de Java emplean la tecnología JDBC para trabajar con los datos
procedentes de la base de datos.
b. SQLJ
SQLJ constituye una solución para el acceso a los datos específica de Oracle que se adapta bien
a los desarrollos Java estrechamente integrados con la base de datos Oracle. En efecto, gracias
a SQLJ es posible hacer referencia a variables Java directamente en las instrucciones SQL y,
para el caso de aplicaciones que se ejecuten en el servidor de base de datos, la gestión de la
conexión está implícita, lo que simplifica aún más el código.
Para que el precompilador de SQLJ transforme las instrucciones SQLJ en llamadas a métodos,
las instrucciones SQLJ deben comenzar obligatoriamente por #SQL y la instrucción SQL debe
encerrarse entre llaves, {}.
Ejemplo
El siguiente fragmento de código Java muestra cómo se pueden integrar los comandos SQLJ en
el código Java:
import java.sql.*;
class Contadores{
public static int ContadorClientes(){
int numero=0;
try{
#sql{SELECT COUNT(*) INTO :numero FROM CLIENTES};
return numero;
} catch(SQLException e){
}finally{
return numero;
}
}
}
Por último, el archivo class tiene que cargarse en la base de datos mediante la utilidad loadjava.
Para un método Java, es necesario crear una función (un método de tipo void) o un
procedimiento PL/SQL mediante las instrucciones CREATE FUNCTION y CREATE PROCEDURE.
Estas funciones y procedimientos pueden agruparse en un paquete. El cuerpo de estas funciones
y procedimientos contendrá la cláusula LANGUAGE JAVA para registrar el nombre completo del
método, el valor de retorno y los parámetros.
La correspondencia entre los tipos de datos SQL y Java se rige por la siguiente tabla.
DATE oracle.sql.DATE
java.sql.Date
java.sql.Time
java.sql.Timestamp
java.lang.String
NUMBER oracle.sql.NUMBER
java.lang.Byte
java.lang.Short 2.
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.BigDecimal
byte - short - int - long - float - double
ROWID oracle.sql.CHAR
oracle.sql.ROWID
java.lang.String
BFILE oracle.sql.BFILE
BLOB oracle.sql.BLOB
oracle.jdbc2.Blob
OBJECT oracle.sql.STRUCT
oracle.jdbc2.Struct
REF oracle.sql.REF
oracle.jdbc2.Ref
Sintaxis
AUTHID
Permite definir el tipo de privilegios que pueden utilizarse durante la ejecución del método,
bien los del creador del método, bien los del usuario del método (opción predeterminada).
No se puede modificar una opción establecida con Loadjava.
PARALLEL_ENABLE
El método puede ejecutarse en un entorno paralelo, ya que no hace referencia a ningún valor
de tipo estático.
DETERMINISTIC
Ejemplos
Conectado a:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production
Procedimiento creado.
SQL>
El siguiente ejemplo define una función que devuelve el número de elementos que hay en la
tabla cuyo nombre se ha pasado como parámetro.
El código Java
import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;
A continuación se crea una función de tipo PL/SQL para poder emplear la función Java en la base
de datos.
Conectado a:
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production
Función creada.
SQL>
3. CREATE JAVA
La instrucción DDL CREATE JAVA permite crear un procedimiento, una función o un recurso Java
desde SQL sin pasar por la utilidad loadjava. El uso de este comando se reserva a código java
para el que el riesgo de errores de compilación es bajo, aunque la depuración es más difícil.
Como con todos los comandos DDL, es necesario disponer de un privilegio determinado (en este
caso, CREATE PROCEDURE) para poder ejecutar esta instrucción.
Sintaxis
Ejemplo
La instrucción CALL
Sintaxis
CALL [nombre_esquema.][nombre_paquete.]
{nombre_procedimiento (parámetro,...)|nombre_función(parámetro,...)}
Los parámetros se definen en SQL*Plus y pueden ser valores literales o variables host.
Ejemplo
Llamada terminada.
NUMERO
----------
13
SQL>
Tabla creada.
Llamada terminada.
SQL>
Ejemplo
Código fuente. El procedimiento Java se utiliza para mostrar directamente el nombre de los
distintos clientes:
import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;
La clase se carga en la base de datos usando Loadjava. Hay un procedimiento PL/SQL asociado
al método Java:
Publicación en la base de datos:
Procedimiento creado.
SQL>
Llamada terminada.
Llamada terminada.
SQL>
Un disparador de base de datos es un programa asociado a una tabla o a una vista. Oracle
ejecuta automáticamente este programa cuando se ejecuta sobre la tabla o vista la operación
DML (INSERT, UPDATE o DELETE) a la que está vinculado el disparador.
Después de la definición del disparador (nombre, tabla o vista asociada, instrucción DML del
disparador, antes o después de la verificación de las restricciones de integridad) se invoca al
procedimiento vinculado al método Java mediante la función CALL. El cuerpo del disparador
puede así reducirse al mínimo.
Ejemplo
La clase Disparador incluye un método que permite reducir el almacén con cada nuevo pedido
de artículos. La clase se carga en la base de datos mediante la utilidad loadjava. Creación del
procedimiento ActAlmacen:
Procedimiento creado.
SQL>
SQL>
Como existe una función o un procedimiento de tipo PL/SQL asociado al método Java, el uso de
esta función o procedimiento es similar al de una función o procedimiento escritos
completamente en PL/SQL.
Paquetes
La implementación de métodos Java no siempre resulta sencilla y además no tiene sentido crear
tantas clases Java como métodos. En Java, todos los métodos que se aplican a un mismo objeto,
por ejemplo, todos los métodos de gestión de pedidos se agrupan en una misma clase. Para
mantener esta coherencia de agrupación en el nivel de programación de la base de datos, las
funciones y los procedimientos asociados a los métodos se agrupan en un paquete.
Por supuesto, un paquete de este tipo no difiere de un paquete PL/SQL normal y se comporta
del mismo modo. El principal aspecto a tener en cuenta es que el paquete permanece en memoria
y permite de este modo ofrecer mejores tiempos de respuesta que si las funciones y
procedimientos fueran independientes.
Ejemplo
import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;
public class Pedidos{
public static float importe(int numped) throws SQLException{
Connection conn=new OracleDriver().defaultConnection();
String consulta="Select sum(cantped*precio) from linpedidos l, articulos
a where a.refart=l.refart and l.numped="+numped;
float mt=0;
try{
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(consulta);
while (rs.next()){mt=rs.getFloat(1); }
rs.close();
stmt.close();
} catch(SQLException e){System.err.println(e.getMessage());}
return mt;
}
public static void suministro(int numped) throws SQLException
{ cambiarEstado(numped,"SU"); }
public static void saldado(int numped) throws SQLException
{ cambiarEstado(numped,"SA"); }
private static void cambiarEstado(int numped, String estadoped) throws
SQLException {
Connection conn=new OracleDriver().defaultConnection();
String consulta="Update pedidos set estadoped=’"+estadoped+"’
where numped="+numped;
try{ Statement ordre=conn.createStatement();
comando.executeQuery(consulta);
comando.close();
} catch (SQLException e) {System.err.println(e.getMessage());}
}
}
Paquete creado.
SQL>
SQL>
Ejemplo
PKG_PEDIDOS.IMPORTE(1)
----------------------
1000
SQL>
Introducción
El analizador de XML permite manipular archivos XML desde el lenguaje PL/SQL. De este modo,
es posible generar archivos en dicho formato de composición. Para poder implementar esta
funcionalidad, el lenguaje PL/SQL utiliza el paquete xmldom con el fin de conocer y analizar la
estructura del documento XML.
El lenguaje PL/SQL, actualmente empleado por los desarrolladores de aplicaciones sobre Oracle,
cuenta así con la posibilidad de evolucionar hacia el lenguaje XML. El analizador de XML para
PL/SQL está escrito en PL/SQL y Java. Soporta todas las especificaciones publicadas por el
consorcio W3C para el estándar 1.0 de XML. Además de cumplir perfectamente el estándar, el
analizador de XML para PL/SQL permite realizar un análisis simplificado del documento,
respetando las directrices del W3C en lo relativo al modelo del documento (DOM, Document
Object Model). También cumple las recomendaciones relativas a XSLT (hojas de estilo) y Xpath.
El siguiente esquema resume de forma sencilla cómo funciona esta herramienta a la hora de
analizar un documento. Este esquema se aplica en los siguientes ejemplos para conocer la
estructura de un documento así como los datos contenidos en dicho documento.
De este modo, todos los programas tienen la misma estructura para poder analizar un
documento XML, que es la siguiente:
Creación de un nuevo objeto de tipo Parser usando la función newParser e inicio del análisis
del documento XML así como de su DTD, si está disponible.
A continuación, tiene que proporcionarse el código fuente XML o DTD, que puede ser de
tipo varchar2, CLOB (Character Large Object Binary) o un archivo.
Dependiendo del tipo de origen, se aplican los posibles métodos de análisis parse() o
parseDTD(), si los datos están almacenados en un archivo; parseBuffer() o
parseDTDBuffer, si los datos están contenidos en un elemento de tipo varchar2; o
parseClob() o parseDTDClob(), si los datos de origen se almacenan en un elemento de
tipo CLOB.
Para los documentos XML que se analizan mediante una de las funciones parse,
parseBuffer o parseClob, el resultado de la ejecución de estos métodos se guarda en un
documento accesible mediante getDocument().
El método getDocument() permite obtener el resultado del análisis y aplicar también los
restantes métodos del modelo DOM.
El método freeDocument permite liberar los recursos relativos al documento actualmente
utilizados por el analizador, con el fin de poder analizar otro documento.
Por último, la instrucción freeParser() permite liberar todos los recursos.
Lectura de un archivo XML
El primer paso consiste en poder leer el archivo en formato XML desde PL/SQL e interpretar
correctamente los datos procedentes de dicho archivo.
El siguiente script permite crear un procedimiento que recibe como parámetro un nombre de
archivo xml y lo abre con el fin de interpretar los datos que contiene. xmlDom y xmlParser son
sinónimos públicos de los paquetes DBMS_XMLDOM y DBMS_XMLPARSER.
-- obtener el documento
doc:=xmlParser.GetDocument(p);
-- liberar el documento
xmlDom.freeDocument(doc);
-- liberar el analizador
xmlParser.freeParser(p);
end;
/
show errors;
SQL>
espacioNombre varchar2(50);
-- elementos para generar el resultado
documentoF xmlDom.DOMDocumentFragment;
elementoF xmlDom.DomNode;
begin
-- creación de un nuevo analizador
p:=xmlParser.newParser;
-- obtener el documento
documentoXsl:=xmlParser.getDocument(p);
Este procedimiento permite aplicar una hoja de estilos (XSL) a un documento XML y el resultado
se proporciona bajo la forma de un tercer documento.
execute aplicarXsl(XML_DIR,’equipo.xml’,’equipo.xsl’,’/tmp/equipo.out’
XSU
La API XSU (Utilidad Xml SQL) para PL/SQL permite generar y almacenar documentos XML desde
y en la base de datos. Los paquetes que permiten implementar estas funcionalidades
son DBMS_XMLQuery yDBMS_XMLSave.
Para poder generar un documento XML que contenga los resultados de una consulta simple
usando el paquete DBMS_XMLQuery es necesario llevar a cabo los siguientes cinco pasos:
El siguiente ejemplo ilustra de forma muy sencilla cómo generar datos en formato XML a partir
del contenido de la base de datos:
set serveroutput on
-- Dar formato XML al resultado de una consulta
declare
contextConsulta DBMS_XMLQuery.ctxType;
resultado CLOB;
begin
-- definición del contexto de la consulta
contextConsulta:=DBMS_XMLQuery.newContext(’select * from clientes’);
-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);
-- mostrar el resultado
mostrarCLOB(resultado);
Con el fin de facilitar la presentación de los elementos en formato CLOB, se ha escrito el método
mostrarCLOB:
Por supuesto, el resultado es bastante satisfactorio, pero aún no constituye un documento XML
utilizable tal cual.
b. Modificación de las etiquetas ROW y ROWSET
La API XSU para PL/SQL permite modificar el nombre de las etiquetas ROW y ROWSET. En
nuestro ejemplo, la etiqueta ROW deberá tomar el nombre de CLIENTE y la etiqueta ROWSET el
de CLIENTES. Modificando ligeramente el script anterior y empleando los métodos setRowTag y
setRowSetTag se pueden llevar a cabo estas modificaciones.
set serveroutput on
-- Dar formato XML al resultado de una consulta
declare
contextConsulta DBMS_XMLQuery.ctxType;
resultado CLOB;
begin
-- definición del contexto de la consulta
contextConsulta:=DBMS_XMLQuery.newContext(’select * from clientes’);
-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);
-- mostrar el resultado
mostrarCLOB(resultado);
Las filas de datos extraídas a través de la consulta pueden incluirse en una página mediante los
procedimientos setMaxRows y setSkipRows. El procedimiento setMaxRows permite
establecer el número máximo de filas de datos que se convertirán a formato XML, mientras que
el procedimientosetSkipRows permite especificar el número de filas de datos que deben
omitirse antes de comenzar la conversión al formato XML.
Estos procedimientos pueden utilizarse, por ejemplo, para limitar el número de filas de datos
presentes en cada documento XML.
El siguiente ejemplo permite limitar a 10 el número de clientes que se incluyen en cada
documento XML generado. Con el fin de que no se genere ninguna excepción después de tratar
todas las filas, hay que llamar al método setRaiseNoRowsException:
set serveroutput on
-- Dar formato XML al resultado de una consulta
declare
contextConsulta DBMS_XMLQuery.ctxType;
resultado CLOB;
begin
-- definición del contexto de la consulta
contextConsulta:=DBMS_XMLQuery.newContext(’select * from clientes’);
-- mostrar el resultado
mostrarCLOB(resultado);
end loop;
exception
when others then
null; --salir del bloque en caso de error
end;
d. Hojas de estilo
La segunda solución es mejor que la primera, ya que evita tener que volver a procesar el
documento para aplicar la hoja de estilos en un segundo paso.
2. Consultas parametrizadas
Después de crear el contexto, hay que proporcionar la consulta SQL que se utilizará para extraer
los datos. Sin embargo, esta consulta puede contener parámetros a los que se les asignará un
valor justo antes de la ejecución de la consulta. En efecto, la consulta solo se ejecuta cuando se
solicita la construcción del documento XML final mediante el método getXMLClob.
Durante la escritura de la consulta, las variables se consideran como variables externas y, por
tanto, van precedidas del signo de dos puntos (:).
Ejemplo
set serveroutput on
-- Dar formato XML al resultado de una consulta
declare
contextConsulta DBMS_XMLQuery.ctxType;
resultado CLOB;
begin
-- definición del contexto de la consulta
contextConsulta :=DBMS_XMLQuery.newContext(’select * from clientes where
numcli=:numero’);
-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);
-- mostrar el resultado
mostrarCLOB(resultado);
-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);
-- mostrar el resultado
mostrarCLOB(resultado);
-- cierre del contexto de la consulta
DBMS_XMLQuery.closeContext(contextConsulta);
end;
/
La API XSU para PL/SQL también incluye el paquete DBMS_XMLSave, el cual permite almacenar,
en las tablas de la base de datos, datos que inicialmente se encuentran en documentos con
formato XML. Gracias a este segundo paquete, XSU permite demostrar que XML es realmente
un formato de intercambio de datos que puede utilizarse para realizar transferencias de datos
entre bases de datos.
Se pueden emplear los datos proporcionados en formato XML para realizar operaciones de
inserción, actualización y borrado (instrucciones INSERT, UPDATE o DELETE).
En general, todos los scripts PL/SQL que utilizan el paquete DBMS_XMLSave respetan la siguiente
estructura:
Para emplear los datos existentes en el documento XML con el fin de añadirlos a una tabla basta
con especificar el nombre de la tabla o vista, así como el documento XML. XSU se encarga de
generar las instrucciones INSERT. Por omisión, la instrucción INSERT afecta a todas las columnas
de la tabla o vista y se emplea el valor NULL cuando no se especifica otra cosa en el documento
XML.
Ejemplo
-- añadir filas
numFilas:=DBMS_XMLSave.insertXML(contextAgregar, documentoXML);
-- cerrar el contexto
DBMS_XMLSave.closeContext(contextAgregar);
end;
/
-- establecer el directorio
create or replace directory "xml_dir" as ’C:\xml’;
dest_clob CLOB;
archivo_in BFILE;
tamaño number;
inicio_destino integer:=1;
inicio_origen integer:=1;
juego_caracteres number:=0;
contexto_idioma number:=0;
aviso number:=0;
vid number;
begin
archivo_in:= bfilename(’xml_dir’,’datos.xml’);
-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);
if (dbms_lob.fileexists(archivo_in)=1) then
-- cerrar el archivo
dbms_lob.fileclose(archivo_in);
end if;
end;
/
También se puede emplear este método de inserción para afectar solo a determinadas columnas
de la tabla de destino. En este caso, es preciso llamar al método setUpdateColumn para
especificar el nombre de las columnas que van a contener los valores que hay que insertar. Para
eliminar cualquier riesgo de definir mal los parámetros, el
método clearUpdateColumnList permite eliminar toda referencia que se haya podido
hacer a las columnas anteriormente.
Ejemplo
El ejemplo siguiente lee los datos en formato XML almacenados en un archivo y después carga
los datos en la tabla de clientes:
declare
-- variables necesarias para leer un archivo
documentoXML CLOB;
archivo_in BFILE;
tamaño number;
inicio_destino integer:=1;
inicio_origen integer:=1;
juego_caracteres number:=0;
contexto_idioma number:=0;
aviso number:=0;
begin
archivo_in:= bfilename(’xml_dir’,’datos2.xml’);
-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);
-- cerrar el archivo
dbms_lob.fileclose(archivo_in);
end;
/
b. Actualización de datos
La actualización es una operación algo más delicada, ya que es necesario indicar la o las
columnas que sirven para identificar la fila, así como la o las columnas cuyos valores se van a
actualizar.
Ejemplo
El siguiente ejemplo permite especificar la ciudad y el código postal de los clientes con números
200 y 201 (los clientes añadidos en los ejemplos anteriores):
declare
-- variables necesarias para leer un archivo
documentoXML CLOB;
archivo_in BFILE;
tamaño number;
inicio_destino integer:=1;
inicio_origen integer:=1;
juego_caracteres number:=0;
contexto_idioma number:=0;
aviso number:=0;
begin
archivo_in:= bfilename(’xml_dir’,’datos3.xml’);
-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);
end;
/
Por último, se puede utilizar un documento XML para llevar a cabo el borrado de una serie de
datos. Las columnas existentes en el documento XML servirán para construir la cláusula WHERE.
Se puede limitar el número de columnas utilizadas para definir la restricción de filas llamando al
procedimientosetKeyColumn.
El siguiente ejemplo permite borrar los clientes número 200 y 201. Esta información está
almacenada en un archivo XML denominado datos4.xml.
declare
-- variables necesarias para leer un archivo
documentoXML CLOB;
archivo_in BFILE;
tamaño number;
inicio_destino integer:=1;
inicio_origen integer:=1;
juego_caracteres number:=0;
contexto_idioma number:=0;
aviso number:=0;
begin
archivo_in:= bfilename(’xml_dir’,’datos4.xml’);
-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);
end;
/
Para las versiones anteriores, Oracle Application Express puede descargarse e instalarse en una
base de datos existente. Anteriormente, Oracle Application Express se conocía con el nombre de
HTML DB. Es posible probar las funcionalidades de APEX desde el siguiente sitio de
Internet: http://apex.oracle.com. Después de la inscripción (gratuita) a este sitio, es posible
utilizar APEX para probar el producto.
Con APEX es posible trabajar con un servidor Oracle sin que sea necesario tener un alto dominio
del lenguaje SQL. No obstante, los conocimientos en SQL y PL/SQL le permitirán trabajar de una
manera más precisa. Con la interfaz APEX se evitan errores de sintaxis y se facilita la realización
de operaciones tediosas.
APEX permite, de una manera muy sencilla, poner en marcha una aplicación de tipo Web que
utilice los datos almacenados en la base de datos Oracle.
Activar Oracle Application Express
Aunque APEX se instala por defecto desde Oracle 11g, es necesario realizar algunas operaciones
para activarlo; estas operaciones deben realizarse por el administrador de la base de datos.
C:\>sqlplus /nolog
Conectado.a
SQL> @?/apex/apxconf.sql
PORT
----------
8080
Enter values below for the XDB HTTP listener port and the password
for the Application Express ADMIN user.
Default values are in brackets [ ].
Press Enter to accept the default value.
Enter a value below for the password for the Application Express ADMIN user
Sesión modificada.
Usuario modificado.
Para instalar otros idiomas (por ejemplo, el español) puede proceder de la siguiente manera:
Siempre en el servidor Oracle defina, a nivel del sistema operativo, la variable de entorno
NLS_LANG para utilizar el juego de caracteres AL32UTF8.
C:\>set NLS_LANG=spanish_spain.AL32UTF8
Inicie SQL*Plus, conéctese como SYS y defina el esquema APEX como esquema actual.
C:\>sqlplus /nolog
Sesión modificada.
SQL> @?/apex/builder/es/load_es.sql
...
La carga del idioma dura varios minutos.
Tras la primera conexión, la interfaz le propone modificar la contraseña. Una vez modificada la
contraseña, la página de conexión se presentará de nuevo.
En la primera página, indique un nombre para el espacio de trabajo y pulse el botón Siguiente
>.
En la página siguiente, indique si el espacio de trabajo está asociado a un esquema existente, o
si debe crearse un esquema nuevo. En este ejemplo vamos a crear un esquema nuevo. Para ello
es preciso indicar un nombre, una contraseña y un tamaño. A continuación, pulse el
botón Siguiente >.
Para terminar, debe crear un administrador para el nuevo espacio de trabajo. Para ello, indique
un nombre, una contraseña y una dirección de correo electrónico. Pulse el botón Siguiente > para
visualizar la página de resumen.
Si la información es correcta, puede pulsar el botón Crear Espacio de Trabajo para confirmar
la creación del espacio de trabajo. Cuando la creación ha terminado, se visualiza una página de
confirmación:
En este estado, es posible crear otros usuarios: desarrolladores de aplicaciones que podrán
trabajar en un espacio de trabajo, o usuarios finales de las aplicaciones desarrolladas con APEX.
En este libro se utilizará la cuenta del administrador del espacio de trabajo como cuenta de
desarrollo.