Está en la página 1de 423

Oracle 12c

SQL, PL/SQL y SQL*Plus


Este libro sobre Oracle 12c se dirige a todos los informáticos que quieran adquirir todas las
competencias necesarias que le permitan dominar la gestión de una base de datos Oracle.

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).

Muchos ejemplos concretos ayudan a adquirir el dominio de estos lenguajes de referencia en el


mundo de las bases de datos relacionales. Estos ejemplos se pueden descargar en esta página.

Los capítulos del libro:


Introducción – Modelo relacional – SQL – SQL*Plus y SQL Developer – PL/SQL – PL/SQL en objetos
de la base de datos – Java – El analizador de XML – Application Express

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.

Estas herramientas emplean un lenguaje común: el SQL.

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.

1. Generalidades sobre los archivos

Un archivo informático es un conjunto de datos de la misma naturaleza (texto, código ejecutable,


datos...), que se identifica mediante un nombre y se guarda en un soporte físico (disco duro,
disquete, cinta, CD-ROM...).

Un archivo puede tener diferentes funciones:

 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 de datos se distinguen según su utilidad en el seno de la aplicación, marcando el


tipo de archivo. Este tipo permitirá seleccionar a la vez el soporte físico del archivo y su
organización.

Tipos de archivos de datos

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.

2. Organizaciones típicas de los archivos

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.

Las opciones principales para la organización de archivos son la organización secuencial, la


organización secuencial indexada, las bases de datos navegables y, evidentemente, las bases de
datos relacionales.

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).

La ventaja de este tipo de organización reside en la simplicidad de uso, la estandarización de las


estructuras y la optimización del espacio de almacenamiento.

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).

Organización secuencial indexada

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.

Además de las ventajas del sistema secuencial (simplicidad y estandarización), permite


encontrar rápidamente un registro en función de la clave.
El principal inconveniente sigue siendo que los archivos no están relacionados entre sí dentro de
la aplicación, por lo que es necesaria una gran cantidad de programación para garantizar la
integridad de los datos. Asimismo, hay que destacar el despilfarro de espacio debido a la
redundancia de los datos (especialmente las claves).

Bases de datos navegables

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.

Los sistemas de gestión de bases de datos relacionales (RDBMS, Relational Database


Management System) administran de forma independiente el nivel lógico (objetos o entidades)
y el nivel físico (archivos).

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.

La implementación de la base de datos se facilita mediante un lenguaje declarativo (no


procedimental) sencillo, basado en la lógica de conjuntos.

a. Dominio

Es un conjunto de valores caracterizado por un nombre.

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:

Estados de los pedidos =


{"EC", "SU", "FA", "SE"};cardinalidad 4
Números de orden =
{n | 1<=n<=9999};cardinalidad 9999

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

Es una columna de una relación, caracterizada por un nombre.

Grado

Es el número de atributos de una relación.

Ejemplo

Para asociar un único tipo de impuesto a cada código, sólo deben considerarse tres parejas.

Relación IVA = {(1,0),(2,4),(3,16)}


Representación

Se realiza en forma de tabla, enumerando los elementos:

O de forma declarativa:

IVA (CODIGO:códigos, VALOR:IVA)

IVA (CODIGO, VALOR)

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.

Algunas de estas reglas son:

Coherencia

Todo valor tomado por un atributo debe pertenecer al dominio sobre el que está definido.

Unicidad

Todos los elementos de una relación deben ser diferentes.

Identificador

Atributo o conjunto de atributos que permiten caracterizar de forma unívoca cada elemento de
la relación.

Clave primaria

Identificador mínimo de una relación.

Claves secundarias

Otros identificadores de la relación.

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

Atributo o conjunto de atributos que verifica la regla de integridad referencial.

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.

Puede emplearse el siguiente modelo:

CLIENTES (NUMEROCLI,NOMBRECLI,DIRECCLI)

NUMEROCLI identificador clave primaria de CLIENTES


(NOMBRECLI,DIRECCLI) identificador clave secundaria de CLIENTES

PEDIDOS (NUMEROPED,FECHAPED,NUMEROCLI,ESTADOPED)

NUMEROPED identificador clave primaria de PEDIDOS


NUMEROCLI clave externa de PEDIDOS, que hace referencia a
NUMEROCLI de CLIENTES

Valor nulo

En el modelo relacional, el concepto de valor nulo es perfectamente admisible. Se trata de un


valor que representa un dato desconocido o inaplicable en una columna.

Se denota mediante _ , ˆ o NULL.

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

Sean las tablas CLIOESTE y CLICENTRO:


Clientes de las dos regiones:

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

Los clientes comunes a las dos regiones son:

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

Los clientes que solo pertenecen a la región OESTE son:


CLIOESTESOLO=CLIOESTE - CLICENTRO

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

La condición se expresa como sigue:

[NOT] [(]atributo operador valor [)] [{AND/OR}condición]

operador un operador de comparación: =, <>, >, <, >=, <=

valor una constante u otro atributo.

Ejemplos

Clientes de ORENSE:

CLIORENSE=σ(DIRECCION="ORENSE")CLIOESTE

Artículos de la serie AB:

ART1=σ(REFART>="AB" AND REFART<"AC")ARTICULOS

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.

Notación: Rx = π R (A1, A2, ..., An).

Ejemplos

Pedidos y estado de los pedidos:

PED= π PEDIDOS(NUMEROPED,NUMEROCLI,ESTADOPED)

Clientes que han realizado pedidos:

CLIPED1= π PEDIDOS(NUMEROCLI)

Clientes y estado de los pedidos:

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

Sean las tablas:

INVENTARIO = DEPOSITO X ART2

g. Combinaciones

La combinación entre dos relaciones de acuerdo a una condición se obtiene aplicando una
restricción al producto cartesiano.

Notación: Rx = S1 JOIN (condición) S2

Ejemplo

Sean las tablas:


LINEASPEDEC = PEDEC JOIN (PEDEC.NUMEROPED =
LINEASPED.NUMPED) LINEASPED

Combinación-theta

La condición es una comparación entre dos atributos.

Equi-combinación

La condición es una igualdad entre dos atributos.

Combinación natural

Es una combinación de igualdad entre atributos con el mismo nombre.

h. Campos calculados elementales

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.

Notación: Rx = π S (A1, ..., N1 = expresión calculada...)

La expresión calculada puede ser:

 una operación aritmética,


 una función matemática,
 una función de cadena.

Ejemplo

Se desea obtener el importe de una línea de pedido (Precio * Cantidad).

LINEAPEDIMP = π LINEAPED(NUMPED,NUMLIN,REFART,
IMPLINEA=CANTPED*PRECSINIVA)

i. Cálculos de valores agregados

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.

Notación: Rx = π S (A1, ..., N1= función estadística (Ax), ...)

Las funciones estadísticas son:

COUNT (*) número de líneas.

COUNT (atributo) número de valores no nulos (NULL).

SUM (atributo) suma de valores no nulos.

AVG (atributo) media de valores no nulos.

MAX (atributo) valor máximo (no nulo).

MIN (atributo) valor mínimo (no nulo).

Ejemplos

Número total de clientes que hay en la tabla.

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))

2. Etapas para la resolución de problemas

En una base de datos conocida (esquemas, dominios, relaciones, elementos), la resolución de


un problema se realiza en tres etapas.

a. Análisis de las necesidades


 Expresar las necesidades expuestas por el cliente en forma de relación.
 Determinar los atributos y las relaciones que se van a utilizar.
 Especificar los campos calculados elementales y agregados para crear los atributos no
existentes.
b. Definición de la vista

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

Clase a: atributo que interviene en la relación resultante.

Clase b: atributo que interviene en un cálculo.

Clase c: atributo que interviene en una restricción.

Clase d: atributo que interviene en una combinación.


c. Orden y especificación de las operaciones

En general, y salvo excepciones, el orden de las operaciones puede ser el siguiente:

1 Relaciones implicadas.

2 Restricciones (para eliminar las filas que no son útiles).

3 Combinaciones, Productos cartesianos, Uniones, Intersecciones, Diferencias (para asociar las filas
restantes).

4 Campos calculados elementales (para crear nuevas columnas).

5 Campos agregados (para las columnas de totalización).

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).

7 Repetir el paso 5 para las restantes agrupaciones.

8 Restricciones relacionadas con los atributos calculados.

9 Proyecciones para eliminar valores duplicados.

10 Proyección final para eliminar los atributos inútiles en la tabla resultante.

Ejemplo

Sea la base de datos compuesta por las tablas siguientes:

CLIENTES (NUMCLI,NOMCLI,DIRECCION)
ARTICULOS (REFART,DESCRIPCION,PRECSINIVA)
PEDIDOS (NUMPED,NUMCLI,FECHAPED,ESTADOPED)
LINEASPED (NUMPED,NUMLIN,REFART,CANTPED)

Se desea obtener el formulario de confirmación del pedido N°1301.

Plantilla del documento:


A partir del análisis de la plantilla y de las tablas iniciales, se deduce que:

fecha actual: información que puede especificarse durante la


generación del formulario.
N° de pedido = NUMPED de PEDIDOS
Fecha del pedido = FECHAPED
Nombre del cliente = NOMCLI de CLIENTES
Dirección del cliente = DIRECCION de CLIENTES
Referencia = REFART de LINEASPED
Descripción = DESCRIPCION de ARTICULOS
Cantidad pedida = CANTPED de LINEASPED
Precio sin IVA = PRECSINIVA de ARTICULOS
Importe sin IVA= campo que hay que calcular
Total sin IVA = campo que hay que calcular

Para definir el documento, será necesaria por tanto la siguiente tabla:

CONFPED (NUMPED,FECHAPED,NOMCLI,DIRECCION,REFART,
DESCRIPCION,PRECSINIVA,CANTPED,IMPSINIVA,TOTSINIVA)

siendo IMPSINIVA = PRECSINIVA*CANTPED en cada línea del pedido y TOTSINIVA =


SUM(IMPSINIVA) el precio total del pedido.

Vista
Operaciones

Restricción sobre el número de pedido:

T1=σ(NUMPED=1301) PEDIDOS

T2=σ(NUMPED=1301) LINEASPED

Combinación natural de PEDIDOS y LINEASPED:

T3=T1 JOIN (T1.NUMPED=T2.NUMPED) T2

Combinación natural de PEDIDOS y CLIENTES:

T4=T3 JOIN (T3.NUMCLI=CLIENTES.NUMCLI) CLIENTES


Combinación natural de LINEASPED y ARTICULOS:

T5=T4 JOIN (T4.REFART=ARTICULOS.REFART) ARTICULOS

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)

Proyección del valor agregado para TOTSINIVA:

T7=πT6(NUMPED,TOTSINIVA=SUM(IMPSINIVA))

Combinación para disponer de todas las columnas en la tabla resultante:

CONFCDE=T6 JOIN (T7.NUMPED=T6.NUMPED) T7


Generalidades
SQL (Structured Query Language, lenguaje estructurado de consulta) es un lenguaje de consulta
utilizado para manipular bases de datos relacionales.

Fue desarrollado a mediados de los años 70 por IBM y lo comenzó a comercializar Oracle en
1979.

El interés del SQL reside en las siguientes características:

Normalización

Implementa el modelo relacional y se describe en los estándares de los principales organismos


de normalización, que lo describen como sigue:

 El instituto ANSI (American National Standards Institute) lo describe en sus documentos


ANSI 9075-1:1999, ANSI 9075-2:1999 y ANSI 9075-5:1999. Puede obtener más detalles
sobre estos documentos que describen la norma visitando el sitio web de ANSI
(http://webstore.ansi.org) o bien el sitio web de NCITS (National Comittee for Information
Technology Standards) que incluye parte de los estándares ANSI sobre SQL
(http://www.incits.org).
 ISO (International Organisation for Standardization) lo describe en los documentos
ISO/IEC 9075-1:1999, ISO/IEC 9075-2:1999 e ISO/IEC 9075-5:1999. Puede obtener una
copia de los documentos de normalización en el sitio web de
ISO: http://www.iso.ch/iso/iso_catalogue.html.

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.

Las instrucciones se escriben en inglés, en lenguaje natural.


El SQL permite manipular tanto registros individuales como conjuntos de registros y permite el
uso del resultado en otro comando. Por tanto, no son necesarias estructuras de control como en
los lenguajes de programación habituales (lenguajes de tercera generación).

Universal

El lenguaje SQL puede utilizarse en todos los niveles de la gestión de una base de datos:

 administración del sistema,


 administración de la base de datos,
 desarrollo y aplicaciones,
 gestión de datos simple.

Todos los usuarios de la base de datos disponen por tanto de un lenguaje común.

Este lenguaje permite además realizar todas las operaciones:

 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.

El primero es la base de datos, que agrupa al conjunto de los demás objetos.

Estos objetos pueden agruparse en diferentes categorías en función de su utilidad.

a. La gestión de los datos


tabla (table) Conjunto de líneas (filas) y columnas.

í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).

sinónimo (synonym) Nombre alternativo para una tabla o una vista.

secuencia (sequence) Generador de una serie de números.

instantáneas (snapshots) Tabla que contiene el resultado de una consulta realizada sobre una
tabla creada en una base de datos remota.

enlaces de base de datos Vínculos con otras bases de datos remotas.


(database links)
b. Almacenamiento físico
agrupación (clúster) Agrupación física de tablas que tienen columnas comunes.
espacio de tablas Agrupación lógica de archivos.
(tablespace)

directorio (directory) Representación en la base de datos de un directorio del sistema operativo


del host.

c. Almacenamiento de instrucciones
esquema (schema) Conjunto de objetos de la base de datos lógica que pertenecen a un
mismo usuario.

procedimiento (procedure) Fragmento de código procedimental nominado.

función (function) Fragmento de código procedimental nominado que devuelve un


valor.

disparador de base de datos Fragmento de código procedimental asociado con una tabla.
(database trigger)

paquetes (packages) Colección de objetos (procedimiento, función...) almacenados de


manera conjunta.

biblioteca (library) Representación de una colección de procedimientos externos a


Oracle, almacenados en bibliotecas compartidas del sistema.

d. Gestión de los usuarios


perfil (profile) Conjunto nominado de restricciones del sistema.

rol (role) Conjunto de privilegios que puede atribuirse a los usuarios.

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.

e. Denominación de los objetos

Los nombres de los objetos deben ajustarse a las siguientes reglas:

 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

Los nombres que se utilicen deben ser significativos y no demasiado largos.

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 SQL se agrupan en categorías en función de su utilidad y de las entidades


manipuladas.

a. DDL (Data Definition Language, lenguaje de definición de datos)

Permite gestionar las "estructuras" de los objetos:

 Crear, modificar, eliminar objetos.


 Autorizar o prohibir el acceso a los datos.
 Activar o desactivar la auditoría.
 Añadir comentarios al diccionario de datos.

Las instrucciones DDL son: CREATE, ALTER, DROP, GRANT, REVOKE, AUDIT, NOAUDIT,
ANALYZE, RENAME, TRUNCATE, COMMENT, FLASHBACK y PURGE.

b. DML (Data Manipulation Language, lenguaje de manipulación de datos)

Permite la gestión de los datos contenidos en los objetos existentes:

 Añadir, eliminar y modificar filas.


 Visualizar el contenido de las tablas.
 Bloqueo de tablas.

Las instrucciones DML son: INSERT, UPDATE, DELETE, SELECT, EXPLAIN PLAN, LOCK TABLE y
MERGE.

c. TCL (Transaction Control language)

Gestiona las modificaciones realizadas por las instrucciones DML:

 Características de las transacciones.


 Validación y anulación de modificaciones.

Las instrucciones del TCL son: COMMIT, SAVEPOINT, ROLLBACK, SET TRANSACTION y SET
CONSTRAINT.
d. SCL (Session Control language)

Permite la gestión de una sesión de usuario:

 Modificación de las características de sesión.


 Activación y desactivación de los privilegios de usuario.

Las instrucciones del SCL son: ALTER SESSION, SET ROLE.

e. Embedded SQL

Permite integrar los lenguajes DDL, DML y de control de transacciones en un lenguaje de


programación:

 Declaraciones de objetos o de instrucciones.


 Ejecución de instrucciones.
 Gestión de variables y cursores.
 Tratamiento de errores.

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)

Cadena de caracteres de longitud fija de n bytes, que se completa añadiendo espacios a la


derecha (n <= 2000).

VARCHAR2 (n)

Cadena de caracteres de longitud variable, de n bytes como máximo (n <= 4000 si el


argumento MAX_STRING_SIZE es igual a STANDARD; n <= 32767 si el argumento
MAX_STRING_SIZE es igual a EXTENDED).

NCHAR (n)

Cadena de caracteres de longitud fija de n bytes, que se completan añadiendo espacios a la


derecha (n <= 2000). Los caracteres se codifican de acuerdo con el juego de caracteres
nacional activo.
NVARCHAR2 (n)

Cadena de caracteres de longitud variable, de n bytes como máximo (n <= 4000 si el


argumento MAX_STRING_SIZE es igual a STANDARD; n <= 32767 si el argumento
MAX_STRING_SIZE es igual a EXTENDED). Los caracteres se codifican de acuerdo con el juego
de caracteres nacional activo.

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

Fecha comprendida entre el 1 de enero de 4712 a.C. y el 31 de diciembre de 9999 d.C.

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.

TIMESTAMP(p) WITH TIME ZONE

Datos de tipo TIMESTAMP con desplazamiento de zona horaria.

TIMESTAMP(p) WITH LOCAL TIME ZONE

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).

Los siguientes tipos de datos aseguran la compatibilidad con las versiones


anteriores

LONG

Cadena de caracteres de longitud variable (2 GB como máximo).

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.

LONG RAW (n)

Datos binarios de longitud variable (4 GB como máximo); cuyo contenido no es interpretado


por Oracle.

Tipos de datos extendidos (Extended Data Types)

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.

Es posible definir hasta 1000 columnas por tabla.

Sintaxis

CREATE TABLE nombre (nombrecolumna type [DEFAULT expr]


[[CONSTRAINT nombre restricción-de-columna...],...
[,CONSTRAINT nombre restricción-de-tabla...]);

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.

REFERENCES tabla [(columna)] [ON DELETE {CASCADE|SET NULL]

Restricción de integridad referencial para el atributo en la tabla de detalle que se está


definiendo. Los valores tomados por este atributo deben existir en una columna que tenga
asociada una restricción PRIMARY KEY o UNIQUE en la tabla maestra.

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.

b. Restricciones de tabla (sobre varias columnas)

PRIMARY KEY (columna,...)

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,...)

Designa la concatenación de los atributos especificados como clave secundaria de la tabla. En


el caso de que esta restricción UNIQUE se aplique sobre una serie de columnas concatenadas,
al menos una de las columnas que formen parte de esta clave secundaria debe permitir
distinguir la fila de manera unívoca. Esta restricción puede aparecer varias veces en la
instrucción.

FOREIGN KEY (columna,...) REFERENCES tabla [(columna,...)] [ON DELETE {CASCADE


| SET NULL}]

Restricción de integridad referencial para el conjunto de atributos especificados de la tabla de


detalle que se está definiendo. Los valores que toman estos atributos deben existir en una
columna que tenga asociada una restricción PRIMARY KEY o UNIQUE en la tabla maestra.

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 la eliminación de las filas dependientes contenidas en la tabla que se está


definiendo, si se elimina la fila que contiene la clave primaria correspondiente en la tabla
maestra. Si esta opción no se especifica, será imposible eliminar en la tabla maestra las filas
que hacen referencia a este valor de clave primaria.

ON DELETE SET NULL


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

Realiza o no (NOT) la verificación de la restricción en el momento de validar la transacción.

d. Denominación de las restricciones

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

Tabla Nombre de la tabla sobre la que se define la restricción.

Columna Nombre de la columna o columnas sobre las que se define la


restricción.

TipoDeRestriccion: mnemónico asociado con el tipo de restricción:


PK Clave primaria
UQ Unique
NN Not Null
CK Check
RF Referencias
FK Clave primaria

Ejemplos

Creación de una tabla ARTICULOS con una sola restricción de clave primaria REFART:

SQL> create table ARTICULOS(


2 REFART char(4) primary key,
3 DESCRIPCION varchar2(30),
4 PRECIO number(8,2),
5 CODIVA number(1),
6 CATEGORIA char(10),
7 CANTALM number(5)
8 );

Tabla creada.
SQL>

En este caso, DESCRIPCION, PRECIO y CANTALM pueden ser NULL: PRECIO y CANTALM pueden
tomar valores negativos.

Creación de una tabla CLIENTES con restricciones sobre las columnas:

SQL> create table CLIENTES(


2 NUMCLI number(4)
3 constraint CLIENTES_PK primary key
4 constraint CLIENTES_NUMCLI_CK check (NUMCLI>0),
5 NOMCLI varchar2(30)
6 constraint CLIENTES_NOMCLI_NN not null,
7 DIRECCLI varchar2(60),
8 COD_POSTAL number(5)
9 constraint CLIENTES_COD_POSTAL_CK
10 check(COD_POSTAL between 1000 and 99999),
11 CIUDAD char(30)
12 );

Tabla creada.

SQL>

NUMCLI y NOMCLI son obligatorios;

NUMCLI debe ser siempre positivo;

COD_POSTAL debe pertenecer al intervalo especificado.

Creación de la tabla de pedidos utilizando una sintaxis de tipo restricción de tabla para definir
las restricciones de integridad.

SQL> create table PEDIDOS(


2 NUMPED number(6),
3 NUMCLI number(4),
4 FECHAPED date,
5 ESTADOPED char(2),
6 constraint PK_PEDIDOS primary key (NUMPED),
7 constraint FK_PEDIDOS_CLIENTES foreign key(NUMCLI)
8 references CLIENTES(NUMCLI),
9 constraint CK_PEDIDOS_ESTADO check (ESTADOPED in (’EC’,’SU’,’SE’))
10 );

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:

SQL> create table LINPED(


2 NUMPED number(6)
3 constraint FK_LINPED_PEDIDOS
4 references PEDIDOS(NUMPED),
5 NUMLIN number(2)
6 constraint CK_LINPED_NUMLIN check (NUMLIN>0),
7 REFART char(4)
8 constraint FK_LINPED_ARTICULOS
9 references ARTICULOS(REFART),
10 CANTPED number(5),
11 constraint PK_LINPED primary key (NUMPED,NUMLIN)
12 );

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.

La cláusula AS permite especificar la expresión que determina el valor de la columna. Esta


expresión puede hacer referencia a otras columnas reales (no virtuales) de la misma tabla, pero
no puede hacer referencia a ninguna columna de otra tabla.

Las palabras reservadas GENERATED ALWAYS y VIRTUAL son opcionales; pueden especificarse
para hacer la sintaxis más clara.

Puede definirse una restricción de columna sobre una columna virtual.

Ejemplo

SQL> create table ARTICULOS (


2 REFART char(4) primary key,
3 DESCRIPCION varchar2(30),
4 PRECSINIVA number(8,2),
5 IVA number(4,2),
6 PRECCONIVA number(8,2)
7 AS ( PRECSINIVA + round(PRECSINIVA * IVA/100,2))
7 );
Tabla creada.

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

f. Columna de tipo identidad

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

nombrecolumna type GENERATED [ALWAYS | BY DEFAULT [ON NULL]]


AS IDENTITY [(options)][restricción-de-columna]

La clausura ALWAYS fuerza el uso de la identidad; se devuelve un error si un INSERT intenta


asignar un valor (incluso NULL) en la columna o si un UPDATE intenta modificar la columna. Es
el valor por defecto de la cláusula GENERATED AS IDENTITY.

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).

Esta funcionalidad tiene las siguientes restricciones:

 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

SQL> create table CATEGORIAS (


2 NOCAT number(3) generated as identity,
3 NOMBRE varchar2(30)
4 );

Tabla creada.
SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);

1 fila creada.

SQL> insert into CATEGORIAS (NOMBRE)


2 values (’Bricolaje’);

1 fila creada.

SQL> select * from CATEGORIAS;

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.

SQL> create table CATEGORIAS (


2 NOCAT number(3) generated by default as identity,
3 NOMBRE varchar2(30)
4 );

Tabla creada.

SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);

1 fila creada.

SQL> insert into CATEGORIAS (NOMBRE)


2 values (’Bricolaje’);

1 fila creada.

SQL> select * from CATEGORIAS;

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.

SQL> update CATEGORIAS set NOCAT = 456 where NOMBRE = ’Informática’;

1 fila modificada.

SQL> select * from CATEGORIAS;

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.

SQL> create table CATEGORIAS (


2 NOCAT number(3) generated by default on null as identity,
3 NOMBRE varchar2(30)
4 );

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.

SQL> select * from CATEGORIAS;

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

nombrecolumna type [VISIBLE | INVISIBLE] [DEFAULT [ON NULL] expr]


[restricción-de-columna]

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.

SQL> -- Pero la columna se puede especificar explícitamente


SQL> -- en un INSERT (o UPDATE).
SQL> insert into CATEGORIAS (NOCAT,NOMBRE,RESPONSABLE)
2 values (2,’Libros’,’Ángel’);

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

Esta funcionalidad es interesante durante la evolución de la estructura de una tabla. Es posible


añadir una columna invisible a una tabla sin impactar el código existente que funciona como si
la columna no existiera, permitiendo al nuevo código o al existente modificado hacer referencia
explícitamente a las columnas invisibles en las consultas. La columna se puede hacer visible más
adelante, cuando todo el código existente se haya modificado para funcionar correctamente.

3. Eliminación de una tabla

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.

Si se hace referencia a la clave primaria de la tabla en otras tablas mediante restricciones de


tipo REFERENCES o FOREIGN KEY, la cláusula CASCADE CONSTRAINTS permite suprimir estas
restricciones de integridad referencial en las tablas "descendientes".

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

DROP TABLE nombre [CASCADE CONSTRAINTS] [PURGE];

Ejemplo

Eliminación de la tabla CLIENTES cuya columna NUMCLI es una clave externa en la tabla
PEDIDOS:

SQL>drop table CLIENTES;


drop table CLIENTES
*
ERROR en línea 1:
ORA-02449: claves únicas/primarias en la tabla referidas por claves ajenas

SQL>drop table CLIENTES cascade constraints;

Tabla borrada.

Borrado de la tabla de CLIENTES con petición de liberación del espacio físico:

SQL> drop table CLIENTES cascade constraints purge;

Table dropped.
SQL>

4. Modificación de una tabla

Es posible modificar la estructura de una tabla en varios niveles:

 añadiendo columnas (nombre, tipo, valor predeterminado, restricción NOT NULL),


 añadiendo restricciones de columna (únicamente la restricción NOT NULL),
 añadiendo restricciones de tabla,
 definiendo de nuevo una columna (tipo, valor predeterminado y visibilidad),
 activando o desactivando restricciones de columna o de tabla,
 eliminando restricciones de columna o de tabla,
 cambiando el nombre de la tabla,
 autorizando o no las modificaciones en la tabla.
a. Adición o modificación de columnas

Sintaxis

ALTER TABLE nombre {ADD/MODIFY} ([columna tipo [visibilidad] [defecto]


[restricción, ...])

Ejemplo

SQL> describe CLIENTES


Nombre Nulo? Tipo
----------------------------------------- -------- -------------
NUMCLI NOT NULL NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
DIRECCLI VARCHAR2(60)
COD_POSTAL NUMBER(5)
CIUDAD CHAR(30)

SQL> alter table CLIENTES add (TEL char(14));

Tabla modificada.

SQL> alter table CLIENTES modify (DIRECCLI char(30));

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

SQL> alter table ARTICULOS add


2 ( PRECIO_NETO number(8,2) AS ( PRECIO_BRUTO + round(PRECIO_BRUTO *
iva/100,2) ) );

Tabla modificada.

SQL> alter table ARTICULOS modify


2 ( PRECIO_NETO AS ( PRECIO_BRUTO + round(PRECIO_BRUTO * IVA/100,2) ) );

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

SQL> alter table CATEGORIAS modify


2 (NOCAT generated by default on null as identity);

Tabla modificada.
SQL> alter table CATEGORIAS modify (NOCAT drop identity);

Tabla modificada.

b. Adición de una restricción de tabla

Sintaxis

ALTER TABLE nombre_tabla ADD[CONSTRAINT nombre] restricción

La sintaxis de declaración de restricciones es idéntica a la que se utiliza para crear una tabla.

Ejemplo

El siguiente ejemplo permite añadir una restricción de validación a la tabla ARTICULOS:

SQL> alter table ARTICULOS


2 add constraint ARTICULOS_PRECIO_CK check (PRECIO >= 0);

Tabla modificada.

SQL>

Es posible definir una restricción de tipo NOT NULL mediante el comando ALTER TABLE.

Si los datos ya existen en la tabla en el momento en que se añade la restricción de integridad,


entonces todas las filas de información deben verificar la restricción. En caso contrario, no se
aplica la restricción a la tabla.

La cláusula EXCEPTION INTO TABLE nombre_tabla permite conocer el rowid (identificador de


fila de Oracle) de las filas que no cumplen la restricción de integridad que se intenta aplicar o
reactivar. Así, el problema se puede corregir fácilmente.

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.

Creación de la tabla de excepciones:

SQL> create table excepciones(row_id rowid,


2 owner varchar2(30),
3 table_name varchar2(30),
4 constraint varchar2(30));

Tabla creada.

SQL>

Incluye en la tabla de excepciones las referencias de las filas que plantean problemas.

El siguiente fragmento de código intenta añadir una restricción de unicidad (UNIQUE) a la


dirección de los clientes:

SQL> alter table clientes


2 add constraint cli_direccli_un unique(direccli)
3 exceptions into excepciones;
add constraint cli_direccli_un unique(direccli)
*
ERROR en línea 2:
ORA-02299: no se puede validar (SCOTT.CLI_DIRECCLI_UN) - se han
encontrado claves duplicadas

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:

SQL> select numcli, direccli


2 from clientes, excepciones
3 where clientes.rowid=excepciones.row_id
4 and excepciones.table_name=’CLIENTES’
5 and excepciones.constraint=’CLI_DIRECCLI_UN’
6 ;

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.

c. Eliminación de una restricción

Sintaxis

ALTER TABLE nombre_tabla DROP{PRIMARY KEY/UNIQUE (columna)/CONSTRAINT} nombre

Ejemplo

SQL> alter table ARTICULOS


2 drop constraint ARTICULOS_PRECIO_CK;

Tabla modificada.

SQL>

d. Activación y desactivación de una restricción

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

ALTER TABLE nombre_tabla {ENABLE VALIDATE/ENABLE NOVALIDATE/DISABLE}


nombre_restricción

ENABLE VALIDATE

Activa la restricción si el conjunto de filas ya presentes en la tabla la cumplen.

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

En este ejemplo se desactiva la restricción sobre la columna COD_POSTAL de la tabla CLIENTES,


se inserta en dicha tabla un valor incompatible con la restricción desactivada y se intenta habilitar
de nuevo la restricción de comprobación (CHECK), validando los datos presentes en la tabla.

SQL> alter table CLIENTES


2 disable constraint CLIENTES_COD_POSTAL_CK;

Tabla modificada.

SQL> insert into CLIENTES (NUMCLI, NOMCLI, COD_POSTAL, CIUDAD)


2 values (128, ’Martín P.’, 999, ’ORENSE’);
1 fila creada.

SQL> alter table CLIENTES


2 enable validate constraint CLIENTES_COD_POSTAL_CK;
alter table CLIENTES
*

ERROR en línea 2:
ORA-02293: no se puede validar
[CLIENTES_COD_POSTAL_CK] - restricción de control violada

SQL>

e. Modificación de una restricción

No es posible modificar la definición de una restricción. Sin embargo, sí es posible modificar el


estado de una restricción.

Sintaxis

ALTER TABLE nombre_tabla MODIFY CONSTRAINT nombre_restricción


estado_restricción;

Los posibles estados de una restricción son los siguientes:

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

En cada nueva transacción, el funcionamiento predeterminado consiste en verificar la


restricción al completar cada instrucción DML. Esta opción está seleccionada de modo
predeterminado.

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

Modificación de la restricción de referencia entre las tablas LINEASPED y PEDIDOS:

SQL> alter table LINEASPED


2 modify constraint FK_LINEASPED_PEDIDOS DEFERRABLE
3 ;

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;

ALTER TABLE nombre_tabla DROP (nombre_columna, nombre_columna[,...]);

Ejemplo

Eliminación de la columna TEL en la tabla CLIENTES:

SQL> alter table CLIENTES


2 drop column TEL;

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

ALTER TABLE nombre_tabla SET UNUSED (nombre_columna[,...]);


ALTER TABLE nombre_tabla DROP UNUSED COLUMNS [CHECKPOINT num_filas];

Ejemplo

Convertir la columna TEL de la tabla CLIENTES en una columna no utilizable. Para ello, primero
se marca la columna como no utilizable.

SQL> alter table CLIENTES set unused (TEL);

Tabla modificada.

SQL>

A continuación se eliminan todas las columnas marcadas como no utilizables de la tabla


CLIENTES. Después de esta operación se pide al sistema que establezca un punto de
sincronización (CHECKPOINT) cada 200 eliminaciones. Esta precaución evita saturar la caché del
búfer (o buffer) de datos con los datos que se van a eliminar y permite realizar escrituras en
disco más a menudo.

SQL> alter table CLIENTES drop unused columns checkpoint 200;


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> select * from dba_unused_col_tabs;

OWNER TABLE_NAME COUNT


--------------------------- ------------------------------ ----------
SCOTT CLIENTES 1

SQL>

g. Cómo cambiar el nombre de una tabla

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

RENAME nombre_antiguo TO nombre_nuevo;

Ejemplo

Cambiar el nombre de la tabla ARTICULOS por PRODUCTOS:

SQL> rename ARTICULOS to PRODUCTOS;

Tabla cambiada de nombre.

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

ALTER TABLE nombre_tabla { READ ONLY / READ WRITE }

Ejemplo

SQL> alter table ARTICULOS read only;

Tabla modificada.

SQL> delete from ARTICULOS;


delete from ARTICULOS
*
Error en la línea 1:
ORA-12081: operación de actualización no permitida para
la tabla "HELIOS"."ARTICULOS"

SQL> update ARTICULOS set DESCRIPCION = upper(DESCRIPCION);


update ARTICULOS set DESCRIPCION = upper(DESCRIPCION)
*
Error en la línea 1:
ORA-12081: operación de actualización no permitida para
la tabla "HELIOS"."ARTICULOS"

SQL> alter table ARTICULOS read write;

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).

5. Restauración de una tabla

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.

No es posible incluir esta operación en una transacción.

Oracle no puede ejecutar la instrucción FLASHBACK TABLE si se ha realizado una modificación


de la estructura en la tabla.

Esta instrucción permite anular el borrado de una tabla efectuado con la instrucción DROP TABLE.

Sintaxis

FLASHBACK TABLE nombreTabla TO BEFORE DROP;

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:

SQL> drop table linped;

Table dropped.

SQL> desc linped


ERROR:
ORA-04043: object linped does not exist

SQL> flashback table linped to before drop;

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

CREATE TABLE nombretabla (...) ENABLE ROW MOVEMENT;


ALTER TABLE nombretabla ENABLE ROW MOVEMENT;
FLASHBACK TABLE nombretabla TO_TIMESTAMP fechaHora;

Ejemplo

Activar el soporte para el movimiento de filas en la tabla de clientes:

SQL> alter table clientes


2 enable row movement;

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.

SQL> delete from clientes where nomcli like ’E%’;

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.

SQL> select count(*) from clientes;


COUNT(*)
----------------
5

SQL> flashback table clientes


2 to timestamp
3 to_timestamp(’28/07/2004 19:06:00’,’DD/MM/YYYY HH24:MI:SS’);

flashback complete.

SQL> select count(*) from clientes;

COUNT(*)
---------------
7

SQL>

Generalmente existe a nivel de la base de datos la instrucción FLASHBACK DATABASE.

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.

El establecimiento de restricciones de clave primaria y de unicidad lleva aparejada la creación


implícita de un índice.
a. Creación de un índice

Sintaxis

CREATE INDEX nombre ON tabla (columna [DESC] [, ...]);

Ejemplos

Creación de un índice sobre la clave externa REFART de la tabla LINEASPED:

SQL>create index FK_LINART on LINEASPED(REFART);

Índice creado.

Creación de un índice sobre la tabla CLIVARIOS utilizando las columnas NOMCLIENTE y


DIRECCION (criterio de búsqueda) concatenadas.

SQL>create index IK_CLID on CLIVARIOS (NOMCLIENTE, DIRECCION);

Índice creado.

b. Eliminación de un índice

Sintaxis

DROP INDEX nombre;

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)

Cadena de caracteres de longitud fija de n bytes, que se completa añadiendo espacios a la


derecha (n <= 2000).
VARCHAR2 (n)

Cadena de caracteres de longitud variable, de n bytes como máximo (n <= 4000 si el


argumento MAX_STRING_SIZE es igual a STANDARD; n <= 32767 si el argumento
MAX_STRING_SIZE es igual a EXTENDED).

NCHAR (n)

Cadena de caracteres de longitud fija de n bytes, que se completan añadiendo espacios a la


derecha (n <= 2000). Los caracteres se codifican de acuerdo con el juego de caracteres
nacional activo.

NVARCHAR2 (n)

Cadena de caracteres de longitud variable, de n bytes como máximo (n <= 4000 si el


argumento MAX_STRING_SIZE es igual a STANDARD; n <= 32767 si el argumento
MAX_STRING_SIZE es igual a EXTENDED). Los caracteres se codifican de acuerdo con el juego
de caracteres nacional activo.

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

Fecha comprendida entre el 1 de enero de 4712 a.C. y el 31 de diciembre de 9999 d.C.

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.

TIMESTAMP(p) WITH TIME ZONE

Datos de tipo TIMESTAMP con desplazamiento de zona horaria.

TIMESTAMP(p) WITH LOCAL TIME ZONE

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).

Los siguientes tipos de datos aseguran la compatibilidad con las versiones


anteriores

LONG

Cadena de caracteres de longitud variable (2 GB como máximo).

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.

LONG RAW (n)

Datos binarios de longitud variable (4 GB como máximo); cuyo contenido no es interpretado


por Oracle.

Tipos de datos extendidos (Extended Data Types)

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.

Es posible definir hasta 1000 columnas por tabla.

Sintaxis

CREATE TABLE nombre (nombrecolumna type [DEFAULT expr]


[[CONSTRAINT nombre restricción-de-columna...],...
[,CONSTRAINT nombre restricción-de-tabla...]);

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.

REFERENCES tabla [(columna)] [ON DELETE {CASCADE|SET NULL]


Restricción de integridad referencial para el atributo en la tabla de detalle que se está
definiendo. Los valores tomados por este atributo deben existir en una columna que tenga
asociada una restricción PRIMARY KEY o UNIQUE en la tabla maestra.

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.

b. Restricciones de tabla (sobre varias columnas)

PRIMARY KEY (columna,...)

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,...)

Designa la concatenación de los atributos especificados como clave secundaria de la tabla. En


el caso de que esta restricción UNIQUE se aplique sobre una serie de columnas concatenadas,
al menos una de las columnas que formen parte de esta clave secundaria debe permitir
distinguir la fila de manera unívoca. Esta restricción puede aparecer varias veces en la
instrucción.

FOREIGN KEY (columna,...) REFERENCES tabla [(columna,...)] [ON DELETE {CASCADE


| SET NULL}]

Restricción de integridad referencial para el conjunto de atributos especificados de la tabla de


detalle que se está definiendo. Los valores que toman estos atributos deben existir en una
columna que tenga asociada una restricción PRIMARY KEY o UNIQUE en la tabla maestra.

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 la eliminación de las filas dependientes contenidas en la tabla que se está


definiendo, si se elimina la fila que contiene la clave primaria correspondiente en la tabla
maestra. Si esta opción no se especifica, será imposible eliminar en la tabla maestra las filas
que hacen referencia a este valor de clave primaria.

ON DELETE SET NULL

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

Realiza o no (NOT) la verificación de la restricción en el momento de validar la transacción.

d. Denominación de las restricciones

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

Tabla Nombre de la tabla sobre la que se define la restricción.

Columna Nombre de la columna o columnas sobre las que se define la


restricción.

TipoDeRestriccion: mnemónico asociado con el tipo de restricción:


PK Clave primaria
UQ Unique
NN Not Null
CK Check
RF Referencias
FK Clave primaria

Ejemplos

Creación de una tabla ARTICULOS con una sola restricción de clave primaria REFART:

SQL> create table ARTICULOS(


2 REFART char(4) primary key,
3 DESCRIPCION varchar2(30),
4 PRECIO number(8,2),
5 CODIVA number(1),
6 CATEGORIA char(10),
7 CANTALM number(5)
8 );

Tabla creada.

SQL>

En este caso, DESCRIPCION, PRECIO y CANTALM pueden ser NULL: PRECIO y CANTALM pueden
tomar valores negativos.

Creación de una tabla CLIENTES con restricciones sobre las columnas:

SQL> create table CLIENTES(


2 NUMCLI number(4)
3 constraint CLIENTES_PK primary key
4 constraint CLIENTES_NUMCLI_CK check (NUMCLI>0),
5 NOMCLI varchar2(30)
6 constraint CLIENTES_NOMCLI_NN not null,
7 DIRECCLI varchar2(60),
8 COD_POSTAL number(5)
9 constraint CLIENTES_COD_POSTAL_CK
10 check(COD_POSTAL between 1000 and 99999),
11 CIUDAD char(30)
12 );

Tabla creada.

SQL>

NUMCLI y NOMCLI son obligatorios;

NUMCLI debe ser siempre positivo;

COD_POSTAL debe pertenecer al intervalo especificado.


Creación de la tabla de pedidos utilizando una sintaxis de tipo restricción de tabla para definir
las restricciones de integridad.

SQL> create table PEDIDOS(


2 NUMPED number(6),
3 NUMCLI number(4),
4 FECHAPED date,
5 ESTADOPED char(2),
6 constraint PK_PEDIDOS primary key (NUMPED),
7 constraint FK_PEDIDOS_CLIENTES foreign key(NUMCLI)
8 references CLIENTES(NUMCLI),
9 constraint CK_PEDIDOS_ESTADO check (ESTADOPED in (’EC’,’SU’,’SE’))
10 );

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:

SQL> create table LINPED(


2 NUMPED number(6)
3 constraint FK_LINPED_PEDIDOS
4 references PEDIDOS(NUMPED),
5 NUMLIN number(2)
6 constraint CK_LINPED_NUMLIN check (NUMLIN>0),
7 REFART char(4)
8 constraint FK_LINPED_ARTICULOS
9 references ARTICULOS(REFART),
10 CANTPED number(5),
11 constraint PK_LINPED primary key (NUMPED,NUMLIN)
12 );

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.

La cláusula AS permite especificar la expresión que determina el valor de la columna. Esta


expresión puede hacer referencia a otras columnas reales (no virtuales) de la misma tabla, pero
no puede hacer referencia a ninguna columna de otra tabla.

Las palabras reservadas GENERATED ALWAYS y VIRTUAL son opcionales; pueden especificarse
para hacer la sintaxis más clara.

Puede definirse una restricción de columna sobre una columna virtual.

Ejemplo

SQL> create table ARTICULOS (


2 REFART char(4) primary key,
3 DESCRIPCION varchar2(30),
4 PRECSINIVA number(8,2),
5 IVA number(4,2),
6 PRECCONIVA number(8,2)
7 AS ( PRECSINIVA + round(PRECSINIVA * IVA/100,2))
7 );
Tabla creada.

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

f. Columna de tipo identidad

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

nombrecolumna type GENERATED [ALWAYS | BY DEFAULT [ON NULL]]


AS IDENTITY [(options)][restricción-de-columna]

La clausura ALWAYS fuerza el uso de la identidad; se devuelve un error si un INSERT intenta


asignar un valor (incluso NULL) en la columna o si un UPDATE intenta modificar la columna. Es
el valor por defecto de la cláusula GENERATED AS IDENTITY.

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).

Esta funcionalidad tiene las siguientes restricciones:

 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

SQL> create table CATEGORIAS (


2 NOCAT number(3) generated as identity,
3 NOMBRE varchar2(30)
4 );

Tabla creada.

SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);

1 fila creada.

SQL> insert into CATEGORIAS (NOMBRE)


2 values (’Bricolaje’);

1 fila creada.

SQL> select * from CATEGORIAS;

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.

SQL> create table CATEGORIAS (


2 NOCAT number(3) generated by default as identity,
3 NOMBRE varchar2(30)
4 );

Tabla creada.

SQL>
SQL> insert into CATEGORIAS (NOMBRE)
2 values (’Informática’);

1 fila creada.

SQL> insert into CATEGORIAS (NOMBRE)


2 values (’Bricolaje’);

1 fila creada.

SQL> select * from CATEGORIAS;


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.

SQL> update CATEGORIAS set NOCAT = 456 where NOMBRE = ’Informática’;

1 fila modificada.

SQL> select * from CATEGORIAS;

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.

SQL> create table CATEGORIAS (


2 NOCAT number(3) generated by default on null as identity,
3 NOMBRE varchar2(30)
4 );

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.

SQL> select * from CATEGORIAS;

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

nombrecolumna type [VISIBLE | INVISIBLE] [DEFAULT [ON NULL] expr]


[restricción-de-columna]

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.

SQL> -- Pero la columna se puede especificar explícitamente


SQL> -- en un INSERT (o UPDATE).
SQL> insert into CATEGORIAS (NOCAT,NOMBRE,RESPONSABLE)
2 values (2,’Libros’,’Ángel’);

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

Esta funcionalidad es interesante durante la evolución de la estructura de una tabla. Es posible


añadir una columna invisible a una tabla sin impactar el código existente que funciona como si
la columna no existiera, permitiendo al nuevo código o al existente modificado hacer referencia
explícitamente a las columnas invisibles en las consultas. La columna se puede hacer visible más
adelante, cuando todo el código existente se haya modificado para funcionar correctamente.

3. Eliminación de una tabla

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.

Si se hace referencia a la clave primaria de la tabla en otras tablas mediante restricciones de


tipo REFERENCES o FOREIGN KEY, la cláusula CASCADE CONSTRAINTS permite suprimir estas
restricciones de integridad referencial en las tablas "descendientes".

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

DROP TABLE nombre [CASCADE CONSTRAINTS] [PURGE];

Ejemplo

Eliminación de la tabla CLIENTES cuya columna NUMCLI es una clave externa en la tabla
PEDIDOS:

SQL>drop table CLIENTES;


drop table CLIENTES
*
ERROR en línea 1:
ORA-02449: claves únicas/primarias en la tabla referidas por claves ajenas

SQL>drop table CLIENTES cascade constraints;


Tabla borrada.

Borrado de la tabla de CLIENTES con petición de liberación del espacio físico:

SQL> drop table CLIENTES cascade constraints purge;

Table dropped.

SQL>

4. Modificación de una tabla

Es posible modificar la estructura de una tabla en varios niveles:

 añadiendo columnas (nombre, tipo, valor predeterminado, restricción NOT NULL),


 añadiendo restricciones de columna (únicamente la restricción NOT NULL),
 añadiendo restricciones de tabla,
 definiendo de nuevo una columna (tipo, valor predeterminado y visibilidad),
 activando o desactivando restricciones de columna o de tabla,
 eliminando restricciones de columna o de tabla,
 cambiando el nombre de la tabla,
 autorizando o no las modificaciones en la tabla.
a. Adición o modificación de columnas

Sintaxis

ALTER TABLE nombre {ADD/MODIFY} ([columna tipo [visibilidad] [defecto]


[restricción, ...])

Ejemplo

SQL> describe CLIENTES


Nombre Nulo? Tipo
----------------------------------------- -------- -------------
NUMCLI NOT NULL NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
DIRECCLI VARCHAR2(60)
COD_POSTAL NUMBER(5)
CIUDAD CHAR(30)

SQL> alter table CLIENTES add (TEL char(14));


Tabla modificada.

SQL> alter table CLIENTES modify (DIRECCLI char(30));

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

SQL> alter table ARTICULOS add


2 ( PRECIO_NETO number(8,2) AS ( PRECIO_BRUTO + round(PRECIO_BRUTO *
iva/100,2) ) );

Tabla modificada.

SQL> alter table ARTICULOS modify


2 ( PRECIO_NETO AS ( PRECIO_BRUTO + round(PRECIO_BRUTO * IVA/100,2) ) );

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

SQL> alter table CATEGORIAS modify


2 (NOCAT generated by default on null as identity);

Tabla modificada.

SQL> alter table CATEGORIAS modify (NOCAT drop identity);

Tabla modificada.

b. Adición de una restricción de tabla

Sintaxis

ALTER TABLE nombre_tabla ADD[CONSTRAINT nombre] restricción

La sintaxis de declaración de restricciones es idéntica a la que se utiliza para crear una tabla.

Ejemplo

El siguiente ejemplo permite añadir una restricción de validación a la tabla ARTICULOS:

SQL> alter table ARTICULOS


2 add constraint ARTICULOS_PRECIO_CK check (PRECIO >= 0);

Tabla modificada.

SQL>

Es posible definir una restricción de tipo NOT NULL mediante el comando ALTER TABLE.

Si los datos ya existen en la tabla en el momento en que se añade la restricción de integridad,


entonces todas las filas de información deben verificar la restricción. En caso contrario, no se
aplica la restricción a la tabla.

La cláusula EXCEPTION INTO TABLE nombre_tabla permite conocer el rowid (identificador de


fila de Oracle) de las filas que no cumplen la restricción de integridad que se intenta aplicar o
reactivar. Así, el problema se puede corregir fácilmente.
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.

Creación de la tabla de excepciones:

SQL> create table excepciones(row_id rowid,


2 owner varchar2(30),
3 table_name varchar2(30),
4 constraint varchar2(30));

Tabla creada.

SQL>

Incluye en la tabla de excepciones las referencias de las filas que plantean problemas.

El siguiente fragmento de código intenta añadir una restricción de unicidad (UNIQUE) a la


dirección de los clientes:

SQL> alter table clientes


2 add constraint cli_direccli_un unique(direccli)
3 exceptions into excepciones;
add constraint cli_direccli_un unique(direccli)
*
ERROR en línea 2:
ORA-02299: no se puede validar (SCOTT.CLI_DIRECCLI_UN) - se han
encontrado claves duplicadas

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:

SQL> select numcli, direccli


2 from clientes, excepciones
3 where clientes.rowid=excepciones.row_id
4 and excepciones.table_name=’CLIENTES’
5 and excepciones.constraint=’CLI_DIRECCLI_UN’
6 ;

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.

c. Eliminación de una restricción

Sintaxis

ALTER TABLE nombre_tabla DROP{PRIMARY KEY/UNIQUE (columna)/CONSTRAINT} nombre

Ejemplo

SQL> alter table ARTICULOS


2 drop constraint ARTICULOS_PRECIO_CK;

Tabla modificada.

SQL>

d. Activación y desactivación de una restricción

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

ALTER TABLE nombre_tabla {ENABLE VALIDATE/ENABLE NOVALIDATE/DISABLE}


nombre_restricción

ENABLE VALIDATE

Activa la restricción si el conjunto de filas ya presentes en la tabla la cumplen.


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

En este ejemplo se desactiva la restricción sobre la columna COD_POSTAL de la tabla CLIENTES,


se inserta en dicha tabla un valor incompatible con la restricción desactivada y se intenta habilitar
de nuevo la restricción de comprobación (CHECK), validando los datos presentes en la tabla.

SQL> alter table CLIENTES


2 disable constraint CLIENTES_COD_POSTAL_CK;

Tabla modificada.

SQL> insert into CLIENTES (NUMCLI, NOMCLI, COD_POSTAL, CIUDAD)


2 values (128, ’Martín P.’, 999, ’ORENSE’);
1 fila creada.

SQL> alter table CLIENTES


2 enable validate constraint CLIENTES_COD_POSTAL_CK;
alter table CLIENTES
*

ERROR en línea 2:
ORA-02293: no se puede validar
[CLIENTES_COD_POSTAL_CK] - restricción de control violada

SQL>

e. Modificación de una restricción

No es posible modificar la definición de una restricción. Sin embargo, sí es posible modificar el


estado de una restricción.
Sintaxis

ALTER TABLE nombre_tabla MODIFY CONSTRAINT nombre_restricción


estado_restricción;

Los posibles estados de una restricción son los siguientes:

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

En cada nueva transacción, el funcionamiento predeterminado consiste en verificar la


restricción al completar cada instrucción DML. Esta opción está seleccionada de modo
predeterminado.

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

Modificación de la restricción de referencia entre las tablas LINEASPED y PEDIDOS:

SQL> alter table LINEASPED


2 modify constraint FK_LINEASPED_PEDIDOS DEFERRABLE
3 ;

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;

ALTER TABLE nombre_tabla DROP (nombre_columna, nombre_columna[,...]);

Ejemplo

Eliminación de la columna TEL en la tabla CLIENTES:

SQL> alter table CLIENTES


2 drop column TEL;

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

ALTER TABLE nombre_tabla SET UNUSED (nombre_columna[,...]);


ALTER TABLE nombre_tabla DROP UNUSED COLUMNS [CHECKPOINT num_filas];

Ejemplo

Convertir la columna TEL de la tabla CLIENTES en una columna no utilizable. Para ello, primero
se marca la columna como no utilizable.

SQL> alter table CLIENTES set unused (TEL);

Tabla modificada.
SQL>

A continuación se eliminan todas las columnas marcadas como no utilizables de la tabla


CLIENTES. Después de esta operación se pide al sistema que establezca un punto de
sincronización (CHECKPOINT) cada 200 eliminaciones. Esta precaución evita saturar la caché del
búfer (o buffer) de datos con los datos que se van a eliminar y permite realizar escrituras en
disco más a menudo.

SQL> alter table CLIENTES drop unused columns checkpoint 200;

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> select * from dba_unused_col_tabs;

OWNER TABLE_NAME COUNT


--------------------------- ------------------------------ ----------
SCOTT CLIENTES 1

SQL>

g. Cómo cambiar el nombre de una tabla

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

RENAME nombre_antiguo TO nombre_nuevo;

Ejemplo

Cambiar el nombre de la tabla ARTICULOS por PRODUCTOS:


SQL> rename ARTICULOS to PRODUCTOS;

Tabla cambiada de nombre.

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

ALTER TABLE nombre_tabla { READ ONLY / READ WRITE }

Ejemplo

SQL> alter table ARTICULOS read only;

Tabla modificada.

SQL> delete from ARTICULOS;


delete from ARTICULOS
*
Error en la línea 1:
ORA-12081: operación de actualización no permitida para
la tabla "HELIOS"."ARTICULOS"

SQL> update ARTICULOS set DESCRIPCION = upper(DESCRIPCION);


update ARTICULOS set DESCRIPCION = upper(DESCRIPCION)
*
Error en la línea 1:
ORA-12081: operación de actualización no permitida para
la tabla "HELIOS"."ARTICULOS"

SQL> alter table ARTICULOS read write;

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).

5. Restauración de una tabla

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.

No es posible incluir esta operación en una transacción.

Oracle no puede ejecutar la instrucción FLASHBACK TABLE si se ha realizado una modificación


de la estructura en la tabla.

Esta instrucción permite anular el borrado de una tabla efectuado con la instrucción DROP TABLE.

Sintaxis

FLASHBACK TABLE nombreTabla TO BEFORE DROP;

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:

SQL> drop table linped;

Table dropped.

SQL> desc linped


ERROR:
ORA-04043: object linped does not exist

SQL> flashback table linped to before drop;

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

CREATE TABLE nombretabla (...) ENABLE ROW MOVEMENT;


ALTER TABLE nombretabla ENABLE ROW MOVEMENT;
FLASHBACK TABLE nombretabla TO_TIMESTAMP fechaHora;

Ejemplo

Activar el soporte para el movimiento de filas en la tabla de clientes:

SQL> alter table clientes


2 enable row movement;

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.

SQL> delete from clientes where nomcli like ’E%’;

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.

SQL> select count(*) from clientes;


COUNT(*)
----------------
5

SQL> flashback table clientes


2 to timestamp
3 to_timestamp(’28/07/2004 19:06:00’,’DD/MM/YYYY HH24:MI:SS’);

flashback complete.

SQL> select count(*) from clientes;

COUNT(*)
---------------
7

SQL>

Generalmente existe a nivel de la base de datos la instrucción FLASHBACK DATABASE.

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.

El establecimiento de restricciones de clave primaria y de unicidad lleva aparejada la creación


implícita de un índice.

a. Creación de un índice

Sintaxis

CREATE INDEX nombre ON tabla (columna [DESC] [, ...]);

Ejemplos

Creación de un índice sobre la clave externa REFART de la tabla LINEASPED:

SQL>create index FK_LINART on LINEASPED(REFART);

Índice creado.

Creación de un índice sobre la tabla CLIVARIOS utilizando las columnas NOMCLIENTE y


DIRECCION (criterio de búsqueda) concatenadas.

SQL>create index IK_CLID on CLIVARIOS (NOMCLIENTE, DIRECCION);

Índice creado.

b. Eliminación de un índice

Sintaxis

DROP INDEX nombre;

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.

Manipulación de los datos


Las instrucciones DML permiten añadir, eliminar, modificar y visualizar las filas contenidas en las
tablas existentes.
1. Instrucciones

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

Los términos de las expresiones pueden ser:

 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

Las condiciones emplean expresiones, operadores de comparación y operadores lógicos.

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:

 - "%" para designar una serie de 0 a n caracteres


 - "_" para designar un único carácter.

Operadores lógicos

Una expresión NULL no es ni VERDADERA ni FALSA.

 Negación de una expresión lógica


NOT expresión
 Combinación de expresiones lógicas
expresión1 { AND / OR } expresión2
d. Funciones

Existen dos tipos de funciones:

 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.

Notación de los argumentos de las funciones:

n: expresión numérica.

d: expresión de fecha.

c: expresión de caracteres.

b: expresión lógica.

Funciones escalares matemáticas

ABS (n)

Valor absoluto de n.
CEIL (n)

Primer entero mayor o igual que n.

COS (n)

Coseno.

COSH (n)

Coseno hiperbólico.

EXP (n)

e elevado a la potencia n (e=2,71828183...).

FLOOR (n)

Primer entero menor o igual que n.

LN (n)

Logaritmo neperiano de n.

LOG (m,n)

Logaritmo de n en base m.

MOD (n1,n2)

Resto del cociente de n1/n2.

POWER (n1,n2)

n1 elevado a n2.

ROUND (n1,[n2])

n1 redondeado a n2 posiciones decimales.

SIGN (n)

-1 si n< 0; 0 si n=0; +1 si n>0.

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])

n1 truncado a n2 posiciones decimales.

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.

Funciones escalares para cadenas de caracteres

ASCII (c)

Código ASCII del primer carácter de 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)

Carácter ASCII correspondiente al código n.

COMPOSE (c)

La cadena de caracteres que se pasa como parámetro se convierte a formato UNICODE.

CONCAT (c1, c2)

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]])

Posición de la enésima aparición de c2 en c1 (la primera aparición es la opción


predeterminada) a partir de la posición n1 (1 es el valor predeterminado).

INSTRB (c1,c2,n1[,n2])

Igual que INSTR con n1 y n2 en bytes.

LENGTH (c)

Número de caracteres de c.

LENGTHB (c)

Igual que LENGTH, pero devuelve el número de bytes.

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])

Devuelve c1 suprimiendo por la izquierda c2 (por omisión, ’ ’).

NLS_INITCAP (c,’param’)

Idéntica a INITCAP teniendo en cuenta param (código del país).

NLS_LOWER (c,’param’)

Idéntica a LOWER teniendo en cuenta param (código del país).

NLSSORT (c)

Secuencia de bytes para ordenar la cadena 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])

Devuelve c1 suprimiendo por la derecha c2 (por omisión, ’ ’).

SOUNDEX (c)

Representación fonética de c.

SUBSTR (c,n1[,n2])

Devuelve una cadena formada por n2 caracteres de c a partir de la posición n1.

SUBSTRB (c,n1[,n2])

Idéntica a SUBSTR con n1 y n2 en bytes.

TRANSLATE (c1,c2,c3)

Reemplaza en c1 todas las apariciones de c2 por c3 (c3 no puede ser una cadena de caracteres
nula).

TRIM ({{LEADING |TRAILING|BOTH c1} | {c1}} FROM c2 )

El carácter c1 se suprime de la cadena c2 bien a partir del principio de la cadena (LEADING),


bien del final de la cadena (TRAILING), o de ambas posiciones (BOTH, o ninguna palabra
clave).

UNISTR (c)

La cadena de caracteres que se pasa como parámetro se convierte a formato Unicode.

UPPER(c)

Devuelve c en mayúsculas.

Funciones escalares para fechas

ADD_MONTHS (d,n)
Suma n meses a la fecha d (n puede ser negativo).

CURRENT_DATE

Proporciona la fecha y la hora actuales teniendo en cuenta la configuración de zona horaria


(TIME_ZONE) de la sesión.

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

Permite conocer la zona horaria en vigor en la base de datos.

EXTRACT (formato FROM d)

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.

FROM_TZ (t, zona_horaria)

Convierte un valor de tipo TIMESTAMP en un valor de tipo TIMESTAMP WITH TIME ZONE.

LAST_DAY (d)

Fecha del último día del mes indicado por la fecha 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)

Proporciona la diferencia en meses entre dos fechas.

NEW_TIME (d,z1,z2)

La fecha d de la zona z1 se convierte en la fecha correspondiente en la zona z2.

NEXT_DAY (d,j)

Proporciona la fecha del siguiente día j que es posterior a la fecha d.

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’.

NUMTOYMINTERVAL (n, formato)

Convierte el número n pasado como argumento a formato de mes, año. El formato


especificado por el segundo parámetro permite precisar si el primer parámetro representa
meses (’MONTH’) o años (’YEAR’).

ROUND (d, formato)

Redondea la fecha d a la unidad especificada por formato (Año, Mes, Día, Hora...).

SESSIONTIMEZONE

Permite conocer la zona horaria activa en la sesión actual.

SYSDATE

Fecha del sistema.

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.

TRUNC (d, formato)

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.

- / ’ . Elementos de separación presentes en el resultado.


;:’texto’

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.

DD Número de día del mes (1 a 31).

DDD Número de día del año (1 a 366).

DY Nombre abreviado del día de la semana.

HH, HH12 Hora del día (1 a 12).

HH24 Hora del día (0 a 23).

IW Número de la semana del año (1 a 53) según la norma ISO.

MI Minutos (0 a 59).

MM Número del mes usando 2 caracteres (1 a 12).

MON Nombre abreviado del mes.

MONTH Nombre del mes.

Q Número de trimestre (1 a 4).

RM Número de mes en números romanos (I a XII).

SS Segundos (0 a 59).

SSSS Número de segundos desde medianoche (0 a 86399).

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.

YYYY Año utilizando 4, 3, 2 o 1 cifras.


YYY
YY
Y
Funciones escalares de conversión

BIN_TO_NUM (expr[, ...])

Convierte un conjunto de números binarios en su equivalente decimal.

CHARTOROWID (char)

Convierte una cadena de caracteres con la forma ’numbloque.numfila.numarch’ en el tipo de


datos ROWID. Esta pseudo-columna representa la dirección física de la fila en la base de datos
Oracle.

CONVERT (char,dest[,source])

Conversión del juego de caracteres.

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)

Convierte un valor hexadecimal contenido en una cadena de caracteres en una expresión


binaria de tipo RAW.

RAWTOHEX (raw), RAWTONHEX (raw)

Es la función inversa de la anterior.

ROWIDTOCHAR (rowid), ROWIDTONCHAR (rowid)

Función inversa de CHARTOROWID.

TO_CHAR (carácter)

Convierte una cadena de caracteres al formato NCHAR, NVARCHAR2, CLOB o NCLOB de la


tabla de caracteres utilizada en la base de datos.

TO_CHAR (n,[formato[,’param’]])

Convierte datos numéricos en caracteres.

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).

param: opciones nacionales.

TO_CHAR (d, formato)

Convierte una fecha en una cadena de caracteres.

TO_CLOB (cadena)

Convierte una cadena de caracteres o de tipo LOB al formato CLOB.

TO_DATE (char, formato)

Es la función inversa de TO_CHAR (conversión de cadenas de caracteres en fecha).

TO_DSINTERVAL (cadena)
Convierte una cadena de caracteres en datos de tipo INTERVAL TO DAY SECOND (intervalo
día/segundo).

TO_NCHAR (c)

Convierte una cadena de caracteres en el juego de caracteres nacional (segundo juego de


caracteres de la base de datos).

TO_NCHAR (d,formato)

Convierte una fecha en cadena en el juego de caracteres nacional.

TO_NCHAR (n)

Convierte un número en una cadena en el juego de caracteres nacional.

TO_NCLOB (c)

Convierte una cadena de caracteres en elementos de tipo NCLOB.

TO_NUMBER (char)

Convierte una cadena de caracteres en un tipo de dato numérico.

TO_TIMESTAMP (c[,formato])

Convierte una cadena de caracteres en un elemento de tipo TIMESTAMP basándose en el


formato de fecha indicado por el segundo parámetro.

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).

Ejemplo de uso de las funciones de conversión

En el siguiente ejemplo, la función SYSDATE permite conocer la fecha y hora actuales y, a


continuación, estos datos se muestran adecuadamente en pantalla con ayuda de la función de
conversión TO_CHAR. Para convertir la fecha en una cadena de caracteres se emplea un formato
de conversión cuyos argumentos se proporcionan en la tabla anterior.

SQL> select to_char(sysdate,’DAY DD MONTH YYYY HH24:MI:SS’) from dual;

TO_CHAR(SYSDATE,’DAYDDMONTHYYYYHH24:M
-------------------------------------
JUEVES 19 DICIEMBRE 2002 14:27:14

SQL>

Funciones de comparación

NULLIF (expr1, expr2)

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.

Funciones escalares diversas

BITAND (arg1, arg2)

Efectúa una operación AND entre los dos argumentos, bit a bit.

COALESCE (expr,[,...])

Devuelve la primera expresión no nula que se pasa como parámetro.

DECODE (columna, valor1, resul1 [,valor2, resul2...],[predeterminado])

Si columna tiene el valor especificado por valor1, el resultado será resul1.

DUMP (exp[,formato[,inicial[longitud]]])

Los posibles formatos son:

8 (el resultado se expresa en octal),

10 (el resultado se expresa en decimal),

16 (el resultado se expresa en hexadecimal),

17 (el resultado se expresa en forma de caracteres).

Los argumentos inicial y longitud permiten especificar la parte de la cadena que hay que tratar.

GREATEST (exp[,exp...])

Devuelve la expresión más grande.

LEAST (exp[,exp......])

Devuelve la expresión más pequeña.


NVL (exp1, exp2)

Si exp1 es NULL, devuelve exp2.

NVL2 (exp1, exp2, exp3)

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

Número identificador del usuario.

USER

Nombre del usuario.

USERENV (opción)

Devuelve características del entorno.

opción: CLIENT_INFO ; ENTRYID ; ISDBA ; LANG ; LANGUAGE ; SESSIONID ; SID; TERMINAL.

VSIZE (exp)

Número de bytes almacenados para exp.

WIDTH_BUCKET (expr, min, max, n)

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

INSERT INTO tabla [(columna ,...)] VALUES (expresión ,...);

Ejemplos

Creación de un cliente (las columnas omitidas tienen valor NULL o son iguales a su valor por
defecto):

SQL> insert into CLIENTES (NUMCLI,NOMCLI)


2 values (37, ’Fco. LACALLE’);

1 fila creada.

SQL>

Asignación de valores a todas las columnas de un artículo:

SQL> insert into ARTICULOS


2 values (’AB03’, ’Alfombras’, 150, 2, ’IMPORT’, 80);

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):

SQL> insert into LINPED


2 values (&NumPed, 1, ’AB10’, 2+6);
Introduzca un valor para numped: 1
antiguo 2: values (&NumPed, 1, ’AB10’, 2+6)
nuevo 2: values (1, 1, ’AB10’, 2+6)

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.

SQL> insert into clientes (numcli, nomcli, dircli, cod_postal, pobl)


2 values (601,’Alberto’,’calle Pirineos’,DEFAULT, DEFAULT);

1 row created.
SQL>

La instrucción INSERT permite agregar una o más filas en la tabla de destino.

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.

Este proceso facilita la transferencia de datos de una tabla a otra.

Sintaxis

INSERT INTO tabla[(columna), ...)] SELECT columna, ...


FROM tabla ...;

Ejemplo

Extracción de la lista de clientes que habitan en Barcelona a una nueva tabla:

SQL> create table cli4(


2 numcli number(6));

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

DELETE FROM tabla [WHERE condición];

Ejemplos
Eliminación de un artículo:

SQL> delete from ARTICULOS where REFART = ’ZZZZ’;

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> delete from ARTICULOS


2 where PRECIO >1250 and PRECIO <1750;
delete from ARTICULOS
*
ERROR en línea 1:
ORA-02292: restricción de integridad (SCOTT.FK_LINPED_ARTICULOS)
violada - registro secundario encontrado

SQL>

Eliminación de las filas que hacen referencia a los artículos:

SQL> delete from LINPED;

1 fila suprimida.

SQL>

La siguiente instrucción elimina los artículos que cuestan entre 1250 y 1750 euros (AB10, AB22):

SQL> delete from ARTICULOS


2 where PRECIO between 1250 and 1750;

2 filas suprimidas.

SQL>

La siguiente instrucción elimina los artículos cuya descripción comienza por "Lo" (ZZ01):

SQL> delete from ARTICULOS where DESCRIPCION like ’Lo%’;


1 fila suprimida.

La siguiente instrucción elimina los artículos cuya cantidad en almacén no tiene asignado un
valor:

SQL> delete from ARTICULOS where CANTALM is null;

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

TRUNCATE TABLE tabla

Ejemplo

Eliminación de artículos:

SQL> truncate table ARTICULOS;

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

UPDATE tabla SET columna = expresión, ... [WHERE condición];

Ejemplos

Actualización de la cantidad disponible en almacén del artículo AB10, fijándola en 15:

SQL>update ARTICULOS set CANTALM=15 where REFART=’AB10’;


1 fila actualizada.

Incremento de un 10% del precio de los artículos cuya referencia comienza por AB:

SQL> update ARTICULOS


2 set PRECIO=PRECIO*1.1
3 where REFART like ’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:

SQL>update ARTICULOS set DESCRIPCION=UPPER(DESCRIPCION),


2 REFART=rtrim(REFART);

8 filas actualizadas.

5. Extracción de datos

La instrucción SELECT permite presentar los datos de una tabla, vista o sinónimo.

Sintaxis

SELECT {* | expresión, ...} FROM tabla [WHERE condición];

* especifica que se muestren todas las columnas.

Ejemplo

Visualización de la tabla ARTICULOS completa:

SQL> select * from ARTICULOS;

Tabla inicial:

SQL> select * from ARTICULOS;

REFA DESCRIPCION PRECIO CODIVA CATEGORIA CANTALM


---- ------------------------- --------- -------- ---------- --------
AB03 Alfombras 150 2 IMPORT 116
AB10 Alfombra china 1250,1 2 IMPORT 10
ZZ01 Lote alfombras 500 2 VARIOS 0
AA00 Regalo 0 VARIOS 8
CD50 Cadena HIFI 735,4 2 IMPORT 7
ZZZZ Cantimplora VARIOS 25
AB22 Alfombra persa 1500 2 IMPORT 5
AB Alfombra 2 REBAJ 2
8 filas seleccionadas.
SQL>

Referencias que tienen menos de 20 unidades en almacén:

SQL> select REFART from ARTICULOS where CANTALM < 20;


REFA
----
AB10
ZZ01
AA00
CD50
AB22
AB
6 filas seleccionadas.
SQL>

6. Control de transacciones

Una transacción es un conjunto de instrucciones DML (INSERT, UPDATE, DELETE) que se


ejecutan entre dos comandos CONNECT, COMMIT y ROLLBACK.

La transacción permite asegurar que el conjunto de instrucciones incluidas en ella se ejecutará


en su totalidad o no se ejecutará.

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

Las modificaciones de filas después de la última instrucción COMMIT o CONNECT se convierten


en definitivas.

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

Las modificaciones de filas realizadas después de la última instrucción COMMIT, CONNECT o


SAVEPOINT se anulan.

Si la instrucción ROLLBACK especifica un punto de salvaguarda (SAVEPOINT), la transacción en


curso sigue estando activa después de la ejecución de la instrucción.

Sintaxis

ROLLBACK [TO punto_grabación];

c. Declaración de un punto de control

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.

La transacción en curso seguirá estando activa después de establecer el punto de salvaguarda


(SAVEPOINT).

Sintaxis

SAVEPOINT punto_grabación;

Ejemplo

SQL> savepoint s1;

Punto de grabación creado.

SQL> select numcli, rtrim(nomcli), ciudad from clientes;


NUMCLI RTRIM(NOMCLI) CIUDAD
---------- ------------------------------ -----------------------------
138 Martín Juan MADRID
15 Gómez S.A. ORENSE
20 M. García TOLEDO
128 Martín P. ORENSE
152 LACALLE PONTEVEDRA
100 PLAZA S.A. PONTEVEDRA
35 Martín Juan ORENSE
36 Del Pino S.A. TOLEDO

8 filas seleccionadas.

SQL> delete from clientes where numcli>35;

5 filas suprimidas.

SQL> select numcli, rtrim(nomcli), ciudad from clientes;

NUMCLI RTRIM(NOMCLI) CIUDAD


---------- ------------------------------ -----------------------------
15 Gómez S.A. ORENSE
20 M. García TOLEDO
35 Martín Juan ORENSE

SQL> savepoint s2;

Punto de grabación creado.

SQL> insert into clientes (numcli, nomcli, ciudad)


2 values (111, ’GASCÓN’, ’BARCELONA’);

1 fila creada.

SQL> select numcli, rtrim(nomcli), ciudad from clientes;


NUMCLI RTRIM(NOMCLI) CIUDAD
---------- ------------------------------ -----------------------------
15 Gómez S.A. ORENSE
20 M. García TOLEDO
35 Martín Juan ORENSE
111 GASCÓN BARCELONA

SQL> rollback to s2;

Rollback terminado.

SQL> select numcli, rtrim(nomcli), ciudad from clientes;

NUMCLI RTRIM(NOMCLI) CIUDAD


---------- ------------------------------ -----------------------------
15 Gómez S.A. ORENSE
20 M. García TOLEDO
35 Martín Juan ORENSE

SQL> rollback to s1;

Rollback terminado.

SQL> select numcli, rtrim (nomcli), ciudad from clientes;

NUMCLI RTRIM(NOMCLI) CIUDAD


---------- ------------------------------ -----------------------------
138 Martín Juan MADRID
15 Gómez S.A. ORENSE
20 M. García TOLEDO
128 Martín P. ORENSE
152 LACALLE PONTEVEDRA
100 PLAZA S.A. PONTEVEDRA
35 Martín Juan ORENSE
36 Del Pino S.A. TOLEDO
8 filas seleccionadas.

SQL> commit;

Validación terminada.

SQL>

d. Acceso simultáneo a los datos

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.

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

SQL> insert into PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED)


2 values (2000, 35, SYSDATE, ’EC’);

1 fila creada.

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

SQL>

Sesión 2: en la sesión 1 no se ejecuta una instrucción COMMIT después de la operación de


inserción. La fila insertada no es visible en la sesión 2. Se inserta una fila en la tabla PEDIDOS.

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

SQL> insert into PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED)


2 values (2001, 15, SYSDATE, ’EC’);

1 fila creada.

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
2001 15 23/12/02 EC

SQL>

Sesión 1: COMMIT
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

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

SQL>

Sesión 2: la fila insertada en la primera etapa de la transacción ahora es visible en la sesión 2.

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> 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>

e. Verificación de las restricciones al final de la transacción

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.

La sintaxis exacta de implementación de estos estados de restricción se explica en la sección


Creación de una tabla - Opciones de las restricciones de este capítulo.

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.

Para este ejemplo es necesario agregar, en el transcurso de la misma transacción, un miembro


y su suscripción y luego pedir la verificación de las restricciones de referencia al validar la
transacción.
Creación de tablas con las restricciones de clave primaria:

SQL> create table suscripciones(


2 numero number(5),
3 miembro number(5),
4 constraint pk_suscripciones primary key(numero)
5 );

Table created.

SQL> create table miembros(


2 numero number(5),
3 apellido varchar2(40),
4 nombre varchar2(40),
5 suscripcion number(5),
6 constraint pk_miembros primary key(numero)
7 );

Table created.

SQL>

Implementación de las restricciones de clave externa:

SQL> alter table suscripciones


2 add constraint fk_suscripciones_miembros
3 foreign key(miembro)
4 references miembros(numero)
5 initially deferred;

Table altered;

SQL> alter table miembros


2 add constraint fk_miembros_suscripciones
3 foreign key(suscripcion)
4 references suscripciones(numero)
5 initially deferred;
Table altered.

SQL>

Inserción de datos:

SQL> insert into suscripciones(numero, miembro)


2 values(1,100);

1 row created.

SQL> insert into miembros(numero, apellido, nombre, suscripcion)


2 values(100,’CASAS’,’Antonio’,1);

1 row created.

SQL> commit;

Commit complete.

SQL>

Traducción del álgebra relacional


El método del álgebra relacional permite resolver extracciones de datos creando tablas
intermedias mediante el uso de operadores (unión, restricción, combinación, etc.). Este método
puede traducirse a SQL mediante la instrucción SELECT, que permite llevar a cabo todas las
operaciones mediante sus diferentes cláusulas (WHERE, GROUP BY, UNION, etc.), y mediante
las instrucciones CREATE e INSERT, que permiten la gestión de las tablas intermedias.

1. Operaciones
a. Restricción

La restricción permite extraer solo aquellas filas que cumplan una condición.

La operación s (condición) se traduce de la siguiente manera:

SELECT * FROM S WHERE condición;

Ejemplo
Restricción sobre el número de pedido en la tabla PED = PEDIDOS (NUMPED = 100):

SQL> select * from PEDIDOS where NUMPED=100;

NUMPED NUMCLI FECHAPED ES


---------- ---------- -------- -
100 15 18/11/02 EC

SQL>

b. Campos calculados elementales


Los campos calculados elementales permiten obtener columnas calculadas para cada fila. La
operación S (col, ..., nvcol = exp) se traduce como:

SELECT col, ..., expresión FROM S;

Ejemplo

Cálculo del valor del almacén ARTICULOS(REFART, DESCRIPCION, VALALM = (PRECIOSINIVA


* CANTALM))

SQL> select REFART, DESCRIPCION, (PRECIO * CANTALM) from ARTICULOS;

REFA DESCRIPCION (PRECIO*CANTALM)


---- ------------------------------ ---------------
ZZZZ CANTIMPLORA
ZZ01 LOTE ALFOMBRAS 0
AA00 REGALO 0
CD50 CADENA HIFI 5147,8
AB ALFOMBRA
AB10 Alfombra china 12501
AB03 Alfombras 17400
AB22 ALFOMBRA PERSA 7500

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

Simplificación de la tabla CLI = CLIENTES (NUMCLI, NOMCLI):

SQL> SELECT NUMCLI, NOMCLI from CLIENTES;

Las proyecciones de agrupación se pueden efectuar con la ayuda de dos posibles sintaxis:

SELECT DISTINCT {* | lista de columnas} FROM tabla;

SELECT lista de columnas FROM tabla GROUP BY lista de columnas;

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

Presentación de una fila por cada nombre de cliente:

SQL> select NOMCLI from CLIENTES;

NOMCLI
------------------------------
Martín Juan
Gómez S.A.
M. García
Martín P.
LACALLE
PLAZA S.A.
Martín Juan

7 filas seleccionadas.

SQL> select distinct NOMCLI from CLIENTES;

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>

Agrupación por NOMCLI y CIUDAD:

SQL> select NOMCLI, CIUDAD from CLIENTES group by NOMCLI, CIUDAD;

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 operación S (col, ..., nvcol = cálculo estadístico) se traduce de la siguiente manera:

SELECT lista de columnas, función de grupo FROM S GROUP BY


lista de columnas;

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

Columna de cualquier tipo.

AVG (coln)

Media de los valores de columna.

COUNT ([DISTINCT] (columna)

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 (*)

Para cada agrupación, número de filas agrupadas.

MAX (columna)

Valor máximo de columna para cada agrupación.

MIN (columna)
Valor mínimo de columna para cada agrupación.

STDDEV (coln)

Desviación típica de los valores de columna para cada agrupación.

SUM (coln)

Suma de los valores de columna para cada agrupación.

VARIANCE (coln)

Varianza de los valores de columna para cada agrupación.

CORR (col1, col2)

Coeficiente de correlación entre las dos columnas.

COVAR_POP (col1, col2)

Covarianza de una población.

COVAR_SAMP (col1, col2)

Covarianza de una muestra.

CUME_DIST (col, porcentaje)

Distribución acumulativa.

DENSE_RANK (col)

Número de orden de una fila en un conjunto ordenado de filas.

FIRST (col) LAST (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.

PERCENTILE_CONT (n) WITHIN GROUP (ORDER BY expr [ASC|DESC])

Distribución inversa continua, con n comprendido entre 0 y 1.

PERCENTILE_DISC (n) WITHIN GROUP (ORDER BY expr [ASC|DESC])

Distribución inversa discreta, estando n comprendido entre 0 y 1.

MEDIAN (expr)

Mediana. Equivalente a PERCENTILE_CONT(0.5) WITHIN GROUP(ORDER BY expr).

PERCENT_RANK (expr)

Similar a CUME_DIST.

RANK (expr)

Calcula el rango de un valor dentro de un grupo de valores.

REGR_(expr)

Calcula la regresión lineal.

STDDEV_POP (expr)

Desviación típica de una población.

STDDEV_SAMP (expr)

Desviación típica de una muestra.

VAR_POP (expr)

Varianza de una población.

VAR_SAMP (expr)

Varianza de una muestra.

LISTAGG (expr[,delimitador]) WITHIN GROUP (cláusula de ordenación)

Para cada agrupación, concatena una expresión con un delimitador.


Cuando el cálculo de valores agregados se realiza sobre una columna determinada, los valores
NULL de dicha columna no se tienen en cuenta en los cálculos.

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.

SQL> select rtrim (CIUDAD), count(*) from CLIENTES group by rtrim(CIUDAD);

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):

SQL> select * from articulos;

REFA DESCRIPCIÓN PRECIO CODIVA CATEGORIA CANTALM


---- ------------------------------ ------- ------ ---------- -------
ZZZZ CANTIMPLORA VARIOS 25
ZZ01 LOTE ALFOMBRAS 500 2 VARIOS 0
AA00 REGALO 0 0 VARIOS 8
CD50 CADENA HIFI 735,4 2 IMPORT 7
AB ALFOMBRA 2 REBAJ 2
AB10 Alfombra china 1375,11 2 IMPORT 10
AB03 Alfombras 165 2 IMPORT 116
AB22 ALFOMBRA PERSA 1650 2 IMPORT 5
CD21 Pletina láser 500 2 IMPORT 20
9 filas seleccionadas.

SQL> select substr(refart,1,2), max(precio), avg(cantalm)


2 from articulos
3 group by substr(refart,1,2);

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.

Estas funciones se diferencian de las funciones de agregación en que, en lugar de devolver un


único valor por cada grupo de valores, devuelven varias filas de resultados por cada grupo. Estas
filas de resultados se denominan ventanas (windows). Se define una ventana desplazable por
cada fila analizada. El tamaño de la ventana determina el número de filas que hay que tener en
cuenta para el cálculo de la fila actual.

AVG

Media.

CORR

Coeficiente de correlación.

COVAR_POP

Covarianza de una población.

COVAR_SAMP

Covarianza de una muestra.

COUNT

Contador.
CUME_DIST

Distribución acumulativa.

DENSE_RANK

Calcula el rango de una fila en un grupo ordenado de filas.

FIRST

Permite obtener la primera fila de un conjunto de resultados seleccionado.

LAST

Permite obtener la última fila de un conjunto de resultados seleccionado.

FIRST_VALUE

Proporciona el primer valor de un conjunto de resultados seleccionado.

LAST_VALUE

Proporciona el último valor de un conjunto de resultados seleccionado.

LAG

Permite acceder a más de una fila simultáneamente.

LEAD

Función similar a LAG.

LISTAGG

Concatenación.

MAX

El elemento más grande.

MIN

El elemento más pequeño.

NTH_VALUE

Valor de una expresión en la enésima fila de una ventana.

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

Distribución inversa continua.

PERCENTILE_DISC

Distribución inversa discreta.

RANK

Rango de un valor en el seno de un grupo.

RATIO_TO_REPORT

Calcula la relación entre un valor y la suma de un conjunto de valores.

REGR

Regresión lineal.

ROW_NUMBER

Permite generar un número exclusivo para cada fila.

STDDEV

Desviación típica.

STDDEV_POP

Desviación típica de una población.

STDDEV_SAMP

Desviación típica de una muestra.

SUM

Suma.

VAR_POP

Varianza de una población.


VAR_SAMP

Varianza de una muestra.

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> select refart, precio,


2 FIRST_VALUE(refart)
3 OVER(order by precio asc rows unbounded preceding) as mas_barato
4 from articulos
5 where upper(substr(refart,1,2))=’AB’;

REFA PRECIO MAS_


---- ------------- -----
AB03 165 AB03
AB10 1375,11 AB03
AB22 1650 AB03
AB AB03

SQL>

g. Restricciones sobre valores agregados

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:

SELECT lista de columnas, función de grupo FROM S GROUP


BY lista de columnas HAVING condición;

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:

SQL> select substr(refart,1,2), max(PRECIO), min(PRECIO)


2 from ARTICULOS group by substr(REFART,1,2)
3 having min(PRECIO)>300;

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.

La operación S X T se expresa de la siguiente manera:

SELECT lista de columnas FROM S, T;

Si las columnas tienen el mismo nombre en ambas tablas, el nombre de la columna va precedido
por el nombre de la tabla.

Por tanto, el nombre completo de la columna es:

nombretabla.nombrecolumna.

Ejemplo

Creación y asignación de valores a la tabla DEPOSITOS. Simulación de la asignación de cada


artículo a un depósito:

SQL> create table DEPOSITOS (CODE char(2) primary key, DIRECCION


varchar(60));
Tabla creada.
SQL> insert into DEPOSITOS values (’OR’, ’Paseo de los Olmos 12 32003 ORENSE’);
1 fila creada.
SQL> insert into DEPOSITOS values (’PO’, ’PONTEVEDRA’);
1 fila creada.
SQL> insert into DEPOSITOS values (’MA’, ’MADRID’);
1 fila creada.
SQL> commit;

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:

SELECT lista de columnas FROM S, T WHERE condición;

Ejemplo

Combinación natural entre PEDIDOS y CLIENTES:

SQL> select NUMPED, PEDIDOS.NUMCLI, NOMCLI


2 from CLIENTES, PEDIDOS
3 where CLIENTES.NUMCLI = PEDIDOS.NUMCLI;

NUMPED NUMCLI NOMCLI


---------- ---------- ------------------------------
1210 15 Gómez S.A.
1301 15 Gómez S.A.
1250 35 Martín Juan
1230 35 Martín Juan

SQL>

A partir de la versión 9i, Oracle admite el uso de combinaciones expresadas usando una sintaxis
compatible con el estándar ANSI.

SELECT lista de columnas


FROM tabla [NATURAL] INNER JOIN tabla ON
{condición_combinación|USING (columna)}
WHERE condiciones;

SQL> select numped, pedidos.numcli, nomcli


2 from clientes inner join pedidos on
3 clientes.numcli=pedidos.numcli;

NUMPED NUMCLI NOMCLI


---------- ---------- ------------------------------
100 15 Gómez S.A.
1210 15 Gómez S.A.
1301 15 Gómez S.A.
1250 35 Martín Juan
1230 35 Martín Juan
SQL>

La palabra clave INNER es opcional.

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> select numped, numcli, nomcli


2 from clientes natural inner join pedidos;

NUMPED NUMCLI NOMCLI


---------- ---------- ------------------------------
100 15 Gómez S.A.
1210 15 Gómez S.A.
1301 15 Gómez S.A.
1250 35 Martín Juan
1230 35 Martín Juan

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:

SQL> select NUMPED, PEDIDOS.NUMCLI, NOMCLI


2 from CLIENTES, PEDIDOS
3 where CLIENTES.NUMCLI=PEDIDOS.NUMCLI (+);

NUMPED NUMCLI NOMCLI


---------- ---------- ------------------------------
1210 15 Gómez S.A.
1301 15 Gómez S.A.
M. García
1250 35 Martín Juan
1230 35 Martín Juan
PLAZA S.A.
Martín Juan
LACALLE

8 filas seleccionadas.
SQL>

La sintaxis ANSI para una unión externa es la siguiente:

SELECT lista de columnas


FROM tabla [NATURAL] {LEFT | RIGHT | FULL} OUTER JOIN tabla ON
{condición_unión |USING (columna)}
WHERE condiciones;

SQL> select NUMPED, PEDIDOS.NUMCLI, NOMCLI


2 from CLIENTES LEFT OUTER JOIN PEDIDOS
3 on CLIENTES.NUMCLI = PEDIDOS.NUMCLI;
NUMPED NUMCLI NOMCLI
---------- ------ ------------------------------
1301 15 Gómez S.A.
M. García
1250 35 Martín Juan
1230 35 Martín Juan
PLAZA S.A.
Martín Juan
LACALLE

7 filas seleccionadas.

SQL>

La palabra clave OUTER es opcional.

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).

k. Unión, intersección, diferencia

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).

Las operaciones S {//-} T se expresan de la siguiente manera:

SELECT lista de columnas FROM S {UNION/UNION ALL/INTERSECT/


MINUS} SELECT lista de columnas FROM T;

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

Agrupación de las filas de CLIENTES y CLIVARIOS:

SQL> select NUMCLI, NOMCLI from CLIENTES


2 UNION
3 select NUMCLI, NOMCLI from CLIVARIOS;

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>

2. Tratamiento del resultado

El resultado de las consultas anteriores puede emplearse para distintas finalidades:

 presentar la información ordenada o no,


 asignar valores a una tabla intermedia,
 crear un archivo externo a la base de datos.
a. Clasificación

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.

El orden de clasificación se puede especificar también indicando en la cláusula ORDER BY el


número de orden correspondiente, dentro de la cláusula SELECT, de la columna que se va utilizar
para realizar la clasificación.

Sintaxis

SELECT ..... ORDER BY exp [Desc][, ...] ;


Ejemplo

Presentación de los artículos clasificados por familia y en orden decreciente de precio:

SQL> select REFART, PRECIO from ARTICULOS


2 ORDER BY substr(REFART,1,2), PRECIO desc;

REFA PRECIO
---- ----------
AA00 0
AB
AB10 1500
AB22 1250,1
AB03 150
CD50 735,4
ZZZZ
ZZ01 500

8 filas seleccionadas.

SQL> select PRECIO, substr(REFART,1,2) from ARTICULOS


2 ORDER BY 2,1 desc;

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.

Se pueden emplear dos métodos:

 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

CREATE TABLE nombre (columna tipo [DEFAULT expr]


[restricción], ...) ;
INSERT INTO nombre [(columna, columna,...)] SELECT ...;

Este método permite seleccionar los tipos de columnas, los valores predeterminados y definir
controles empleando restricciones.

Ejemplo

Creación de una tabla simplificada a partir de la tabla CLIENTES:

SQL> create table CLI (NUMCLI char(4), NOMCLI char(10));

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.

SQL> select * from CLI;

NUMC NOMCLI
---- ----------
138 Martín Jua
SQL> drop table CLI;

Tabla borrada.

SQL>

Segundo método

Sintaxis

CREATE TABLE nombre [(columna, columna, ....)] AS SELECT ...;

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

Guardado de la restricción "Clientes de Orense" en la tabla CLIORENSE:

SQL> create table CLIORENSE as


2 select NUMCLI, NOMCLI from CLIENTES
3 where COD_POSTAL between 32000 and 32999;

Tabla creada.

SQL> select * from CLIORENSE;

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> drop table CLIORENSE;


Tabla borrada.

SQL>

Mediante SQLPLUS

Guardar el resultado de la consulta en un archivo ASCII.

Sintaxis

SPOOL nombre_archivo

Ejemplo

Creación de un archivo secuencial ASCII archivo.lst que contenga los datos de la tabla CLIENTES:

SQL> SET HEADING OFF


SQL> SPOOL archivo
SQL> select * from CLIENTES;
SQL> SPOOL OFF

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

CREATE GLOBAL TEMPORARY TABLE tabla (nombre_columna tipo,...)


[ON COMMIT PRESERVE ROWS];

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.

SQL> insert into tcli


2 select cli.numcli, nomcli
3 from clientes cli, pedidos ped
4 where cli.numcli=ped.numcli;

3 filas creadas.

SQL>

En la misma sesión, se consulta la tabla temporal para conocer su contenido:

SQL> select * from tcli;

NUMCLI NOMCLI
---------- ------------------------------
1 Alberto
1 Alberto
2 Casimiro

SQL>

En otra sesión, se consulta la misma tabla temporal para conocer su contenido:

SQL> select * from tcli;

ninguna fila seleccionada


SQL>

La creación de la misma tabla con la opción ON COMMIT PRESERVE ROWS:

SQL> create global temporary table TCLI(


2 NUMCLI number(4),
3 NOMCLI varchar2(30))
4 ON COMMIT PRESERVE ROWS;

Table created.

SQL> insert into tcli


2 select cli.numcli, numcli
3 from clientes cli, pedidos ped
4 where cli.numcli=ped.numcli;

5 rows created.

SQL> commit;

Commit complete.

SQL> select count(*) from tcli;

COUNT(*)
---------------
5

SQL>

c. Enumeración de todas las posibilidades de un cálculo de valores agregados

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.

ROLLUP permite realizar agrupaciones con niveles crecientes de generalidad.

CUBE permite realizar el cálculo solicitado sobre todas las agrupaciones posibles.
Sintaxis

SELECT lista_columnas, cálculo_agregado FROM tabla GROUP BY


{ROLLUP|CUBE} (lista_columnas)

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> select nomcli, p.numped, sum(cantped*precio) as total


2 from clientes cli, pedidos p, lineasped l, articulos a
3 where p.numcli=cli.numcli and p.numped=l.numped and l.refart=a.refart
4 group by rollup (nomcli, p.numped);

NOMCLI NUMPED TOTAL


------------------------------ ---------- ------------
Alberto 1 3000
Alberto 2 1250,1
Alberto 4250,1
Casimiro 3 300
Casimiro 300
4550,1

SQL>

Utilizando la expresión DECODE, se puede obtener una presentación más cuidad.

SQL> select decode (grouping(nomcli),1,’Total clientes’, nomcli) as NOMBRE,


2 substr(decode(grouping(p.numped),1,’Total pedidos’, p.numped),1,20)
3 as numped, sum(cantped*precio) as total
4 from clientes cli, pedidos p, lineasped l, articulos a
5 where p.numcli=cli.numcli and p.numped=l.numped and l.refart=a.refart
6 group by rollup (nomcli, p.numped);

NOMBRE NUMPED TOTAL


------------------------------ -------------------- ------------
Alberto 1 3000
Alberto 2 1250,1
Alberto Total pedidos 4250,1
Casimiro 3 300
Casimiro Total pedidos 300
Total clientes Total pedidos 4550,1
6 filas seleccionadas.
SQL>

La instrucción CUBE permite explorar todas las combinaciones posibles:

SQL> select decode (grouping(nomcli),1,’Total clientes’, nomcli) as NOMBRE,


2 substr(decode(grouping(p.numped),1,’Total pedidos’, p.numped),1,20)
3 as numped, sum(cantped*precio) as total
4 from clientes cli, pedidos p, lineasped l, articulos a
5 where p.numcli=cli.numcli and p.numped=l.numped and l.refart=a.refart
6 group by cube (nomcli, p.numped);

NOMBRE NUMPED TOTAL


--------------------------- -------------------- ------------
Alberto 1 3000
Alberto 2 1250,1
Alberto Total pedidos 4250,1
Casimiro 3 300
Casimiro Total pedidos 300
Total clientes 1 3000
Total clientes 2 1250,1
Total clientes 3 300
Total clientes Total pedidos 4550,1
9 filas seleccionadas.
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).

El contenido de la tabla EMPLEADOS es el siguiente:

SQL> select * from empleados;

NUMERO NOMBRE EDAD SALARIO


----------- --------------- ------------ --------------
1 María 53 3500
2 Pablo 28 1200
4 Juan 35 2300
7 Lucas 41 1800
5 Ana 25 1100
SQL>

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.

SQL> Create table tinfo as


2 select numero, edad from empleados
3 /

Table created.

SQL>

Finalmente los datos de la tabla de empleados se actualizan:

SQL> merge into empleados e


2 using (select numero, edad from tinfo) t
3 on (t.numero=e.numero)
4 WHEN MATCHED THEN UPDATE SET salario=salario*1.04
5 WHERE (t.edad>40)
6 DELETE WHERE (t.edad>65);

2 rows merged.
SQL>

El nuevo contenido de la tabla de empleados es ahora:

SQL> select * from empleados;

NUMERO NOMBRE EDAD SALARIO


------------ --------------------------- ----------------- ----------
1 María 53 3640
2 Pablo 28 1200
4 Juan 35 2300
7 Lucas 41 1872
5 Ana 25 1100
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

MERGE INTO nombreTabla USING origen


ON (condition)
[WHEN MATCHED THEN UPDATE SET nombreColumna=valor
[WHERE condición] [DELETE WHERE condición] ]
[WHEN NOT MATCHED THEN INSERT (nombreColumna,...)
VALUES (valor, ...) [WHERE condición] ];

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

permite definir la acción de actualización o bien de borrado a efectuar.

WHEN NOT MATCHED

permite definir una inserción a realizar en la tabla de destino.

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.

Los casos en que se emplean las vistas son diversos:

 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:

 instrucciones para operaciones de conjuntos (UNION, INTERSECT, MINUS),


 funciones de grupo,
 cláusulas GROUP BY, CONNECT BY, START WITH.

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

CREATE [OR REPLACE] [FORCE | NO FORCE] VIEW nombre


[(columnas [VISIBLE | INVISIBLE], .....)] AS SELECT .....
[WITH CHECK OPTION | WITH READ ONLY];

OR REPLACE

Si la vista ya existe, permite reemplazar la descripción por la nueva consulta. En la práctica, la


definición de una vista no se puede modificar parcialmente.

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]

Indica si la columna es visible (es el caso por defecto) o invisible. El funcionamiento es el


mismo que para las columnas de las tablas. Esta funcionalidad apareció en la versión 12.

WITH READ ONLY

Prohíbe cualquier inserción, modificación o eliminación de datos a través de la vista.

WITH CHECK OPTION


Durante la inserción o modificación de filas en la vista, verifica que las filas insertadas o
modificadas puedan visualizarse en dicha vista.

Compilación

Sintaxis

ALTER VIEW nombre COMPILE;

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:

SQL> create or replace view V_CLIORENSE as


2 select NUMCLI, NOMCLI, COD_POSTAL, CIUDAD from CLIENTES
3 where COD_POSTAL between 32000 and 32999
4 with check option;
Vista creada.

SQL> select NUMCLI, substr(NOMCLI, 1, 12), COD_POSTAL,


2 substr(CIUDAD,1,12) from V_CLIORENSE;

NUMCLI SUBSTR(NOMCL COD_POSTAL SUBSTR(CIUDAD


---------- ------------ ---------- ------------
15 Gómez S.A. 32225 ORENSE
35 Martín Juan 32001 ORENSE
128 Martín P. 32255 ORENSE

SQL> insert into V_CLIORENSE values


2 (255, ’UMBERTO S.A.’, 27001, ’LUGO’);
insert into V_CLIORENSE values (255, ’UMBERTO S.A.’, 27001, ’LUGO’)
*
ERROR en línea 1:
ORA-01402: violación de la cláusula WHERE en la vista WITH CHECK OPTION
SQL> insert into V_CLIORENSE values (176, ’García e Hijo’, 32005, ’AMOEIRO’);

1 fila creada.

SQL> select NUMCLI, substr(NOMCLI, 1, 12), COD_POSTAL,


2 substr(CIUDAD,1,12) from V_CLIORENSE;

NUMCLI SUBSTR(NOMCL COD_POSTAL SUBSTR(CIUDAD


---------- ------------ ---------- ------------
15 Gómez S.A. 32225 ORENSE
35 Martín Juan 32001 ORENSE
128 Martín P. 32255 ORENSE
176 García e Hijo 32005 AMOEIRO

SQL> select NUMCLI, substr(NOMCLI, 1, 12), COD_POSTAL,


2 substr(CIUDAD,1,12) from CLIENTES;

NUMCLI SUBSTR(NOMCL COD_POSTAL SUBSTR(CIUDAD


---------- ------------ ---------- ------------
15 Gómez S.A. 32225 ORENSE
20 M. García 40040 TOLEDO
35 Martín Juan 32001 ORENSE
36 PLAZA S.A. 27001 LUGO
128 Martín P. 32255 ORENSE
138 Martín Juan 28020 MADRID
152 LACALLE 27001 LUGO
176 García e Hijo 32005 AMOEIRO

8 filas seleccionadas.

SQL>

La vista V_CLIPED salvaguarda la combinación CLIENTES/PEDIDOS. La vista V_CLIPED32


permite aplicar una restricción sobre los clientes de la provincia de Orense (código postal 32).
La vista V_CLIPED se convierte en una vista no válida después de la eliminación de una tabla
referenciada en la cláusula SELECT. La vista V_CLIPED32 queda entonces automáticamente
invalidada.
SQL> create or replace view V_CLIPED (NUMCLIENTE, NOMBRE, PEDIDO,
2 CP) as select CLIENTES.NUMCLI, NOMCLI, NUMPED,
3 COD_POSTAL from CLIENTES, PEDIDOS
4 where CLIENTES.NUMCLI = PEDIDOS.NUMCLI;

Vista creada.

SQL> select * from V_CLIPED order by NUMCLI;

NUMCLIENTE NOMBRE PEDIDO CP


---------- ---------------------------------- ------- -----
15 Gómez S.A. 1210 32225
15 Gómez S.A. 1301 32225
35 Martín Juan 1250 32001
35 Martín Juan 1230 32001

SQL> create or replace view V_CLIPED32 as


2 select * from V_CLIPED
3 where CP between 32000 and 32999;

Vista creada.

SQL> select * from V_CLIPED32 order by NUMCLI;

NUMCLIENTE NOMBRE PEDIDO CP


---------- ---------------------------------- ------- -----
15 Gómez S.A. 1210 32225
15 Gómez S.A. 1301 32225
35 Martín Juan 1250 32001
35 Martín Juan 1230 32001

SQL> drop table PEDIDOS cascade constraints;

Tabla borrada.

SQL> alter view V_CLIPED compile;


Advertencia: Vista modificada con errores de compilación.

SQL> select * from V_CLIPED32 order by NUMCLI;


select * from V_CLIPED32 order by NUMCLI
*
ERROR en línea 1:
ORA-04063: view "SCOTT.V_CLIPED32" tiene errores

SQL>

Inserción en una vista basada en una combinación:

SQL> create or replace view V_PEDCLI (NUMPED, FECHAPED, NUMCLI,


2 NOMCLI) as select NUMPED, FECHAPED, PEDIDOS.NUMCLI,
3 NOMCLI from CLIENTES, PEDIDOS
4 where CLIENTES.NUMCLI=PEDIDOS.NUMCLI;

Vista creada.

SQL> select * from V_PEDCLI order by NUMCLIENTE;

ninguna fila seleccionada

SQL> insert into V_PEDCLI (NUMPED, FECHAPED, NUMCLI)


2 values (1501, SYSDATE, 176);

1 fila creada.

SQL> select * from V_PEDCLI order by NUMCLI;

NUMPED FECHAPED NUMCLIENTE NOMCLI


---------- -------- ---------- --------------
1501 23/12/02 176 García e Hijo

SQL>
Eliminación

Sintaxis

DROP VIEW nombre;

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.

SQL> select nomcli, importe


2 from clientes cli, (select numped, sum(cantped*precio) as importe
3 from lineasped l, articulos a
4 where l.refart=a.refart
5 group by numped) lped,
6 pedidos ped
7 where cli.numcli=ped.numcli
8 and lped.numped=ped.numped;

NOMCLI IMPORTE
------------------------------ ----------
Alberto 3000
Alberto 500
Casimiro 300

SQL>

b. Objetos schema (esquema)

Un esquema es un conjunto de tablas, vistas y privilegios agrupados bajo un mismo nombre (el
del usuario).

El uso explícito de un esquema mediante la instrucción CREATE SCHEMA AUTHORIZATION


permite comprender el concepto de transacción aplicado a las instrucciones DDL para la creación
de tablas y vistas y a la asignación de privilegios mediante GRANT.
Si alguna de las instrucciones DDL especificadas en la instrucción CREATE SCHEMA
AUTHORIZATION no funciona correctamente, el conjunto entero de instrucciones se anula.

El nombre de esquema utilizado en la instrucción es el nombre asociado al usuario (USER) que


ha abierto la sesión actual.

Sintaxis

CREATE SCHEMA AUTHORIZATION nombre


{CREATE {TABLE/VIEW}..../GRANT... }...;

Ejemplo

Instrucción CREATE SCHEMA AUTHORIZATION ejecutada sin errores. Todas las instrucciones
DDL especificadas han sido ejecutadas.

SQL> drop view v_pedcli;

Vista borrada.

SQL> drop table linped;

Tabla borrada.

SQL> drop table pedidos;

Tabla borrada.

SQL> drop table clientes;

Tabla borrada.

SQL> drop table articulos;

Tabla borrada.

SQL> create schema authorization scott


2 create table clientes(
3 numcli number(4)
4 constraint pk_clientes primary key
5 constraint ck_clientes_numcli check (numcli>0),
6 nomcli varchar2(30)
7 constraint nn_clientes_nomcli not null,
8 direccli varchar2(80),
9 cod_postal number(5)
10 constraint ck_clientes_codpostal check(cod_postal between 1000 and 95999),
11 ciudad char(30)
12 )
13 create table articulos(
14 refart char(4) primary key,
15 descripcion varchar2(30),
16 precio number(8,2),
17 codiva number(1),
18 categoria char(10),
19 cantalm number(5)
20 )
21 create table pedidos(
22 numped number(9),
23 numcli number(4),
24 fechaped date,
25 estadoped char(2),
26 constraint pk_pedidos primary key (numped),
27 constraint fk_pedidos_clientes foreign key(numcli) references
clientes(numcli),
28 constraint ck_pedidos_estado check (estadoped in (’EC’,’SU’,’SE’))
29 )
30 create table linped (
31 numped number(6)
32 constraint fk_linped_pedidos references pedidos (numped),
33 numlin number(2)
34 constraint ck_linped_numlin check (numlin>0),
35 refart char(4)
36 constraint fk_linped_articulos references articulos(refart),
37 cantped number(5),
38 constraint pk_linped primary key(numped,numlin)
39 )
40 create view v_pedcli (numped, fechaped, numcli, nomcli) as
41 select numped, fechaped, pedidos.numcli, nomcli
42 from pedidos, clientes
43 where pedidos.numcli=clientes.numcli
44 grant select on articulos to public
45 ;

Esquema creado.

SQL> desc pedidos;


Nombre Nulo? Tipo
----------------------------------------- -------- ---------------------------
-
NUMPED NOT NULL NUMBER(9)
NUMCLI NUMBER(4)
FECHAPED DATE
ESTADOPED CHAR(2)

SQL> desc clientes;


Nombre Nulo? Tipo
----------------------------------------- -------- ---------------------------
-
NUMCLI NOT NULL NUMBER(4)
NOMCLI NOT NULL VARCHAR2(30)
DIRECCLI VARCHAR2(80)
CODPOSTAL NUMBER(5)
CIUDAD CHAR(30)

SQL> desc articulos;


Nombre Nulo? Tipo
----------------------------------------- -------- ---------------------------
-
REFART NOT NULL CHAR(4)
DESCRIPCION VARCHAR2(30)
PRECIO NUMBER(8,2)
CODIVA NUMBER(1)
CATEGORIA CHAR(10)
CANTALM NUMBER(5)
SQL> desc linped;
Nombre Nulo? Tipo
----------------------------------------- -------- ---------------------------
-
NUMPED NOT NULL NUMBER(6)
NUMLIN NOT NULL NUMBER(2)
REFART CHAR(4)
CANTPED NUMBER(5)

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.

SQL> drop table LINPED;

Tabla borrada.

SQL> drop view V_CLIPEDLIN

Vista borrada.

SQL> create schema authorization JUAN


2 create table LINPED(
3 NUMPED number(6)
4 constraint LINPED_NUMPED_RF
5 references PEDIDOS(NUMPED),
6 NUMLIN number(2)
7 constraint LINPED_NUMLIN_CK check(NUMLIN>0),
8 REFART char(4)
9 constraint LINPED_refart_RF
10 references ARTICULOS(REFART),
11 CANTPED number(5),
12 constraint LINPED_PK primary key (NUMPED, NUMLIN))
13 create view V_CLIPEDLIN (NUMCLIENTE, NOMCLI, NUMPED, FECHAPED,
14 NUMLIN, REFART, CANTPED) as
15 select NUMCLIENTE, NOMCLI, LINPED.NUMPED, FECHAPED, NUMLIN,
16 REFART, CANTPED
17 from V_PEDCLI, LINPEDIDOS
18 where V_PEDCLI.NUMPED = LINPEDIDOS.NUMPE;
create schema authorization JUAN
*
ERROR en línea 1:
ORA-02427: fallo al crear la vista

SQL>
SQL> select * from LINPED;
select * from LINPED
*
ERROR en línea 1:
ORA-00942: la tabla o vista no existe

SQL>

c. Objetos Synonym (sinónimo)

Un sinónimo es un nombre alternativo que se asigna a un objeto de tipo TABLE, VIEW,


SEQUENCE, SNAPSHOT, PROCEDURE, FUNCTION o PACKAGE.

Los sinónimos proporcionan una mayor flexibilidad en la gestión de los nombres de objetos:

 poniendo a disposición de los usuarios objetos con el mismo nombre,


 ocultando el nombre del esquema al que pertenece el objeto,
 proporcionando la posibilidad de hacer referencia varias veces a un objeto dentro de una
consulta,
 simplificando la escritura de las consultas.

Creación

Sintaxis

CREATE [PUBLIC] SYNONYM nombre FOR objeto;

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

DROP [PUBLIC] SYNONYM nombre;

Ejemplo

Combinación de la tabla NOMENCLATURA consigo misma para visualizar los artículos


compuestos:

SQL> select * from NOMENCLATURA;

REFART DESCRIPCION COMPONENTE NUM


------ ------------------------------ ------------ ----------
XX55 BICICLETA 0
x133 Ruedas XX55 2
x520 Cuadro XX55 1
x456 Manillar XX55 1
QD24 Lote de alfombras 0
AB03 Alfombrillas QD24 10

6 filas seleccionadas.

SQL> create synonym COMPOSICION for NOMENCLATURA;

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;

REFART DESCRIPCION NUM DESCRIPCION


------ ------------------------------ ---------- ------------
QD24 Lote de alfombras 10 Alfombrillas
XX55 BICICLETA 2 Ruedas
XX55 BICICLETA 1 Cuadro
XX55 BICICLETA 1 Manillar

SQL>

d. Objetos Sequence (secuencia)

La creación de un objeto SEQUENCE pone a disposición del usuario un generador de números.

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.

No obstante, utilizar una secuencia no garantiza la ausencia de "huecos" en la numeración. La


secuencia es un sencillo generador de números y todos los números que facilita son diferentes,
pero, si se solicitan números a una secuencia y no se utilizan a continuación, entonces dichos
números se pierden. La secuencia es, en la práctica, un objeto en sí mismo y puede ser utilizado
por varias tablas.

Cada valor de la secuencia se expresa utilizando un máximo de 28 cifras significativas.

Sintaxis

CREATE SEQUENCE nombre [parámetros];


ALTER SEQUENCE nombre parámetros;
DROP SEQUENCE nombre;

Parámetros

START WITH n

Valor inicial.

INCREMENT BY n

Establece el valor del incremento. Puede ser positivo o negativo.

MINVALUE n/NOMINVALUE

Establece un valor límite mínimo o que no existe dicho valor mínimo.

MAXVALUE n/NOMAXVALUE
Establece un valor límite máximo o que no existe dicho valor máximo.

CYCLE/NOCYCLE

CYCLE fuerza a la secuencia a volver al valor MINVALUE cuando se ha alcanzado MAXVALUE


(secuencia creciente) o al valor MAXVALUE cuando se ha alcanzado el valor MINVALUE
(secuencia decreciente).

CACHE n/NOCACHE

Fuerza la anticipación del proceso de generación de los valores siguientes de la secuencia,


almacenándolos en memoria, con el fin de mejorar los tiempos de respuesta de la secuencia.

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.

Las secuencias se usan mediante pseudo-columnas en las instrucciones de manipulación de


datos.

pseudo-columnas

nomseq.CURRVAL

Proporciona el valor actual de la secuencia. Esta pseudo-columna no tiene asignado ningún


valor cuando se crea la secuencia ni cuando se abre una nueva sesión.

nomseq.NEXTVAL

Incrementa el valor de la secuencia y devuelve el nuevo valor de la misma. Esta pseudo-


columna debe ser la primera a la que se haga referencia después de crear la secuencia o de
abrir una sesión.

Si se hace referencia a la misma secuencia desde varias sesiones, el valor de la pseudo-columna


CURRVAL en una sesión no se modifica mientras que el usuario correspondiente no haga
referencia a la pseudo-columna NEXTVAL; y esto es así incluso aunque otros usuarios hagan
referencia a NEXTVAL en su sesión.

Ejemplo
SQL> create sequence C_NUMCLI start with 1000 maxvalue 9999 nocycle;

Secuencia creada.

SQL> insert INTO CLIENTES (NUMCLI, NOMCLI, CIUDAD)


2 values (C_NUMCLI.nextval, ’GARCÍA y GARCÍA’, ’CADIZ’);

1 fila creada.

SQL> insert INTO CLIENTES (NUMCLI, NOMCLI, CIUDAD)


2 values (C_NUMCLI.nextval, ’GÓMEZ y GÓMEZ’, ’JAEN’);

1 fila creada.

SQL> select NUMCLI, NOMCLI, CIUDAD from CLIENTES order by NUMCLI;


NUMCLI NOMCLI CIUDAD
---------- ------------------------------ -------------------------
15 Gómez S.A. ORENSE
20 M. García TOLEDO
35 Martín Juan ORENSE
36 DEL PINO S.A. TOLEDO
138 Martín Juan MADRID
152 LACALLE CACERES
1000 GARCÍA y GARCÍA CADIZ
1001 GÓMEZ y GÓMEZ JAEN
8 filas seleccionadas.
SQL>

2. Consultas complejas
a. Elementos de la sintaxis

Alias

Nombre alternativo dado a una columna o a una tabla en una consulta.

Los alias de columna permiten:

 Cambiar el nombre de la columna en la presentación o en la tabla resultante.


 Proporcionar un nombre que use caracteres especiales (el espacio, por ejemplo).
Los alias de tabla definidos en las cláusulas FROM de las instrucciones SELECT se corresponden
con sinónimos internos de la consulta. Permiten agilizar la escritura de la instrucción y referirse
a la misma tabla en contextos diferentes dentro de una instrucción DML compleja (con
subconsulta).

Sintaxis

SELECT columna [AS] alias_columna,...


FROM tabla alias_tabla,...

Ejemplos

Presentación de un nombre de columna que contiene espacios:

SQL> select NUMCLI, NOMCLI as "Nombre del cliente" from CLIENTES;


NUMCLI Nombre del cliente
---------- ------------------------------
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>

Utilización de la tabla de origen en una subconsulta. Establece la correspondencia de la cantidad


en almacén de cada artículo con el valor máximo de la cantidad en almacén para la familia de
artículos (dos primeros caracteres de la referencia).

SQL> update articulos a


2 set cantalm=(select max(cantalm) from articulos b
3 where substr(a.refart,1,2)=substr(b.refart,1,2));

9 filas actualizadas.

SQL> select refart, descripcion, precio, cantalm from articulos;


REFA DESCRIPCION PRECIO CANTALM
---- ------------------------------ ---------- ----------
AB22 Alfombra persa 1250,1 116
CD50 Cadena HIFI 735,4 20
ZZZZ Cantimplora 25
AA00 Regalo 0 8
AB03 Alfombra 150 116
CD21 Pletina láser 500 20
AB Alfombra 116
ZZ01 Lote alfombras 500 25
AB10 Alfombra china 1500 116

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

SELECT ...... WHERE [(columna, columna,...)] operador ANY


({SELECT ...../expresión,...});

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:

SQL> select refart, descripcion, precio, cantalm from articulos


2 where precio=ANY(select precio from articulos
3 where refart=’ZZ01’);

REFA DESCRIPCION PRECIO CANTALM


---- ------------------------------ ---------- ----------
CD21 Pletina láser 500 20
ZZ01 Lote alfombras 500 25
SQL>

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

SELECT ...... WHERE [(columna, columna,..)] operador ALL


(SELECT...../expresión,...);

Exists

La condición es verdadera si la subconsulta devuelve al menos una fila.

Sintaxis

SELECT ...... WHERE [(]columna [, columna, ..)] EXISTS


(SELECT ...../expresión,...);

Ejemplo

La lista de clientes sólo se muestra si hay al menos un pedido en la tabla PEDIDOS:

SQL> select NUMCLI, NOMCLI from CLIENTES


2 where exists (select ’x’ from PEDIDOS);

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> delete from PEDIDOS;


4 filas suprimidas.

SQL> select NUMCLI, NOMCLI from CLIENTES


2 where exists (select ’x’ from PEDIDOS);

ninguna fila seleccionada

SQL>

b. Subconsultas

Al escribir una consulta compleja, hay que diferenciar entre la consulta externa y la consulta
interna, es decir, la subconsulta.

Las subconsultas pueden clasificarse en dos categorías: subconsultas anidadas y subconsultas


correlacionadas.

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> select NUMCLI, NOMCLI, CIUDAD from CLIENTES


2 where CIUDAD in (select CIUDAD from CLIENTES
3 where NOMCLI like ’Martín Juan%’);

NUMCLI NOMCLI CIUDAD


---------- ------------------------------ ---------
138 Martín Juan MADRID
15 Gómez S.A. ORENSE
35 Martín Juan ORENSE

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

Lista de los clientes que no tienen pedidos asociados:

SQL> select numcli, nomcli


2 from clientes cl
3 where not exists (select numcli
4 from pedidos pe
5 where cl.numcli=pe.numcli);

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>

Diferencia entre los dos tipos de subconsultas

Al escribir subconsultas, es posible elegir la escritura de subconsultas anidadas, que favorece el


uso de la cláusula IN, o la escritura de subconsultas correlacionadas, que favorece el uso de la
cláusula EXISTS. Para saber cuál es la mejor solución en función de los datos a extraer, hay que
profundizar un poco en el funcionamiento de las cláusulas IN y EXISTS.

En el marco del uso de la cláusula IN (subconsulta anidada) es posible concebir que la


subconsulta se evalúa como una vista en línea y que se hace una unión sobre la tabla de la
consulta principal con los datos procedentes de esta subconsulta.

El ejemplo que presenta la subconsulta anidada se evalúa de la forma siguiente:

Select numcli, nomcli, ciudad


from clientes cli1, (select ciudad from clientes where nomcli
like ’GARCIA%’) cli2
where cli1.ciudad=cli2.ciudad

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.

El ejemplo que ilustra la subconsulta correlacionada es interesante respecto a una subconsulta


anidada si:

 el número de clientes es pequeño en relación a los pedidos;


 la extracción de los diferentes números de cliente a partir de la tabla de pedidos representa
una pesada carga de trabajo.

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> create table empleados(


2 numemp number(5)
3 constraint pk_empleados primary key,
4 nombre char(30),
5 puesto char(15),
6 numjefe number(5));
Tabla creada.

SQL>

La consulta SQL permite conocer la jerarquía de organización de la empresa:

SQL> select substr(lpad(’ ’,2*(level-1))||nombre,1,30) as nombre,


2 numemp, numjefe, puesto
3 from empleados
4 start with puesto=’dg’
5 connect by prior numemp=numjefe;

NOMBRE NUMEMP NUMJEFE PUESTO


------------------------------ ---------- ---------- ------------
Evaristo 5 dg
Barrios 2 5 drh
Alcalá 1 2 contable
Castillo 3 2 secretaria
Hernández 8 2 empleado
Hernández 6 5 experto
Diego 4 6 secretaria
García 7 6 empleado

8 filas seleccionadas.

SQL>

La función SYS_CONNECT_BY_PATH, que solo puede utilizarse en las consultas jerárquicas,


permite conocer la ruta completa desde la raíz del árbol. Esta función solo se puede aplicar a las
columnas de tipo carácter.

El siguiente ejemplo muestra el uso de esta función en una consulta jerárquica.

SQL> select lpad(’ ’,2*(level-1))||SYS_connect_by_path(rtrim(nombre),’/’)


as nombre
2 from empleados
3 start with puesto=’dg’
4 connect by prior numemp=numjefe;
NOMBRE
------------------------------------------------------------------------
Evaristo
/Evaristo/Barrios
/Evaristo/Barrios/Alcalá
/Evaristo/Barrios/Castillo
/Evaristo/Barrios/Hernández
/Evaristo/Hernández
/Evaristo/Hernández/Diego
/Evaristo/Hernández/García

8 filas seleccionadas.

SQL>

La función CONNECT_BY_ROOT permite conocer, a partir de un elemento extraido de una


consulta jerárquica, los datos sobre la cima de la jerarquía. Es necesario anteceder el nombre
de las columnas de las que se quiere esta información con CONNECT_BY_ROOT.

Esta funcionalidad es especialmente interesante cuando se quiere extraer de una forma


jerárquica los datos con una restricción sobre ciertos criterios.

Por ejemplo, si la tabla contiene reglas de ensamblado de piezas, es posible mediante


CONNECT_BY_ROOT conocer los elementos que cuentan con la pieza sobre la que se ha hecho
la restricción.

Ejemplo

El ejemplo siguiente permite conocer fácilmente al superior de cada empleado.

SQL> select substr(lpad(’ ’,2*(level-1))||nombre,1,30) as nombre,


2 numemp, numjefe, puesto, CONNECT_BY_ROOT nombre as BigJefe
3 from empleados
4 start with puesto=’dg’
5 connect by prior numemp=numjefe;

NOMBRE NUMEMP NUMJEFE PUESTO BIGJEFE


--------------------- ------ ------- ------ -------
Ernesto 5 dg Ernesto
Bernardo 2 5 drh Ernesto
Alberto 1 2 contable Ernesto
Coronas 3 2 secretaria Ernesto
Hestor 8 2 empleado Ernesto
Fraguas 6 5 experto Ernesto
Damas 4 6 secretaria Ernesto
García 7 6 empleado Ernesto

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.

SQL> select numemp, nombre, puesto, connect_by_isleaf as dirigente


2 from empleados
3 start with puesto=’dg’
4 connect by numjefe = PRIOR numemp;

NUMEMP NOMBRE PUESTO DIRIGENTE


----------------------------- ------ - ---------
5 Ernesto dg 0
2 Bernardo drh 0
1 Alberto contable 1
3 Coronas secretaria 1
8 Hestor empleado 1
6 Fraguas experto 0
4 Damas secretaria 1
7 García empleado 1

8 rows selected.
SQL>

d. Pivotar los datos

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:

SQL> desc VENTAS;


Nombre NULL ? Tipo
-------------------------------------- --------------- ----------
CODIGOPAIS CHAR(2)
CODIGOPRODUCTO CHAR(4)
AÑO NUMBER(4)
CANTIDAD NUMERO(8)

Podemos consultar esta tabla para generar un informe que permita visualizar las ventas
acumuladas por país y año:

SQL> select AÑO, CODIGOPAIS, sum (CANTIDAD)


2 from VENTAS
3 group by AÑO, CODIGOPAIS
4 order by AÑO, CODIGOPAIS;

AÑO CODIGOPAIS SUM(CANTIDAD)


------- ------------ -------------
2006 FR 1254878
2006 IT 8548778
2006 ES 45785
2007 ES 1254741
2007 FR 4528745
2007 IT 369858
2008 IT 5658747
2008 FR 4587854
2008 ES 1254774

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

SQL> select * from (


2 select AÑO, CODIGOPAIS, CANTIDAD
3 from VENTAS
4 )
5 pivot
6 (
7 sum (CANTIDAD)
8 for CODIGOPAIS in (’FR’, ’ES’, ’IT’)
9 )
10 order by AÑO;

AÑO ’FR’ ’ES’ ’IT’


----- -------------------- ------------ -------------
2006 1254878 45785 8548778
2007 4528745 1254741 369858
2008 4587854 1254774 5658747

Sintaxis simplificada

FROM tabla | subconsulta


PIVOT ( función_agregación(expresión)
FOR columna IN (valor [[AS] alias], ...)
)

La cláusula función_agregación(expresión) permite indicar la fórmula de cálculo de los datos que


se van a visualizar en la tabla cruzada; esta fórmula de cálculo debe utilizar una función de
agregación (SUM, AVG, COUNT, etc.).

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

SQL> select * from (


2 select AÑO, CODIGOPAIS, CANTIDAD
3 from VENTAS
4 )
5 pivot
6 (
7 sum (CANTIDAD)
8 for CODIGOPAIS in (’FR’ AS FRANCIA, ’ES’ AS ESPAÑA, ’IT’ AS ITALIA)

9 )
10 order by AÑO;

AÑO FRANCIA ESPAÑA ITALIA

-------------- ------------ ----------- -------------


2006 1254878 45785 8548778
2007 4528745 1254741 369858
2008 4587854 1254774 5658747

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):

SQL> desc VENTAS;


Nombre NULL ? Tipo
-------------------------------------- --------------- --------
AÑO NUMBER(4)
FRANCIA NUMBER
ESPAÑA NUMBER
ITALIA NUMERO

SQL> select * from VENTAS;

AÑO FRANCIA ESPAÑA ITALIA


-------- ---------------- ----------- -------------
2006 1254878 45785 8548778
2007 4528745 1254741 369858
2008 4587854 1254774 5658747

Para visualizar el resultado en formato de tabla, es necesario modificar la codificación de la


consulta para utilizar la cláusula UNPIVOT.

Ejemplo:

SQL> select * from VENTAS


2 unpivot
3 (
4 CANTIDAD
5 for CODIGOPAIS in (FRANCIA, ESPAÑA, ITALIA)
6 )
7 order by AÑO, CODIGOPAIS;

AÑO CODIGOPAIS SUM(CANTIDAD)


-------- --------------- ----------------------
2006 FR 1254878
2006 IT 8548778
2006 ES 45785
2007 ES 1254741
2007 FR 4528745
2007 IT 369858
2008 IT 5658747
2008 FR 4587854
2008 ES 1254774

9 filas seleccionadas.

Sintaxis simplificada

FROM tabla | subconsulta


UNPIVOT [{INCLUDE / EXCLUDE} NULLS] (
título_columna_celda
FOR título_columna_pivotada IN (columna, ...)
)

título_columna_celda define el título de la columna que va a mostrar los datos,


inicialmente presentes en la celda indicada de la tabla cruzada.
La cláusula FOR permite indicar las columnas de la tabla cruzada de origen que deben convertirse
en valores de una columna, cuyo título se indica en título_columna_pivotada.

La cláusula INCLUDE NULLS permite incluir en el resultado las filas con valores nulos; por
defecto, estas filas no se incluyen.

Ejemplo de utilización de la cláusula INCLUDE NULLS

SQL> select * from VENTAS


2 unpivot include nulls

3 (
4 CANTIDAD
5 for CODIGOPAIS in (FRANCIA, ESPAÑA, ITALIA)
6 )
7 order by AÑO, CODIGOPAIS;

AÑO CODIGOPAIS SUM(CANTIDAD)


-------- -------------- -------------
2006 FR 1254878
2006 IT 8548778
2006 ES 45785
2006 FR
2007 ES 1254741
2007 FR 4528745
2007 IT 369858
2008 IT 5658747
2008 FR 4587854
2008 ES 1254774

10 filas seleccionadas.

e. Limitar el resultado de una consulta

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]

 cláusula_OFFSET: OFFSET n {ROW | ROWS}


 FETCH {FIRST | NEXT} m [PERCENT] {ROW | ROWS} {ONLY
cláusula_FETCH:
| WITH TIES}

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

SQL> -- Creación de una tabla (simplificada) de empleados.


SQL> create table EMPLEADOS (
2 numero number(3) generated as identity,
3 nombre varchar2(30));

Table creada.

SQL> insert into EMPLEADOS(nombre) values (’Ángel’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Valeria’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’David’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Tomás’);


1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Ana’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Felipe’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Raquel’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Pablo’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Juan’);

1 fila creada.

SQL> insert into EMPLEADOS(nombre) values (’Lucas’);

1 fila creada.

SQL> commit;

Validación realizada.

SQL> select * from EMPLEADOS;

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:

SQL> -- Selección de los 5 "primeros" empleados


SQL> -- (clasificación por el número de empleado).
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 <= 5;

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.

ROW SHARE (RS)

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.

ROW EXCLUSIVE (RX)

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.

SHARE ROW EXCLUSIVE (SRX)

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

Sesión 1: La transacción bloquea la tabla PEDIDOS de forma exclusiva.

SQL> lock table PEDIDOS in EXCLUSIVE mode;

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.

SQL> insert into PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED)


2 values (3001, 35, SYSDATE, ’EC’);

Sesión 1: Inserción de una fila y validación de la transacción.

SQL> insert into PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED)


2 values (3001, 35, SYSDATE, ’EC’);

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> insert into PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED)


2 values (3001, 35, SYSDATE, ’EC’);
insert into PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED)
*
ERROR en línea 1:
ORA-00001: restricción única (SCOTT.PEDIDOS_PK) violada

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

COMMENT ON TABLE nombre_tabla_vista IS ’texto’;


COMMENT ON COLUMN nombre_tabla_vista.nombre_columna IS ’texto’;

Ejemplo

Especificación de un comentario sobre la tabla CLIENTES:

SQL> comment on table CLIENTES


2 IS ’Clientes de la empresa’;

Comentario creado.

SQL>

A continuación se especifica un comentario sobre la columna direccli, con el fin de explicar qué
datos contiene dicha columna:

SQL> comment on column CLIENTES.DIRECCLI


2 IS ’Dirección del cliente’;

Comentario creado.
SQL>

Para ver los comentarios, hay que consultar el diccionario:

SQL> select comments


2 from user_tab_comments
3 where table_name=’CLIENTES’;

COMMENTS
--------------------------------------------------------------
Clientes de la empresa

SQL>

Las vistas ALL_COL_COMMENTS y USER_COL_COMMENTS contienen los comentarios definidos


en el nivel de columna.

5. Información sobre los objetos del esquema

El diccionario de datos contiene muchas vistas que proporcionan información detallada sobre los
diferentes elementos presentes en el esquema.

Entre las vistas más utilizadas pueden citarse las siguientes:

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.

SQL> select table_name


2 from user_tables;

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.

El principal interés de establecer el parámetro NLS en el nivel de función es reemplazar la opción


definida en el nivel de sesión.

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.

SQL> select numped


2 FROM pedidos
3 WHERE fechaped>TO_DATE(’25-APR-2001’,’DD-MON-YYYY’,
4 ’NLS_DATE_LANGUAGE=AMERICAN’);

NUMPED
----------
3
8
10
11

SQL>

Lista de los diferentes parámetros NLS disponibles para las funciones SQL:

Funciones SQL Parámetros NLS

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

La instrucción CASE permite especificar una condición de una instrucción condicional


directamente en la consulta SELECT, sin tener que llamar a un bloque de instrucciones
procedimentales.

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

La instrucción ELSE es opcional y, en el caso de que esta condición no se especifique, el valor


devuelto es NULL si no se ha ejecutado ninguna instrucción WHEN ... THEN.

Ejemplo

El siguiente ejemplo permite saber el nombre de la región de los clientes a partir del código
postal:

SQL> select numcli, nomcli, case to_number(substr(cod_postal,1,2))


2 when 32 then ’Galicia’
3 when 28 then ’Madrid’
4 else ’Otro’ END as region
5 from clientes;

NUMCLI NOMCLI REGION


----------- ------------------------------ -------
15 Gómez S.A. Galicia
20 M. García Otro
35 Martín Juan Galicia
36 DEL PINO S.A. Otro
152 LACALLE Madrid
138 Martín Juan Otro
37 E. LACALLE Otro

7 filas seleccionadas.

SQL>

En este otro ejemplo, se realiza la conversión del código postal dentro de la cláusula WHEN:

SQL> select numcli, nomcli, case


2 when to_number(substr(cod_postal,1,2)) in (32,27)
3 then ’Galicia’
4 else ’Otro’ END as region
5 from clientes;

NUMCLI NOMCLI REGION


---------- ------------------------------ -------
15 Gómez S.A. Galicia
20 M. García Otro
35 Martín Juan Galicia
36 DEL PINO S.A. Otro
152 LACALLE Otro
138 Martín Juan Otro
37 E. LACALLE Galicia

7 filas seleccionadas.

SQL>

7. Las expresiones regulares

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.

Aunque los diferentes metacaracteres se presentan a continuación, es preferible trabajar con


algunos ejemplos de expresiones regulares para comprender bien cómo funcionan.

Las anclas

ˆ marca el principio de línea

$ marca el fin de línea

Los cuantificadores

* corresponde a 0 o más caracteres.

? corresponde a 0 o 1 carácter.

+ corresponde a 1 o más caracteres.

{m} corresponde a m caracteres exactamente.

{m,} corresponde al menos a m caracteres.


{m, n} corresponde al menos a m caracteres, pero menos de n caracteres.

Hay que prestar atención a la manipulación de estos metacaracteres porque no poseen


necesariamente el mismo sentido que los utilizados con el operador LIKE.

El carácter . permite señalar la existencia de cualquier carácter en la cadena.

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.

Las clases de caracteres POSIX se enumeran en la siguiente tabla:

[:alpha:] carácter alfabético

[:lower:] carácter alfabético en minúsculas

[:upper:] carácter alfabético en mayúsculas

[:digit:] número

[:alnum:] carácter alfanumérico

[:space:] espacio

[:punct:] signo de puntuación

[:cntrl:] carácter de control no imprimible

[:print:] carácter imprimible

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.

Finalmente, y aquí reside a menudo la dificultad en la escritura de expresiones regulares, ciertos


metacaracteres no tienen el mismo sentido según su ubicación. Es el caso de los 2
metacaracteres ˆ y -.

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...

El carácter - permite simplificar la escritura de rangos de valores citando simplemente el primer


y el último caracteres separados por -. Por ejemplo en la expresión ˆA[n-p][[:lower:]] permite
identificar las cadenas siguientes: Ana, Anillo, Apero...

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.

Por tanto, la expresión ˆA[-nop][[:lower:]] permite identificar Aviso, Amigo, Arbóreo...

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:

SQL> select numcli, nomcli


2 from clientes
3 where regexp_like(nomcli, ’ˆB[[:lower:]]’);

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:

SQL> alter table articulos


2 add constraint ck_refart
3 check(regexp_like(refart, ’ˆ[[:upper:]]{2,}’));

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:

SQL> select regexp_replace(nomcli,’( ){2,}’,’ ’) as nomcli


2 from clientes;

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

En el ejemplo siguiente se quiere conocer la posición de la subcadena S.A. en el nombre de los


clientes:

SQL> select nomcli, regexp_instr(nomcli, ’S.A.$’) as posicion


2 from clientes;

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:

SQL> select nomcli, regexp_substr(nomcli, ’LA.*’)


2 from clientes
3 ;

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:

Contar el número de palabras de una frase:

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.

La principal herramienta para utilizar SQL y PL/SQL es la interfaz de usuario de SQL*Plus.

Este programa permite a los usuarios finales, desarrolladores y administradores llevar a cabo las
siguientes operaciones:

 escribir, editar y ejecutar comandos SQL y bloques PL/SQL.


 dar formato a los resultados de las consultas.
 visualizar las estructuras de las tablas y copiar datos entre bases de datos.
 ejecutar comandos y operaciones de entrada/salida (introducción, presentación y
manipulación de variables).

SQL*Plus también dispone de sus propios comandos de programación. Es importante no


confundir la utilidad SQL*Plus con el lenguaje SQL.

Antes de la version 11, la herramienta SQL*Plus se declinaba de tres maneras diferentes:

 herramienta de línea de comandos (sqlplus.exe) ;


 aplicación gráfica de Windows (sqlplusw.exe) ;
 aplicación Web (iSQL*Plus).

A partir de la versión 11 solo sigue existiendo la versión de línea de comandos.

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.

SQL*Plus permite conectarse automáticamente, pasando como parámetros el nombre de usuario


y la contraseña en la línea de comandos del sistema operativo, o bien solicita dichos datos
después de iniciar la aplicación.
Además, se puede cambiar el nombre de usuario en el transcurso de una sesión, estableciendo
una nueva conexión para el nuevo usuario.

a. Ejecución del programa

En el símbolo del sistema, el programa se ejecuta con la siguiente sintaxis:

Sintaxis

sqlplus[[-S] [nombreusuario[/contraseña][@cadena_de_conexión]]

-S

modo silencioso.

nombreusuario

nombre con el que se desea conectar a la base de datos.

contraseña

contraseña del usuario.

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

Ejecución del programa pasando como parámetros el nombre de usuario (thisUser) y la


contraseña (Segura2012):

$sqlplus thisUser/Segura2012

SQL*Plus: Release 12.1.0.2.0 Production on Vie. 24 Abr. 18:43:21 2015

Copyright (c) 1982, 2014, Oracle. All rights reserved.

Hora de la última conexión: Ven. 25 Abr. 2015 16:26:12 +01:00


Conectado a:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
With the Partitioning, OLAP, Advanced Analytics and Real Application Testing
options

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

SQL*Plus: Release 12.1.0.2.0 Production on Vie. 24 Abr. 18:45:19 2015

Copyright (c) 1982, 2014, Oracle. All rights reserved.

Introduzca el nombre de usuario: thisUser


Introduzca la contraseña:
Hora de la última conexión: Ven. 25 Abr. 2015 16:36:16 +01:00

Conectado a:
............
SQL>

Desde la versión 12, la fecha/hora de la última conexión de los usuarios se guarda en el


diccionario de datos (columna LAST_LOGIN de la vista DBA_USERS). Esta fecha/hora de última
conexión se muestra automáticamente en la conexión o ejecución de SQL*Plus (consulte los dos
ejemplos anteriores).

b. Conexión después de la ejecución


CONNECT

Sintaxis

CONNECT [nombreusuario[/contraseña]] [@cadena_de_conexión]]

Ejemplo

El usuario actual desea conectarse con el nombre FLORENCIO:

SQL> connect Florencio


Introduzca la contraseña:
Conectado.
SQL>

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.

Conexión a una base de datos remota desde SQL*Plus:

SQL> connect scott/tiger@dbhelios


Conectado.
SQL>

c. Cómo cambiar la contraseña

El usuario puede cambiar su contraseña en el entorno SQL*Plus.

PASSWORD

Sintaxis

PASSWORD [nombreusuario]

Ejemplo

Cambio de la contraseña del usuario actual:

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

Después de desconectarse, el usuario ya no puede emplear comandos SQL o PL/SQL.

DISCONNECT

Sintaxis

DISCONNECT
Ejemplo

Desconexión sin salir de SQL*Plus:

SQL> DISCONNECT
Desconectado de ...
...........
SQL>

e. Cómo salir de SQL*Plus

Salir del programa implica desconectarse de la base de datos.

EXIT

Sintaxis

EXIT [SUCCESS / FAILURE / WARNING /n /variable


/:variable_acoplada][COMMIT / ROLLBACK]

SUCCESS/FAILURE/WARNING/n/variable/:variable_acoplada

Permite comunicar al sistema operativo un código de retorno referido a la ejecución de la


sesión.

COMMIT/ROLLBACK

Valida o anula la transacción en curso al terminar la sesión (COMMIT es el comando


predeterminado).

Ejemplo

Salida de SQL*Plus y vuelta al sistema operativo ($: símbolo de sistema de UNIX):

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:

SQL> insert into CLIENTES (numcli, nomcli) values (10, ’PEPE’);


1 fila creada.
SQL> insert into
2 clientes (numcli, nomcli)
3 values (12, ’TONI’)
4 ;
1 fila creada.
SQL>

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

Declaración del formato de columna:

SQL> column REFART heading "Referencia"


SQL> column DESCRIPCION -
SQL> heading "Descripción"
SQL>

a. Gestión del búfer

La última instrucción SQL se almacena en memoria (búfer).

Este búfer puede reutilizarse en varios casos:

 para ejecutar de nuevo el último comando SQL o el último bloque PL/SQL.


 para visualizar el último comando.
 para modificar el último comando.
 para almacenarlo en un archivo.

La nueva ejecución del búfer se realiza mediante el comando RUN o /.

LIST

Visualización del búfer.

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

L[IST] [n|n m|n|n LAST|*|* n|* LAST|LAST]

n, m número de línea

* línea actual

LAST última línea

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

Introducción de un comando SQL, visualización del búfer y ejecución:

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

Añade una línea al búfer después de la línea actual.

Sintaxis

I[NPUT] [texto]
Ejemplo

Añade una línea al último comando:

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

Añade un texto al final de la línea actual.

Sintaxis

A[PPEND] texto

Ejemplo

Añade texto al final de la línea 2:

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

C[HANGE]/texto antiguo /[texto nuevo]

Si el texto nuevo se omite, se suprime el antiguo.

Ejemplo

Modificación de la primera línea:

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

Elimina una o varias líneas del búfer.

Sintaxis

DEL [n|n m|n|n LAST|*|* n|* LAST|LAST]

n, m número de línea

* línea actual

LAST última línea

Si el comando DEL se ejecuta sin parámetros, se elimina la 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

Eliminación de la última línea del búfer:

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

Guarda el búfer en un archivo.

Sintaxis

S[AVE] nomarchivo [{CREATE/REPLACE/APPEND}]

El archivo creado utiliza de forma automática la extensión .sql si no se especifica ninguna otra
extensión.

CREATE

(opción predeterminada) crea un archivo nuevo.

REPLACE

reemplaza el contenido de un archivo existente.

APPEND

añade el contenido del búfer al final de un archivo existente.

GET

Carga del búfer a partir de un archivo.

Sintaxis

G[ET] nomarchivo [{LIST/NOLIST}]

LIST

(opción predeterminada) lista el contenido del búfer.

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.

Estos archivos de comandos se reconocen por su extensión predeterminada .sql y pueden


contener comentarios.

EDIT

Llamada al editor estándar del sistema operativo.

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).

Edit carga por omisión los archivos empleando la extensión .sql.

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

Durante la ejecución, el texto de los comentarios se ignora.

Los comentarios también pueden indicarse mediante:

-- SQL*Plus ignora el resto de la línea situada detrás de los signos --.

/*... SQL*Plus ignora el texto escrito entre estos dos separadores. El comentario puede ocupar varias
*/ líneas.
START,@,@@

Ejecución de los comandos contenidos en el archivo.

Sintaxis

STA[RT] nomarchivo o @nomarchivo o @@nomarchivo

Por omisión, se utiliza la extensión .sql para el archivo.


El nombre del archivo debe contener la ruta completa de acceso al archivo, si no se encuentra
en el directorio actual.

Por omisión, si solo se especifica el nombre de archivo en el comando START o @, el script se


busca en el directorio de trabajo de SQL*Plus. Ejecutar un script utilizando el comando @@
permite garantizar que se buscará el archivo en el mismo directorio donde se encuentra el script
que solicita la ejecución.

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

COPY {FROM base| TO base| FROM base TO base}


{APPEND|CREATE|INSERT|REPLACE} tabla_de_destino
[(columna, ...)] USING consulta

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

En este argumento se agrupan el nombre del usuario, la contraseña y la cadena de conexión


para acceder a una base de datos remota.

APPEND

Los datos procedentes de la consulta se insertan en la tabla de destino. Si ésta no existe,


entonces se crea antes de insertar los datos.

CREATE

Los datos procedentes de la consulta se insertan en la tabla de destino después de crearla. Si


la tabla de destino ya existía antes de la ejecución del comando COPY, entonces se produce un
error.

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> COPY FROM scott/tiger@DBHELIOS -


> TO SUMINISTRO/@DBHELIOS -
> APPEND dept -
> USING SELECT * FROM DEPT

El tamaño de la matriz de recuperación/enlace es 15. (El tamaño de


la matriz es 15)
Se validará cuando esté listo. (copycommit es 0)
La longitud máxima es 80. (long es 80)
La tabla DEPT se ha creado.

4 filas seleccionadas a partir de SCOTT@DBHELIOS


4 filas insertadas en DEPT.
4 filas validadas en DEPT en SUMINISTRO@DBHELIOS

SQL>

3. Gestión del entorno SQL*Plus

SQL*Plus permite gestionar directamente (sin utilizar el lenguaje SQL) determinadas


funcionalidades de la base de datos, como la visualización de la estructura de objetos o la copia
de datos de una base de datos a otra. También es posible personalizar el uso de SQL*Plus
modificando parámetros que actúan sobre el funcionamiento de los comandos, la presentación
o el resultado de los mismos.

DESCRIBE

Describe la estructura de tablas, vistas, sinónimos o código almacenado.

Sintaxis
DESC[RIBE] objeto

SPOOL

Redirecciona la salida.

Sintaxis

SPO[OL] {nomarchivo [CRE[ATE] | REP[LACE] | APP[END]] | OFF OUT}

nomarchivo

nombre del archivo que recibe los resultados (la extensión predeterminada es .lst).

CRE[ATE]

crea un nuevo archivo. Se produce un error si el archivo ya existe.

REP[LACE]

sustituye el archivo si existe. Si el archivo no existe, se crea. Es la opción por defecto.

APP[END]

añade la salida al final del archivo. Si el archivo no existe, se crea.

OFF

cierra el archivo.

OUT

cierra el archivo y envía la salida a la impresora.

SHOW

Permite la visualización del entorno.

Sintaxis

SHO[W] {ALL/parámetro}

SET

Establece parámetros de entorno.

Sintaxis

SET parámetro valor

El valor predeterminado de los parámetros es el primero de los valores indicados:


AUTOCOMMIT {OFF/ON/IMMEDIATE/n}

Validación automática.

CMDSEP {;/OFF/ON/c}

Separador de comandos formados por varias líneas.

FEEDBACK {6/n/OFF/ON}

Muestra el número de registros seleccionados, si se han seleccionado al menos n registros.

LONG {80/n}

Formato máximo de las columnas de tipo LONG.

NULL {texto}

Representación de los valores NULL.

PAUSE {OFF/ON/texto}

Activación de la pausa al final de la página.

SPACE {1/n}

Número de caracteres que separan las columnas en la presentación.

SQLCASE {MIXED/LOWER/UPPER}

Conversión a mayúsculas o minúsculas de los comandos antes de la ejecución.

SQLCONTINUE {>/texto}

Símbolo de sistema para la enésima línea.

SQLNUMBER {ON/OFF}

Numeración del indicador del sistema para la enésima línea.

SQLPROMPT {SQL/texto}

Símbolo de sistema para la primera línea.

SQLTERMINATOR {;/c/OFF/ON}

Carácter de fin de comando.

ECHO {OFF/ON}
Muestra los comandos de un script durante la ejecución.

TERMOUT {ON/OFF}

Muestra el resultado de los comandos de un script.

HELP

Proporciona acceso al sistema de ayuda (si se ha instalado).

Sintaxis

HELP [comando]

HOST

Proporciona acceso al sistema operativo.

Sintaxis

HOST [comando SO]

En determinados sistemas operativos se puede utilizar un carácter genérico para ejecutar un


comando del sistema desde SQL*Plus. Dado que este carácter depende del sistema, es necesario
consultar la documentación de Oracle relativa a la plataforma de instalación para saber cuál es
dicho carácter.

Presentación de los datos


SQL*Plus ofrece algunas funcionalidades que permiten gestionar variables, introducir valores y
dar formato a los resultados de las consultas.

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

Se pueden gestionar dos tipos de variables:

 las variables de usuario, utilizadas por SQL*Plus o para la sustitución de texto en


comandos SQL y SQL*Plus antes de su ejecución.
 las variables de acoplamiento, empleadas para interactuar con PL/SQL.
DEFINE

Creación de una variable de usuario.

Sintaxis
DEF[INE] [variable = texto]

Sin parámetro, DEFINE permite visualizar las variables existentes.

Las variables creadas mediante este comando son obligatoriamente de tipo carácter.

Determinadas variables tienen nombres y usos reservados:

_EDITOR

Editor invocado por EDIT.

_O_VERSION

Versión de Oracle.

_O_RELEASE

Número de revisión (release) de Oracle.

_CONNECT_IDENTIFIER

Identificador utilizado para la conexión.

_DATE

Fecha actual.

USER

Nombre del usuario actual.

_SQLPLUS_RELEASE

Versión de SQL*Plus.

Como máximo, se pueden definir 1024 variables.

UNDEFINE

Elimina una variable de usuario.

Sintaxis

UNDEF[INE] variable

Ejemplo

Creación de las variables x y _editor, visualización de las mismas y eliminación de la variable x:


SQL> define x = abcdef
SQL> def _EDITOR = vi
SQL> DEF
DEFINE _EDITOR = "vi" (CHAR)
DEFINE X = "abcdef" (CHAR)
SQL> undef x

ACCEPT

Asigna un valor a una variable de usuario.

Si la variable no ha sido definida, la crea.

Sintaxis simplificada

ACCEPT variable [NUM/CHAR] [PROMPT texto] [HIDE]

NUM/CHAR

Caracteres que se pueden emplear en el valor de la variable (solamente cifras o un valor


alfanumérico). CHAR es la opción predeterminada.

PROMPT texto

Muestra el texto especificado antes de introducir el valor de la variable.

HIDE

Indica que el valor que se escriba no se mostrará en pantalla.

Ejemplo

Asignación de valores a las variables V_codigo y V_nombre:

SQL> accept V_NOMBRE


(el usuario introduce un nombre: María)
SQL> accept V_CODIGO NUM prompt "Código:"
Código: ? (introducido por el usuario el n° 15)
SQL> def
DEFINE V_NOMBRE = "María" (CHAR)
DEFINE V_CODIGO = 15 (NUMBER)
SQL>

&nombre
Uso de una variable de sustitución.

Sintaxis

&variable

Si la variable no existe, se solicita que se especifique el correspondiente valor.

Ejemplo

Asignación de variables y uso en un comando SQL:

SQL> accept NUMERO NUMBER prompt "Número de cliente: "


Número de cliente: 15
SQL> accept NOMBRE prompt "Nombre de cliente: "
Nombre de cliente: PEPE
SQL> def tb = clientes
SQL> select * from &tb where
2 Numcli > &Numero and
3 NOMCLI =’&Nombre’;
antiguo 1: select * from &tb where
nuevo 1: select * from clientes where
antiguo 2: Numcli > &Numero and
nuevo 2: Numcli > 15 and
antiguo 3: NOMCLI =’&Nombre’
nuevo 3: NOMCLI =’PEPE’
ninguna fila seleccionada
SQL>

&&nombre

Permite además crear la variable.

Sintaxis

&&variable

Ejemplo

Cuando la consulta se vuelve a ejecutar, el valor de la variable no se solicita de nuevo:

SQL> select * from &&NombreTabla


2 /
Introduzca un valor para el nombre de la tabla: LINPED
antiguo 1: select * from &&NombreTabla
nuevo 1: select * from LINPED

ninguna fila seleccionada

SQL> run
1* select * from &&NombreTabla
antiguo 1: select * from &&NombreTabla
nuevo 1: select * from LINPED

ninguna fila seleccionada

SQL>

VARIABLE

Creación de una variable para utilizarla en un bloque PL/SQL.

Sintaxis

VAR[IABLE] [nombre [NUMBER/CHAR(n)]]

Si no se especifica un parámetro, VARIABLE muestra las características de las variables


existentes.

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.

PRINT

Muestra el contenido de la variable PL/SQL.

Sintaxis

PRINT variable

Ejemplo

SQL> var ncliente number


SQL> variable
variable ncliente
tipo de dato NUMBER
SQL> begin
2 select count(*) into :ncliente
3 from clientes;
4 end;
5 /

Procedimiento PL/SQL terminado correctamente.

SQL> print ncliente

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.

a. Control de la ejecución de scripts


PAUSE

Hace que se suspenda una ejecución.

Sintaxis

PAUSE [texto]

PROMPT

Muestra el texto especificado.

Sintaxis

PROMPT [texto]

b. Cabecera y pie de página

Declaración o anulación de una cabecera: TTITLE.

Declaración o anulación de un pie de página: BTITLE.


BTITLE, TTITLE

Sintaxis

{BTITLE/TTITLE} [opción [texto/variable]]/ [OFF/ON]

Las diferentes opciones son:

COL n

Coloca el texto en la columna n.

SKIP n

Salta n líneas.

TAB n

Salta n columnas.

LEFT/CENTER/RIGHT

Alineación.

BOLD

Texto en negrita.

FORMAT

Formato de presentación, compuesto por:

9 indica una cifra (ejemplo: formato ’9999’ para 4 cifras).

0 muestra los ceros no significativos (ejemplo: ’00999’).

$ es el prefijo del signo $.

B reemplaza los ceros no significativos por espacios.

MI/PR: MI muestra el signo menos (-) después de un valor negativo, PR muestra los valores
negativos entre corchetes.

, inserta una coma.

. coloca el punto decimal (ejemplo: ’999.99’ para 3 enteros y 2 decimales).

V multiplica por 10 el número de decimales.


EEEE especifica una notación científica.

DATE especifica el formato de fecha.

An permite mostrar n caracteres.

Variables predefinidas:

SQL.PNO

Página actual.

SQL.LNO

Línea actual.

SQL.RELEASE

Número de versión de Oracle.

SQL.SQLCODE

Último código de error.

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

Declaración de los atributos de las columnas seleccionadas.

Sintaxis

COLUMN [{columna/expresión} opción]

Las diferentes opciones son:

ALIAS nombre
Nombre alternativo.

LIKE alias

Copia los atributos del alias.

CLEAR

Reinicializa los atributos.

FOLD_AFTER

Inserta un retorno de carro después de la columna.

FOLD_BEFORE

Inserta un retorno de carro antes de la columna.

FORMAT formato

Especifica el formato del valor mostrado.

HEADING texto

Encabezado de la columna.

JUSTIFY{LEFT/CENTER/RIGHT}

Tipo de alineación.

NEWLINE

Igual que FOLD_BEFORE.

NEW_VALUE variable

Introduce el valor de la columna en la variable para mostrarlo en la cabecera de la página.

OLD_VALUE variable

Igual que NEW_VALUE pero para el pie de página.

NULL c

Especifica el texto para los valores nulos.

NOPRINT/PRINT

Muestra o no la columna.
WRAPPED/WORD_WRAPPED/TRUNCATED

Corta las líneas de longitud excesiva.

OFF

Desactivación de la definición.

ON

Habilita de nuevo la definición.

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

COMPUTE función OF {expresión/columna}


ON {expresión/columna/REPORT/ROW}

Las funciones que se pueden emplear son las siguientes:

AVG

Media de los valores no nulos.

COUNT

Recuento de los valores no nulos.

MAXIMUM

Valor máximo.

MINIMUM

Valor mínimo.

NUMBER

Número de líneas.

STD

Desviación típica.
SUM

Suma de los valores.

VARIANCE

Varianza.

f. Anulación de declaraciones
CLEAR

Sintaxis

CLEAR {BREAKS/COLUMNS/COMPUTES/TIMING/BUFFER/SQL/SCREEN}

3. Entorno y tratamiento de errores

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

TIMING [{START texto/SHOW/STOP}]

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.

La declaración WHENEVER permite prevenir estos errores.

WHENEVER

Sintaxis

WHENEVER {OSERROR/SQLERROR} {EXIT[SUCCESS/


FAILURE/ [WARNING/n/variable/:variableRelacionada][COMMIT/ROLLBACK]/
CONTINUE [COMMIT/ROLLBACK/NONE]}

EXIT

Sale de SQL*Plus generando el código de error especificado.

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

No se hace nada antes de abandonar o continuar con la ejecución.

SET ERRORLOGGING

Sintaxis simplificada

SET ERRORL[OGGING] {ON | OFF} [TABLE [schema.]tabla] [TRUNCATE] [IDENTIFIER


identificador]

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

Vacía la tabla cuando se activa el registro de errores.

IDENTIFIER

Cadena de caracteres utilizada para identificar los errores.

c. Parámetros del entorno


SET

Establece parámetros vinculados a la presentación.

Sintaxis

SET parámetro valor

DEFINE {’&’/c/ON/OFF}

Define el carácter empleado para la sustitución de variables.

EMBEDDED {OFF/ON}

Establece que cada informe comience en una página nueva.

HEADSEP {|/c/ON/OFF}

Carácter que define un encabezado de columna de varias líneas.

LINESIZE {80/n}
Número de caracteres por línea.

NEWPAGE {1/n/NONE}

Número de líneas entre el principio de la página y el encabezado definido.

NUMFORMAT {formato}

Formato predeterminado de los tipos numéricos.

NUMWIDTH {10/n}

Tamaño predeterminado de los tipos numéricos.

PAGESIZE {14/n}

Número de líneas entre el encabezado y la parte inferior de la página.

SCAN {ON/OFF}

Controla la presencia de variables de sustitución.

SHOWMODE {ON/OFF}

Muestra los valores de las variables en caso de que cambien.

TAB {OFF/ON}

Uso de tabulaciones.

TIME {OFF/ON}

Muestra la hora antes de cada comando.

TIMING {OFF/ON}

Muestra estadísticas de tiempo.

TRIMOUT {ON/OFF}

Suprime los espacios al final de la línea.

UNDERLINE {-/c/ON/OFF}

Carácter de subrayado.

VERIFY {ON/OFF}

Muestra el comando antes de su ejecución (en caso de sustitución de variable).


WRAP {ON/OFF}

Hace que las líneas se ajusten al ancho de la página.

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:

rem Edición de la confirmación de un pedido


rem Entorno
set echo off
set feed off
set pagesize 60
set newpage 0
set linesize 80

rem Introducción del número de pedido

accept VPED number prompt ’N° de pedido que desea editar: ’

rem Formato de página

set term off

column REFART heading "Referencia|artículo"


column DESCRIPCION heading "Descripción"
column PRECIO heading "Precio"
column CANTPED heading "Cantidad"
column NUMPED noprint new_value VNUMPED
column NOMCLI noprint new_value VNOM

break on NUMPED skip page

compute sum of Importe on NUMPED


ttitle center "Confirmación de pedido" -
skip 2 left "Número : " VNUMPED -
skip 1 left "Cliente : " VNOM skip 3

btitle tab 40 "Página " sql.pno

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

Resultado del script anterior cuando se especifica el número de pedido 1210:

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

4. Creación de un informe en formato HTML

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}]

Las opciones predeterminadas se muestran subrayadas.

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.

Los diferentes parámetros de este comando son:

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
&lt, &gt,&quot y &amp.

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:

rem Ejemplo de generación de un informe en HTML


set echo on
set markup html on spool on entmap on -
head "<TITLE>Los pedidos</TITLE> -
<STYLE type=’text/css’> -
<!-- BODY{background:#FFFFC6} --> -
</style>"-
BODY "TEXT=’#FF00FF’" -
TABLE "BORDER=’2’" -
preformat off
column numped heading ’N°’
column numcli heading ’Cliente’
column fechaped heading ’Fecha’
column estadoped heading ’Estado’ format A6
spool prueba.html
select numped, numcli, fechaped, estadoped from pedidos;
spool off
set markup html off spool off

La ejecución de este script proporciona el siguiente resultado:

SQL> select numped, numcli, fechaped, estadoped from pedidos;

N° Cliente Fecha Estado


---------- ---------- -------- ------
100 15 23/07/02 EC
1301 15 22/07/02 EC
1210 15 20/07/02 SE
1250 35 19/07/02 EC
1230 35 18/07/02 SE

SQL> spool off

SQL Developer

1. Iniciar 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

En esta dirección también encontrará la documentación y los tutoriales.

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).

La ventana principal de Oracle SQL Developer tiene el siguiente aspecto:

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.

En general, esta herramienta se maneja muy fácilmente y su aprendizaje es sencillo. En este


capítulo haremos una presentación rápida de su utilización; para obtener más información puede
consultar la documentación "Oracle® SQL Developer User’s Guide".
2. Crear una nueva conexión
Para crear una nueva conexión puede pulsar el botón o pulsar con el botón secundario del ratón
en la carpeta Conexiones y seleccionar el menú Nueva conexión.

Se abre un cuadro de diálogo, en el que se debe indicar la información siguiente:

Nombre de Nombre de la conexión.


Conexión

Usuario Cuenta que debe utilizarse en la conexión.

Contraseña Contraseña de la cuenta que debe utilizarse en la conexión.

Guardar Si se ha seleccionado esta opción, la contraseña se registra y no se solicitará de


Contraseña nuevo al iniciarse la conexión.

Nombre del Host Nombre del servidor.

SID Nombre de la instancia.

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.

3. Introducir las consultas SQL

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.

A continuación, es posible introducir la consulta deseada en la sección de entrada de texto y


después pulsar el botón o pulsar la tecla [F9] o [Ctrl][Intro]; el resultado se visualiza en la
pestañaResultado de la Consulta, con el formato de una hoja Excel:

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.

La lista desplegable situada en la parte superior derecha permite cambiar de conexión:


También puede abrir un script existente en SQL Developer pulsando el botón , y seleccionando a
continuación el archivo en el cuadro de diálogo que aparece. El script se abre en una nueva sección
de trabajo:

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.

Puede guardar el script modificado pulsando el botón .

Oracle SQL Developer soporta un importante número de comandos SQL*Plus.

4. Actualizar los datos


Puede utilizar la sección de trabajo presentada previamente para introducir y ejecutar las consultas
de actualización (INSERT, UPDATE, DELETE). En este caso, debe utilizar el botón para registrar
definitivamente las modificaciones en la base de datos (COMMIT). En caso necesario, para anular
las modificaciones en curso (ROLLBACK), puede pulsar el botón .

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:

Agregar una nueva fila.

Eliminar la fila actual.

Registrar definitivamente las modificaciones en la base de datos.

Anular las modificaciones.

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:

5. Trabajar con los objetos de un esquema

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.

Ejemplo para una tabla

Para modificar la definición de un objeto, seleccione el objeto en el panel de conexiones, pulse


el botón secundario del ratón y, a continuación, seleccione el menú Editar.... Se abre un cuadro
de diálogo específico del tipo de objeto seleccionado.

Ejemplo para una tabla

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.

Ejemplo para una tabla

6. Exportar los datos

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...:

A continuación, se abre un cuadro de diálogo para indicar principalmente el formato de la


exportación y el nombre del archivo:

Cuando pulsa en el botón Siguiente>, el asistente muestra una pantalla de resumen:

Pulse en el botón Terminar para ejecutar la exportación.


7. Exportar las definiciones

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 primera pantalla del asistente permite definir:

 la conexión que se va a utilizar,


 las diferentes opciones para la exportación del código DDL (definición de los objetos),
 el formato del archivo para la exportación de los datos,
 el nombre del archivo de la 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:

La última pantalla del asistente muestra un resumen:

Pulse el botón Terminar para ejecutar la exportación.

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).

Las ventajas del lenguaje PL/SQL son diversas:

 Integración de SQL: se pueden utilizar las instrucciones DML, las de control de


transacciones y las funciones SQL prácticamente con la misma sintaxis.
 Procesamiento procedimental: la gestión de variables y las estructuras de control
(condiciones y bucles) incrementan las posibilidades de gestión de los datos.
 Funcionalidades suplementarias: la gestión de cursores y el tratamiento de errores ofrecen
nuevas posibilidades de procesamiento.
 Mejora del rendimiento: se pueden agrupar varias instrucciones en una misma unidad
(bloque) que dará lugar a un único "acceso" a la base de datos (en lugar de un acceso por
cada instrucción).
 Integración en los productos de Oracle: los bloques o procedimientos PL/SQL son
compilados y ejecutados por el "motor" de PL/SQL. Este motor está integrado en el motor
de la base de datos, así como en determinadas herramientas de Oracle: Oracle*Forms,
Oracle*Report, Oracle*Graphics.
2. Instrucciones SQL integradas en PL/SQL

Estas instrucciones se usan prácticamente con la misma sintaxis que en SQL.

 Para la realización de consultas: SELECT.


 Para la manipulación de datos: INSERT, UPDATE, DELETE.
 Para la gestión de transacciones: COMMIT, ROLLBACK, SAVEPOINT...
 Las funciones TO_CHAR, TO_DATE, UPPER, SUBSTR, ROUND...
3. Instrucciones específicas de PL/SQL

Las características procedimentales de PL/SQL aportan las siguientes posibilidades:


 gestión de variables (declaración, asignación de valores y uso),
 estructuras de control (secuencias, condiciones, bucles).

Las funcionalidades suplementarias disponibles son las siguientes:

 gestión de cursores (tratamiento del resultado de una consulta fila a fila),


 tratamiento de errores (declaración, acción que hay que llevar a cabo).
4. Bloques PL/SQL

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.

Estructura de un bloque PL/SQL

Un bloque consta de tres secciones.

DECLARE
(declaración de variables, constantes, excepciones y
cursores)

BEGIN
(instrucciones SQL, PL/SQL, estructuras de control)

EXCEPTION
(tratamiento de errores)

END ;

Es posible añadir comentarios a un bloque:

-- permite incluir un comentario que ocupe una sola línea.

/*... ... */ permite incluir un comentario que ocupe varias líneas.

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.

En PL/SQL, permiten almacenar valores procedentes de la base de datos o de cálculos, que se


emplearán para comprobar condiciones, realizar cálculos o asignar valores a otras variables o
datos de la base de datos.

Las variables se caracterizan por:

 su nombre, compuesto por letras, números y los caracteres $, _ o #.


El nombre puede tener hasta un máximo de 30 caracteres y no debe ser una palabra
reservada.
 su tipo, que determina el formato de almacenamiento y de uso de la variable.

Es obligatorio declarar las variables antes de poder usarlas.

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

El valor de la variable no puede modificarse en el código de la sección BEGIN.

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)]

Cadena de caracteres de longitud fija, con n comprendido entre 1 y 32767. Si no se especifica


un tamaño máximo, entonces se usa el valor predeterminado de 1. También hay que tener en
cuenta que la longitud máxima de una columna de tipo CHAR es 2000 y, por tanto, es
imposible insertar un valor de más de 2000 caracteres en una columna de dicho tipo.

VARCHAR2[(n)]

Cadena de caracteres de longitud variable, con n comprendido entre 1 y 32767 y que


representa el número máximo de bytes que pueden asignarse a la variable. Si el argumento
MAX_STRING_SIZE es igual a STANDARD, también hay que tener en cuenta que la longitud
máxima de una columna de tipo VARCHAR2 es de 4000 bytes y, por tanto, es imposible
insertar un valor de más de 4000 caracteres en una columna de dicho tipo. Por el contrario, si
el argumento MAX_STRING_SIZE es igual a EXTENDED, la longitud máxima de una columna de
tipo VARCHAR2 es 32.767 bytes, es decir, la misma longitud que en PL/SQL.

LONG

Cadena de caracteres de longitud variable, con un máximo de 32760 bytes.

RAW[(n)]

Cadena de caracteres o datos binarios de longitud variable, con n comprendido entre 1 y


32767. PL/SQL no gestiona el contenido de una variable de este tipo (PL/SQL no gestiona los
caracteres nacionales).

LONG RAW

Igual que el tipo LONG, pero PL/SQL no interpreta el contenido.

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)]

Cadena de caracteres de longitud fija, con n comprendido entre 1 y 32767.

NVARCHAR2[(n)]

Cadena de caracteres de longitud variable, con n comprendido entre 1 y 32767.


El número de caracteres almacenados depende del número de bytes utilizados para codificar
cada carácter del juego de caracteres seleccionado.

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.

Los valores de tipo ROWID tienen el formato siguiente: OOOOOOFFFBBBBBBRRR y se


descomponen en cuatro partes:

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.

RRR Especifica el número de fila dentro del bloque.

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 de tipo PLS_INTEGER y BINARY_INTEGER necesitan menos espacio de memoria


que las de tipo NUMBER. Las variables de tipo PLS_INTEGER y BINARY_INTEGER permiten
realizar los cálculos más rápidamente que las de tipo NUMBER.

c. Tipos para objetos de gran tamaño

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

Permite almacenar un objeto binario de hasta 128 TB.

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.

d. Otros tipos de datos

BOOLEAN

Almacena los valores lógicos TRUE, FALSE o el valor NULL.

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.

Tipo Oracle Subtipos

NUMBER DEC, DECIMAL, NUMERIC, DOUBLE PRECISION,FLOAT, REAL


INTEGER, INT, SMALLINT

BINARY_INTEGER NATURAL, NATURALN, POSITIVE, POSITIVEN, SIGNTYPE

VARCHAR2 STRING, VARCHAR

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.

El objetivo de los subtipos es simplificar la escritura y facilitar la comprensión del programa,


empleando nombres de tipos de datos conocidos por el programador o utilizados en la empresa.
Por ejemplo, el tipo de datos CHARACTER es un subtipo de CHAR que permite que el lenguaje
PL/SQL respete la norma ANSI.

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

SUBTYPE nombre_subtipo IS tipo;

Ejemplo

Definición y uso de un subtipo: declaración del subtipo fechanacimiento y uso en un bloque


PL/SQL.

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 /

Procedimiento PL/SQL terminado correctamente.

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.

Colecciones de tipo tabla anidada e index by table

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

Declaración de una colección de tipo tabla anidada:

TYPE nombre_tipo IS TABLE OF tipo_elemento [NOT NULL]

Declaración de una colección de tipo índice por tabla:

TYPE nombre_tipo IS TABLE OF tipo_elemento [NOT NULL]


INDEX BY BINARY_INTEGER | VARCHAR2(n) | CHAR [(n)]

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

Colecciones de tipo VARRAY

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

TYPE nombre_tipo IS VARRAY (tamaño_max) OF tipo_elemento [NOT NULL]

nombre_tipo

Representa el nombre de la colección.

tamaño_max

Representa el número máximo de elementos presentes en la colección.

tipo_elemento
Representa el tipo de datos de los elementos que constituyen la colección.

Ejemplo

Declaración y uso de colecciones. En el siguiente ejemplo se define una colección denominada


Calendario.

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

b. Registros

Un registro es un conjunto de valores relacionados entre sí y agrupados bajo un mismo nombre.


Cada valor se almacena en un campo. Por ejemplo, el registro que permite manipular un cliente
estará formado por los campos número, nombre, dirección... Por tanto, los registros
proporcionan un método sencillo de manipular datos que están relacionados entre sí.

Para poder crear un registro, es necesario definir previamente el tipo de registro en la sección
DECLARE del bloque PL/SQL.

Record

Un registro (RECORD) es una agrupación de elementos de tipos diferentes, relacionados de forma


lógica entre sí y designados por un mismo nombre.

Sintaxis

TYPE nombre_tipo IS RECORD


([nombre_campo tipo_campo [[NOT NULL] :=expresion ]
[, ...]);
nombre_variable nombre_tipo;

tipo_campo corresponde a un tipo PL/SQL definido anteriormente.


Los campos de una variable de tipo RECORD pueden ser referenciados mediante el operador "."
:Nombre_variable.nombre_campo

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

Como en la declaración de variables, es posible inicializar los campos en la declaración y


establecer que sean campos obligatorios o no.

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

nombre-de-variable {nombre de tabla | nombre de cursor} %ROWTYPE;

Ejemplo

-- Declaración de una variable que puede recibir una fila


completa de la tabla ARTICULOS
DECLARE
LINART ARTICULOS%ROWTYPE;
-- Cuando se utilice, podrá hacerse referencia simplemente al nombre
SELECT * INTO LINART;
-- o al nombre en combinación con una columna
x := LINART.preciosiniva * 1.1;

6. Variables definidas en un entorno externo a PL/SQL

Estas variables se declaran fuera del bloque y pueden utilizarse dentro del mismo.

Se trata de campos de pantalla (form) creados en Oracle*Forms o de variables definidas en un


lenguaje host mediante los precompiladores o SQL*Plus (en un bloque PL/SQL estas variables
siempre van precedidas por el signo de dos puntos ":").

Ejemplo
Uso de una variable de acoplamiento SQL*Plus (x):

SQL> variable x NUMBER


SQL> define t = CLIENTES
SQL> Begin
2 select COUNT(*) into :x from &t;
3 end;
4 /
antiguo 2: select COUNT(*) into :x from &t;
nuevo 2: select COUNT(*) into :x from CLIENTES;
Procedimiento PL/SQL terminado correctamente.
SQL> print x
X
9
SQL>

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

Existen varias formas de asignar valores a las variables.

:=

Asigna de forma directa 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.

Los operadores de cálculo son los siguientes:

operadores aritméticos + ; - ; * ; / ; ** (potencia)

operador de concatenación ||

Para agrupar los cálculos se pueden emplear paréntesis.

La escritura de constantes sigue las mismas reglas que en SQL.


Ejemplo

Asignación de valores a variables (en la sección BEGIN):

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

SELECT {* | lista de expresiones} INTO lista de variables FROM ...;


FETCH nombre cursor INTO lista de variables;

Ejemplo

Asignación de valores a variables a partir de tablas de la base de datos:

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

Modificación de la tabla CLIENTES a partir de valores de variables:

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

Comprobar la visibilidad de las variables en los siguientes bloques PL/SQL anidados:

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>

8. Variables estructuradas e instrucciones DML

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

El siguiente ejemplo demuestra la implementación de esta posibilidad desde un bloque PL/SQL.


La variable estructurada vcli está compuesta por varios campos. Cada uno de estos campos está
destinado a recibir un valor para una columna de la tabla CLIENTES. Se asignan valores a los
distintos campos de la variable y, a continuación, se utiliza directamente en el comando INSERT.

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’;

-- insertar estos datos en la tabla de clientes


insert into clientes values vcli;
end;
/

También se pueden emplear variables estructuradas en operaciones de actualización con la


instrucción UPDATE. Para ello, la variable estructurada debe contener un campo por cada
columna de la tabla y, de este modo, se actualiza la fila completa en un único paso. El comando
UPDATE utiliza entonces la cláusula SET ROW= variable compuesta.

Ejemplo

-- script para una operación de actualización usando una variable


estructurada
declare
vcli clientes%rowtype;
begin
-- inicialización de la variable vcli
select * into vcli
from clientes
where numcli=100;
-- actualización de los datos
vcli.nomcli:=’Newton’;
-- actualización de los datos en la base de datos
update clientes
set row=vcli
where numcli=100;
end;
/

La cláusula SET ROW no acepta el resultado de una subconsulta.

En ocasiones, es necesario leer de nuevo los datos insertados, eliminados o actualizados. La


operación habitual consiste en utilizar un comando SELECT para conocer el valor de las columnas
después de la actualización. Pero con las variables estructuradas es posible solicitar a las
instrucciones INSERT, UPDATE o DELETE que devuelvan el valor de las columnas que se han
actualizado mediante la cláusula RETURNING. Por supuesto, solo se puede utilizar esta cláusula
si la instrucción DML de SQL se ha aplicado exactamente a una fila de datos.

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.

Las tres posibles estructuras de control son:

 secuencial: las instrucciones se ejecutan una a continuación de otra.

 alternativa: las instrucciones se ejecutan en función de una condición.

 repetitiva: las instrucciones se ejecutan varias veces en función de una condición.


1. Procesamientos condicionales
If

Permite ejecutar instrucciones en función del resultado de una condición.

Sintaxis

IF condición1 THEN procesamiento1;


[ELSIF condición2 THEN procesamiento2;]
[ELSE
procesamiento3;]
[END IF;]

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

PL/SQL permite llevar a cabo operaciones repetitivas mediante la instrucción LOOP.

Utilizada sola, la instrucción LOOP inicia bucles sin fin y sistemáticos.

Sintaxis

[<<ETIQUETA>>]
LOOP
instrucciones;
.......
END LOOP [ETIQUETA];

Salida del bucle mediante el comando:

EXIT [LABEL] [WHEN condición]

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;

La instrucción CONTINUE permite interrumpir la iteración en curso y pasar inmediatamente a la


siguiente; esta instrucción está disponible a partir de la versión 11.

La sintaxis es parecida a la sintaxis de la instrucción EXIT:

CONTINUE [LABEL] [WHEN condición]

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

Insertar solo los clientes con números impares:

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.

Las instrucciones se ejecutan tantas veces como cambia el índice de valor.

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];

El índice se declara de forma implícita.

exp1, exp2 son constantes, expresiones o variables.

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

Creación de 10 clientes con números consecutivos:

FOR n IN 100..110 LOOP


insert into CLIENTES (NUMCLI) values (n);
END LOOP;
COMMIT;

WHILE

La entrada en el bucle tiene lugar si la condición es verdadera.

A continuación, se ejecutan las instrucciones mientras la condición siga siendo verdadera.

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.

Los estados de ejecución del comando se almacenan en el cursor.

Existen dos tipos de cursores:

 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

CURSOR nombre_cursor IS instrucción_select;

b. Apertura

Después de haber declarado el cursor, es preciso "abrirlo" para ejecutar la instrucción SELECT.

La apertura desencadena las siguientes acciones:

 la asignación de memoria del cursor,


 la identificación del resultado,
 la activación de los posibles bloqueos (si SELECT ... FOR UPDATE).

La apertura del cursor se realiza en la sección BEGIN del bloque.

Sintaxis

OPEN nombre_cursor;

c. Tratamiento de las filas

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

FETCH nombre_cursor INTO lista_variables;

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

FOR variable IN cursor LOOP


--instrucciones
END LOOP;

Ejemplo

Definición y recorrido de un CURSOR sobre la tabla CLIENTES. Presentación del último cliente
leído de la tabla:

SQL> variable NUM_CLIENTE number


SQL> variable NOMBRE_CLIENTE char(20)
SQL>
SQL> declare
2 cursor c_cli is select NUMCLI, NOMCLI from CLIENTES;
3 begin
4 for V_CLI in C_CLI LOOP
5 :NUM_CLIENTE := V_CLI.NUMCLI;
6 :NOMBRE_CLIENTE := V_CLI.NOMCLI;
7 end loop ;
8 end;
9 /

Procedimiento PL/SQL terminado correctamente.

SQL> rem último cliente leído en el bucle


SQL> print NUM_CLIENTE

NUM_CLIENTE
-----------
100

SQL> print NOMBRE_CLIENTE

NOMBRE_CLIENTE
---------------
Newton

SQL>

También es posible no declarar el cursor en la sección DECLARE y especificarlo directamente en


la instrucción FOR:

SQL> variable NUM_CLIENTE number


SQL> variable NOMBRE_CLIENTE char(20)

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 /

Procedimiento PL/SQL terminado correctamente.

SQL> rem último cliente leído


SQL> print NUM_CLIENTE

NUM_CLIENTE
-----------
100

SQL> print NOMBRE_CLIENTE

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

Es un atributo de tipo booleano.

Para un cursor implícito, el nombre del atributo es: SQL%FOUND

Es TRUE (verdadero) si:

 la última instrucción INSERT, UPDATE o DELETE ha procesado al menos una fila,


 o si la última instrucción SELECT ... INTO ha devuelto al menos una fila.

Para un cursor explícito, el nombre del atributo es: nombre_cursor%FOUND

Es TRUE si la última instrucción FETCH ha extraído una fila.

%NOTFOUND
Es un atributo de tipo booleano.

Para un cursor implícito, el nombre del atributo es: SQL%NOTFOUND

Es TRUE (verdadero) si:

 la última instrucción INSERT, UPDATE, o DELETE no ha procesado ninguna fila,


 o si la última instrucción SELECT ... INTO no ha extraído ninguna fila (en este caso, primero
se genera una excepción; consulte la sección "Gestión de errores" en este capítulo).

Para un cursor explícito, el nombre del atributo es: nombre_cursor%NOTFOUND

Es TRUE si la última instrucción FETCH no ha extraído ninguna fila.

%ISOPEN

Es un atributo de tipo booleano.

Para un cursor implícito, el nombre del atributo es: SQL%ISOPEN

Siempre toma el valor FALSE, ya que ORACLE vuelve a cerrar los cursores después de utilizarlos.

Para un cursor explícito, el nombre del atributo es: nombre_cursor%ISOPEN

Es TRUE si el cursor está abierto.

%ROWCOUNT

Este atributo es de tipo numérico.

Para un cursor implícito, el nombre del atributo es: SQL%ROWCOUNT

Contiene el número de filas tratadas por la última instrucción INSERT, UPDATE o DELETE.

Es igual a 0 si la última instrucción SELECT...INTO no ha extraído ninguna fila; es igual a 1 si la


última instrucción SELECT... INTO ha extraído exactamente 1 fila y es igual a 2 si SELECT...INTO
ha extraído más de 1 fila (aunque se genera una excepción si el número de filas devuelto es
diferente de 1, consulte la sección Gestión de errores en este capítulo).

Para un cursor explícito, el nombre del atributo es:nombre_cursor%ROWCOUNT

Indica el número de la fila extraída por la última instrucción FETCH.

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.

% ISOPEN % FOUND %NOT %ROW


FOUND COUNT

OPEN
4. La
antes FALSO error error error

después VERDADERO NULL NULL 0

primer
FETCH
VERDADERO NULL NULL 0
antes
VERDADERO VERDADERO FALSO 1
después

FETCH

antes VERDADERO VERDADERO FALSO 1

después VERDADERO VERDADERO FALSO según los


datos

último
FETCH
VERDADERO VERDADERO FALSO según los
antes datos
VERDADERO FALSO VERDADERO
después según los
datos

CLOSE

antes VERDADERO FALSO VERDADERO según los


datos
después FALSO error error
Error

variable ROWNUM

La variable ROWNUM devuelve un número que indica el orden en el que se ha seleccionado la


fila desde una tabla. La primera fila seleccionada tiene el número 1, la segunda el número 2...
Si el comando SELECT de extracción de filas contiene una cláusula ORDER BY, entonces ROWNUM
contiene el número de la filaanterior a la selección de los datos.

Ejemplo

Uso de ROWNUM: en el siguiente ejemplo, la variable ROWNUM se usa para extraer los tres
primeros clientes:

SQL> select NUMCLI, NOMCLI


2 from CLIENTES
3 where ROWNUM<=3;
NUMCLI NOMCLI
---------- ------------------------------
1 Alberto
2 Bernardo
3 Castillo

SQL>

5. Modificación de los valores de un cursor

En una operación de modificación o de eliminación, la cláusula CURRENT OF permite acceder


directamente a la fila que acaba de extraerse mediante el comando FETCH.

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.

Por otro lado, la cláusula CURRENT OF no permite manipular la clave primaria.

Ejemplo

Uso de un cursor para actualizar cada línea procesada:

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

Declaración del cursor con parámetros:

CURSOR nombre_cursor(nombre_parámetro tipo_dato, ...)


IS consulta_SELECT;

Apertura del cursor y paso del valor de los parámetros:

OPEN nombre_cursor(valor_parámetro1, ...);

Ejemplo

Uso de un cursor paramétrico: en el siguiente ejemplo, el cursor recibe como parámetro el


número de cliente y permite conocer los números de los pedidos realizados por este cliente.

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 /

Procedimiento PL/SQL terminado correctamente.


SQL>

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.

Estructura de un bloque PL/SQL:

La sección EXCEPTION permite definir un tratamiento apropiado para los posibles errores que
puedan producirse durante la ejecución del bloque PL/SQL.

Se distingue entre dos tipos de errores:

 errores internos de Oracle,


 anomalías debidas al programa.

Después de ejecutar el código correspondiente al tratamiento de la excepción, el bloque en curso


de ejecución se termina y la siguiente instrucción que se ejecuta es la que sigue a la llamada a
este bloque PL/SQL en el bloque maestro.

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.

Esquema que resume la principal ventaja de un mecanismo de captura de errores:

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.

La activación de excepciones no permite proseguir normalmente el tratamiento de las


operaciones.

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.

Excepción Error de Oracle Valor de SQLCODE

ACCESS_INTO_NULL ORA-06530 -6530

CASE_NOT_FOUND ORA-06592 -6592

COLLECTION_IS_NULL ORA-06531 -6531

CURSOR_ALREADY_OPEN ORA-06511 -6511

DUP_VAL_ON_INDEX ORA-00001 -1

INVALID_CURSOR ORA-01001 -1001

INVALID_NUMBER ORA-01722 -1722

LOGIN_DENIED ORA-01017 -1017

NO_DATA_FOUND ORA-01403 +100

NOT_LOGGED_ON ORA-01012 -1012

PROGRAM_ERROR ORA-06501 -6501

ROWTYPE_MISMATCH ORA-06504 -6504

SELF_IS_NULL ORA-030625 -30625

STORAGE_ERROR ORA-06500 -6500

SUBSCRIPT_BEYOND_COUNT ORA-06533 6533

SUBSCRIPT_OUTSIDE_LIMIT ORA-06532 -6532

SYS_INVALID_ROWID ORA-01410 -1410

TIMEOUT_ON_RESOURCE ORA-00051 -51

TOO_MANY_ROWS ORA-01422 -1422


VALUE_ERROR ORA-06502 06502 Las

ZERO_DIVIDE ORA-01476 -1476


excepciones predefinidas pertenecen al paquete STANDARD, de modo que se pueden utilizar tal
cual en los programas PL/SQL.

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

Gestión de la excepción predefinida de Oracle TOO_MANY_ROWS: en el siguiente ejemplo, la


sección de excepciones del bloque PL/SQL permite tratar las excepciones que corresponden a un
intento de almacenar un conjunto de valores en una única variable (TOO_MANY_ROWS).

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

2. Anomalías del programa de usuario

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.

La declaración de excepciones es similar a la de las variables.

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

En el ejemplo anterior dedicado a cursores se desea detener y anular las modificaciones si un


determinado precio sobrepasa el precio máximo fijado.

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.

En la práctica, una excepción se propaga de bloque en bloque hasta encontrar un tratamiento


que le sea adecuado en la sección de excepciones. Una vez se ha gestionado la excepción, se
sale del bloque actual para volver al bloque de nivel superior, sin arrastrar ya ningún error. En
ocasiones, puede ser necesario generar de nuevo una excepción después del tratamiento de
excepciones. Para ello, se utiliza la palabra clave RAISE seguida del nombre de la excepción que
hay que propagar al bloque de nivel superior.

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

PRAGMA EXCEPTION_INIT (nombre_excepción, número_error_oracle)

Ejemplo

Detección de un error de Oracle no predefinido: en el ejemplo siguiente, el bloque PL/SQL trata


el error que se produce en caso de interbloqueo. Un bloqueo de este tipo se produce cuando los
bloqueos aplicados a las diferentes filas modificadas por los usuarios bloquean a todos los
usuarios. Oracle detecta automáticamente los interbloqueos y decide en dicho caso liberar una
transacción para autorizar la introducción del comando ROLLBACK con el fin de liberar los
recursos y a los usuarios.

Por tanto, el tratamiento de esta excepción será simplemente el comando ROLLBACK.

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

PL/SQL declara las excepciones predefinidas en el paquete STANDARD. No es necesario en


absoluto volver a definir estas excepciones, ya que la definición local de la excepción
enmascararía a la declaración global. Por ejemplo, si se define una excepción invalid_number
asociada a un código de error de Oracle, para tratar la excepción predefinida que usa este
nombre habrá que preceder el nombre de la excepción con el nombre del paquete, es decir,
standard.invalid_number.

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;

4. Ámbito de las excepciones

La visibilidad de las excepciones es similar a la de las variables. Una excepción es visible en el


bloque en el que ha sido definida y en todos los subbloques de dicho bloque. Sin embargo, se
puede enmascarar esta excepción en los subbloques, definiendo de nuevo una excepción que
utilice el mismo nombre.

Visibilidad de las excepciones:

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

El paquete DBMS_STANDARD, que se instala con Oracle, proporciona un conjunto de funciones


y procedimientos que facilitan el desarrollo en un entorno Oracle. Por ejemplo, el
procedimientoraise_application_error permite definir errores de usuario en los
subprogramas.

Sintaxis

raise_application_error (número_error, mensaje [,{TRUE|FALSE}]);

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.

Cuando un bloque PL/SQL llama al procedimiento raise_application_error se


interrumpe la ejecución de este bloque y el error pasa al bloque que ha hecho la llamada. Este
bloque debe tratar la excepción como un error de Oracle.

Ejemplos

Uso de raise_application_error: en el siguiente ejemplo se produce un error si el cliente vive en


Orense.

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>

Bloque de eliminación de un cliente: en este segundo ejemplo se utilizan los mecanismos de


tratamiento de excepciones para eliminar a un cliente.

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.

Este programa se ejecuta en SQL*Plus.

1. Especificación del programa

Se desea actualizar la cantidad que hay en almacén de la tabla ARTICULOS (REFART,


DESCRIPCION, PRECIOSINIVA, CANTALM) a partir de los pedidos en curso (ESTADOPED = ’EC’)
almacenados en las tablas PEDIDOS (NUMPED, NUMCLI, FECHAPED, ESTADOPED) y LINEASPED
(NUMPED, NUMLIN, REFART, CANTPED).

El proceso debe actualizar la columna CANTALM de la tabla ARTICULOS, restando la cantidad


pedida (CANTPED de la tabla LINEASPED) para el artículo. También debe actualizar el estado del
pedido (ESTADOPED) a ’SU’ (suministrado) si todas las cantidades especificadas en el pedido
pueden ser suministradas (CANTALM > 0 después de realizar la operación de sustracción).

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 Suministro de pedidos y actualización de almacenes


rem Creación de la tabla TESTIGO
create table TESTIGO(numped number(6), texto char(60));

rem Bloque PL/SQL de actualización


DECLARE
cursor cped is select p.numped, refart, cantped
from linped l,pedidos p
where p.numped=l.numped
and p.estadoped=’EC’
order by p.numped;
vped cped%rowtype;
vcantalm articulos.cantalm%type;
vnvcant vcantalm%type;
vtexto testigo.texto%type;
verr boolean;
vpedref pedidos.numped%type;
BEGIN
open cped; --Ejecución del cursor
fetch cped into vped; --Lectura de la primera línea
<<Bped>>
while cped%found loop
vpedref:=vped.numped; --Principio de pedidos
verr:=false;
vtexto:=’Problema en el artículo: ’;
commit;
<<Blig>>
while cped%found and vped.numped=vpedref loop
select cantalm into vcantalm
from articulos
where refart=vped.refart;
vnvcant:=vcantalm-vped.cantped;
if (vnvcant>=0) then --almacén OK
update articulos set cantalm=vnvcant
where refart=vped.refart;
else -- almacén incorrecto
verr:=true;
vtexto:=rtrim(vtexto)||rtrim(vped.refart);
end if;
fetch cped into vped; --lectura de la siguiente línea
end loop Blig;
if verr then
rollback;
else
update pedidos set estadoped=’SU’
where numped=vpedref;
vtexto:=’Pedido suministrado’;
end if;
insert into testigo values (vped.numped, vtexto);
commit;
end loop Bped;
close cped;
END;

/
rem Consulta de la tabla testigo
select * from testigo;
drop table testigo;

3. Ejecución en SQL*Plus
SQL> select * from articulos;

REFA DESCRIPCION PRECIO CODIVA CATEGORIA CANTALM


---- --------------------- ------------ ------- ---------- ----------
AB22 ALFOMBRA PERSA 1250,1 2 IMPORT 40
CD50 CADENA HIFI 2 IMPORT 1
CD21 Pletina láser 500 2 IMPORT 100
ZZZZ CANTIMPLORA VARIOS 25
AA00 REGALO 0 VARIOS 8
AB03 Alfombras 150 2 IMPORT 30
AB ALFOMBRA 2 REBAJ 2
ZZ01 LOTE ALFOMBRAS 500 2 VARIOS 150
AB10 Alfombra china 1500 2 IMPORT 2

9 filas seleccionadas.

SQL> select * from ped;

NUMPED ES REFAR CANTPED


--------- -- ----- ----------
1210 EC AB10 3
1210 EC CD50 4
1250 EC AB03 8
1301 EC AB03 5
1230 EC AB10 20

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

SQL> drop table testigo;

Tabla borrada.
SQL> select * from articulos;

REFA DESCRIPCION PRECIO CODIVA CATEGORIA CANTALM


---- ---------------------------------- -------- ---------- ----------
AB22 ALFOMBRA PERSA 1250,1 2 IMPORT 40
CD50 CADENA HIFI 2 IMPORT 1
CD21 Pletina láser 500 2 IMPORT 100
ZZZZ CANTIMPLORA VARIOS 25
AA00 REGALO 0 VARIOS 8
AB03 Alfombras 150 2 IMPORT 17
AB ALFOMBRA 2 REBAJ 2
ZZ01 LOTE ALFOMBRAS 500 2 VARIOS 150
AB10 Alfombra china 1500 2 IMPORT 2

9 filas seleccionadas.

SQL> select * from ped;

NUMPED ES REFAR CANTPED


---------- -- ----- ----------
1210 EC AB10 3
1210 EC CD50 4
1250 SU AB03 8
1301 SU AB03 5
1230 EC AB10 20

SQL> spool off


Introducción
Además de los bloques PL/SQL anónimos utilizados por SQL*Plus o por las herramientas de
desarrollo (Oracle*Forms, Oracle*Reports...), se puede emplear código PL/SQL en determinados
objetos de la base de datos, como los procedimientos almacenados (PROCEDURE, FUNCTION,
PACKAGE) y los triggers de base de datos.
Los triggers de bases de datos
Un trigger es un bloque PL/SQL asociado a una tabla. Este bloque se ejecutará cuando se aplique
a la tabla una instrucción DML (INSERT, UPDATE, DELETE).

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.

Principio de funcionamiento de los triggers instead of

Sintaxis

CREATE [OR REPLACE] TRIGGER nombre_trigger


{BEFORE/AFTER/INSTEAD OF}
{INSERT/UPDATE[OF col,...]/DELETE}
ON Nombre_tabla [FOR EACH ROW]
[FOLLOWS nombre_otro_trigger[,...]]
[ENABLE/DISABLE]
[WHEN (condition)]
Bloc PL/SQLv

OR REPLACE

Reemplaza la descripción del trigger si ya existe.

BEFORE

El bloque PL/SQL se ejecuta antes de la verificación de las restricciones de tabla y de actualizar


los datos almacenados en la misma.

AFTER

El bloque PL/SQL se ejecuta después de la actualización de los datos contenidos en la tabla.

INSTEAD OF

El bloque PL/SQL siguiente reemplaza el procesamiento estándar asociado a la instrucción que


ha activado al trigger (solo por una vista).

INSERT/UPDATE [OF col,...]/DELETE

Instrucción asociada a la activación del trigger. Varias instrucciones pueden activar un mismo
trigger y se combinan mediante el operador OR.

FOR EACH ROW

El trigger se ejecuta para cada fila tratada por la instrucción asociada.

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)

La condición especificada debe cumplirse para que se ejecute el código.

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:

CREATE TRIGGER antes_elim_cli


BEFORE DELETE
ON FLORENCIO.CLIENTES
DECLARE
...
BEGIN
...
END;

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:

create or replace trigger post_actprecio


after update of precio
on articulos
for each row
when (old.precio > new.precio)
declare
...
begin
...
end;

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.

Modificación de la tabla PEDIDOS:

SQL> alter table pedidos


2 add (usuario varchar2(30));

Tabla modificada.

SQL>

En el trigger se cambia el nombre de la nueva fila, y el trigger se ejecuta antes de la verificación


de las restricciones de integridad para cada fila insertada en la tabla de pedidos.

Definición del trigger:

SQL> create or replace trigger bf_ins_pedidos


2 before insert
3 on pedidos
4 referencing new as nuevo
5 for each row
6 begin
7 select user into :nuevo.usuario from dual;
8 end;
9 /

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.

Creación de la tabla de estadísticas:

SQL> create table stat_util(


2 usuario varchar2(30),
3 numero integer);

Tabla creada.

SQL>

El trigger debe asegurarse de que el usuario existe en la tabla de estadísticas y, si todavía no


existe, debe crearlo. El trigger se ejecuta después de cada inserción de fila por razones de
optimización en caso de que se violen las restricciones de integridad.

Código del trigger:

SQL> create or replace trigger af_ins_pedidos


2 after insert
3 on pedidos for each row
4 declare
5 vnumero stat_util.numero%type;
6 begin
7 -- obtener el número del usuario actual
8 select numero into vnumero
9 from stat_util
10 where usuario=:new.usuario;
11 -- actualizar el valor
12 update stat_util
13 set numero=vnumero+1
14 where usuario=:new.usuario;
15 exception
16 when no_data_found then
17 insert into stat_util (usuario, numero)
18 values (:new.usuario,1);
19 end;
20 /
Trigger creado.

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:

SQL> create or replace trigger af_ins_delete


2 after insert or delete
3 on pedidos for each row
4 declare
5 vnumero stat_util.numero%type;
6 vutil stat_util.usuario%type;
7 begin
8 select user into vutil from dual;
9 --conocer el número actual para el usuario actual
10 select numero into vnumero
11 from stat_util
12 where usuario=vutil;
13 --actualizar el valor
14 if (inserting) then
15 vnumero:=vnumero+1;
16 end if;
17 if (deleting) then
18 vnumero:=vnumero-1;
19 end if;
20 update stat_util
21 set numero=vnumero
22 where usuario=vutil;
23 exception
24 when no_data_found then
25 if (inserting) then
26 insert into stat_util(usuario, numero)
27 values (vutil,1);
28 else
29 null;
30 end if;
31 end;
32 /

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.

Creación de la vista y visualización del fallo:

SQL> create or replace view cliorense


2 as select numcli,nomcli,direccli
3 from clientes
4 where upper(ciudad)=’ORENSE’;

Vista creada.

SQL> insert into cliorense


2 values (13,’Pedro’,’Av. del deporte’);

1 fila creada.

SQL> select * from cliorense;

NUMCLI NOMCLI DIRECCLI


---------- -------------------- ------------
15 GÓMEZ S.A. C/ Mayor
35 MARTÍN JUAN C/ Menor

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.

Creación y prueba del trigger:

SQL> create or replace trigger inst_ins_cliorense


2 instead of insert
3 on cliorense for each row
4 begin
5 insert into clientes (numcli, nomcli, direccli, codpostal, ciudad)
6 values (:new.numcli, :new.nomcli, :new.direccli, 32000,’Orense’);
7 end;
8 /

Trigger creado.

SQL> insert into cliorense


2 values (13,’Pedro’,’Av. del deporte’);

1 fila creada.
SQL> select * from cliorense;

NUMCLI NOMCLI DIRECCLI


---------- -------------------- ------------------
15 GÓMEZ S.A. C/ Mayor
35 MARTÍN JUAN C/ Menor
13 Pedro Av. del deporte

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.

SQL> create or replace trigger inst_del_vpedlin


2 instead of delete
3 on vpedlin
4 for each row
5 declare
6 vcantimpl number(5);
7 begin
8 delete from lineasped
9 where numped=:old.numped
10 and numlin=:old.numlin;
11 -- si es la última fila suprimir el pedido
12 select count(*) into vcantimpl
13 from lineasped
14 where numped=:old.numped;
15 exception
16 when no_data_found then
17 delete from pedidos where numped=:old.numped;
18 end;
19 /

Trigger creado.

SQL>

En la versión 11, Oracle ha introducido la noción de trigger compuesto.

A diferencia de un trigger simple, en el que el momento de su activación es único (antes o


después de la instrucción o la actualización de una fila), un trigger compuesto puede tener hasta
cuatro secciones, cada una de ellas correspondiente a un instante de activación: antes de la
instrucción, antes de cada fila, después de cada fila, después de la instrucción.
El trigger compuesto presenta una ventaja en relación al uso de varios triggers separados: las
diferentes secciones pueden compartir las declaraciones comunes (variables, tipos, cursores,
subprogramas, etc.).

Sintaxis

CREATE [OR REPLACE] TRIGGER nombre_trigger


FOR {INSERT/UPDATE [OF columna, ...]/DELETE}
ON nombre_tabla
[FOLLOWS nombre_otro_trigger[, ...]]
[ENABLE/DISABLE]
[WHEN (condición)]
COMPOUND TRIGGER
[declaraciones_comunes]
[BEFORE STATEMENT IS
[declaraciones_locales]
BEGIN
instrucciones
END BEFORE STATEMENT]
[BEFORE EACH ROW IS
[declaraciones_locales]
BEGIN
instrucciones
END BEFORE EACH ROW]
[AFTER EACH ROW IS
[declaraciones_locales]
BEGIN
instrucciones
END AFTER EACH ROW]
[AFTER STATEMENT IS
[declaraciones_locales]
BEGIN
instrucciones
END AFTER STATEMENT]
END [nombre_trigger]

La cláusula FOR reemplaza a la cláusula BEFORE/AFTER de un trigger simple y permite definir


el evento de activación del trigger.
La cláusula ON permite especificar la tabla afectada; a este nivel, la cláusula FOR EACH
ROW del trigger simple no está permitida.

Las cláusulas FOLLOWS, ENABLE/DISABLE y WHEN son las mismas que para un trigger
simple.

La cláusula opcional declaraciones_comunes permite definir las declaraciones comunes


(variables, tipos, cursores, subprogramas, etc.) a las diferentes secciones de código del trigger.

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

dondeinstante_activación es igual a una de las cláusulas siguientes: BEFORE


STATEMENT,BEFORE EACH ROW, AFTER STATEMENT y AFTER EACH ROW.

La cláusula opcional declaraciones_locales permite definir las declaraciones locales de


cada sección de código.

Como ejemplo, vamos a crear un trigger que audita las modificaciones de salario de los
empleados:

SQL> create or replace trigger auditar_modificaciones_salariales


2 for update of salario on empleado
3 compound trigger
4 acumulado number:=0;
5 procedure mostrar(texto varchar2)
6 is
7 begin
8 dbms_output.put_line(texto);
9 end mostrar;
10 after each row is
11 incremento number;
12 begin
13 incremento:= :new.salario - :old.salario;
14 mostrar(:new.numeroempleado || ’ : ’ || incremento);
15 acumulado:= acumulado + incremento;
16 end after each row;
17 after statement is
18 begin
19 mostrar(’Total: ’ || acumulado);
20 end after statement;
21 end auditar_modificaciones_salariales
22 /

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.

En la sección after statement el trigger solo muestra el valor de la variable


global acumulado.

Ahora podemos verificar este trigger:

SQL> set serveroutput on


SQL> select NUMEROEMPLEADO,SALARIO from EMPLEADO;

NUMEROEMPLEADO SALARIO
----------------------------- ----------
1 1200
2 1800
SQL> update EMPLEADO set SALARIO=SALARIO * 1.01;
1: 12
2: 18
Total: 30

2 filas actualizadas.

Triggers sobre sucesos del sistema o de usuario


Es posible utilizar triggers para hacer un seguimiento de los cambios de estado del sistema,
como por ejemplo el arranque y el apagado. Estos triggers van a permitir mejorar la gestión de
la base de datos y de la aplicación. En efecto, determinados sucesos del sistema o del usuario
tienen una repercusión directa sobre el rendimiento de la aplicación y/o la coherencia de los
datos.

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

Nombre de la base de datos.

ora_des_encrypted_password

Permite conocer las descripciones cifradas de contraseñas del usuario que se hayan creado o
modificado.

ora_dict_obj_name

Nombre del objeto sobre el que acaba de ejecutarse la operación DDL.

ora_dict_obj_name_list

Permite conocer la lista de todos los nombres de objetos que se han modificado.

ora_dict_obj_owner

Propietario del objeto sobre el que se aplica la operación DDL.

ora_dict_obj_owner_list
Permite conocer la lista de todos los propietarios de los objetos que se han modificado.

ora_dict_obj_type

Tipo del objeto esperado en la última operación DDL.

ora_grantee

Permite conocer qué usuarios tienen este privilegio.

ora_instance_num

Número de la instancia.

ora_is_alter_column

Devuelve TRUE si la columna que se pasa como parámetro se ha modificado.

ora_is_creating_nested_table

Permite saber si se ha creado una tabla anidada.

ora_is_drop_column

Permite saber si la columna que se pasa como parámetro se ha eliminado.

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

Permite conocer el nombre del usuario que ha iniciado la sesión.

ora_privileges_list

Permite conocer la lista de privilegios concedidos o revocados a un determinado usuario.

ora_revokee

Permite saber a qué usuarios se les ha revocado el privilegio.

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

Mensaje de error almacenado en un índice dado en la pila de errores.

ora_server_error_num_params

Número de argumentos substituidos en el mensaje de error almacenado en un índice dado en


la pila de errores.

ora_server_error_param

Valor substituido para un número de argumentos determinado en el mensaje de error


almacenado en un índice dado de la pila de errores.

ora_sql_text

Consulta SQL que está en el origen de la ejecución del trigger.

ora_sysevent

Nombre del suceso del sistema que ha activado el trigger.

ora_with_grant_option

Devuelve TRUE si el privilegio se ha concedido con una opción de administración.

ora_space_error_info

Si el error es relativo a una falta de espacio, da información acerca del objeto afectado.

2. Sucesos del sistema

STARTUP

Este suceso se activa al abrir la instancia.

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

Create trigger nombre_trigger {AFTER|BEFORE} suceso_sistema


ON{DATABASE|SCHEMA}
Bloque PL/SQL

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

Implementación de un trigger de gestión de errores: en el siguiente ejemplo, los datos relativos


a cada error provocado en el esquema del usuario que ha creado el trigger se almacenan en la
tabla errores, que se ha creado previamente.

SQL> create or replace trigger srv_error


2 after SERVERERROR on schema
3 begin
4 insert into errores (usuario, tiempo, num_error)
5 values (ora_login_user, sysdate, ora_server_error(1));
6 end;
7 /

Trigger creado.

SQL>

3. Sucesos de usuario

AFTER LOGON

Se produce después de haber establecido una conexión con el servidor.

BEFORE LOGOFF

Se produce antes de interrumpir la conexión con el servidor.

BEFORE CREATE, AFTER CREATE

Se produce cuando se crea un objeto.

BEFORE ALTER, AFTER ALTER

Se produce cuando se modifica un objeto.


BEFORE DROP, AFTER DROP

Se produce cuando se elimina un objeto.

BEFORE ANALYZE, AFTER ANALYZE

Se produce cuando se ejecuta una instrucción de análisis.

BEFORE ASSOCIATE STATISTICS, AFTER ASSOCIATE STATISTICS

Se produce cuando se ejecuta una asociación de estadísticas.

BEFORE AUDIT, AFTER AUDIT

Se produce cuando se activa una auditoría.

BEFORE NOAUDIT, AFTER NOAUDIT

Se produce cuando se anula una operación de auditoría.

BEFORE COMMENT, AFTER COMMENT

Se produce cuando se incluye un comentario.

BEFORE DDL, AFTER DDL

Se produce durante la ejecución de la mayoría de las instrucciones DDL, a excepción de ALTER


DATABASE, CREATE CONTROLFILE, CREATE DATABASE y todas las instrucciones DDL
ejecutadas dentro de un bloque PL/SQL.

BEFORE DISSOCIATE STATISTICS, AFTER DISSOCIATE STATISTICS

Se produce durante la disociación de las estadísticas de un objeto.

BEFORE GRANT, AFTER GRANT

Se produce durante la ejecución de una instrucción GRANT.

BEFORE RENAME, AFTER RENAME

Se produce durante la ejecución de una instrucción RENAME.

BEFORE REVOKE, AFTER REVOKE

Se produce durante la ejecución de la instrucción REVOKE.

BEFORE TRUNCATE, AFTER TRUNCATE

Se produce al truncar una tabla.


Sintaxis

Create trigger nombre_trigger {AFTER|BEFORE}


suceso_usuario ON{DATABASE|SCHEMA}
Bloque PL/SQL

Debe consultar la lista anterior para saber si el suceso puede tratarse mediante un trigger de
tipo BEFORE o AFTER.

Ejemplo

Implementación de un trigger de supervisión de tablas: en el siguiente ejemplo, el trigger


definido permite monitorizar todas las creaciones de tablas. Todas las operaciones de creación
se almacenan en la tabla INFO_TABLA que se ha creado previamente.

SQL> create or replace trigger srv_table


2 after ddl
3 on database
4 begin
5 if (ora_dict_obj_type=’TABLE’) then
6 if (ora_sysevent=’CREATE’) then
7 insert into info_tabla(usuario,nom_tabla,creación)
8 values (ora_login_user, ora_dict_obj_name, sysdate);
9 end if;
10 end if;
11 end;
12 /

Trigger creado.

SQL>

Modificaciones en los triggers


Un trigger de base de datos no puede modificarse. Sin embargo, puede borrarse para volver a
crearlo a continuación, o crearlo mediante la opción OR REPLACE.

La instrucción ALTER TRIGGER permite desactivar y después reactivar los triggers. La


desactivación puede planificarse cuando vaya a realizarse una importación masiva de datos o
una modificación importante.
La desactivación y la reactivación de triggers pueden realizarse trigger por trigger, o tabla por
tabla. La instrucción ALTER TABLE permite activar y desactivar todos los triggers aplicados sobre
una tabla.

Sintaxis

ALTER TRIGGER nombre_trigger {ENABLE|DISABLE};


ALTER TABLE nombre_trigger { ENABLE|DISABLE } ALL TRIGGERS;

Ejemplo

Desactivación seguida de una reactivación de triggers:

SQL> alter trigger bf_ins_pedidos DISABLE;

Trigger modificado.

SQL> ALTER TRIGGER bf_ins_pedidos ENABLE;

Trigger modificado.

SQL> ALTER TABLE pedidos DISABLE ALL TRIGGERS;

Tabla modificada.

SQL> ALTER TABLE pedidos ENABLE ALL TRIGGERS;

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.

La columna TRIGGER_TYPE permite saber si se trata de un trigger de tipo BEFORE, AFTER o


INSTEAD OF; si su modo de ejecución es FOR EACH ROW o no, y si se trata de un trigger basado
en un suceso o no.

La columna TRIGGERING_EVENT permite saber qué suceso se ve afectado por el trigger.


Ejemplo

Consulta del diccionario: en el ejemplo siguiente, se consulta la vista USER_TRIGGERS para


saber qué triggers están definidos sobre el esquema del usuario actual.

SQL> select substr(trigger_name,1,20) as nom_trigger,


2 trigger_type as type,
3 substr(base_object_type,1,8) as sobre,
4 substr(table_name,1,10) as nom_objeto,
5 substr(triggering_event,1,20) as suceso
6 from user_triggers;

NOM_TRIGGER TYPE SOBRE NOM_OBJETO SUCESO


-------------------- ---------------- --------- ---------- -------
AF_INS_PEDIDOS AFTER EACH ROW TABLE PEDIDOS INSERT
BF_INS_PEDIDOS BEFORE EACH ROW TABLE PEDIDOS INSERT
INST_INS_CLIORENSE INSTEAD OF VIEW CLIORENSE INSERT
SRV_TABLE AFTER EVENT DATABASE DDL
SRV_ERROR AFTER EVENT SCHEMA ERROR

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

CREATE [OR REPLACE] PROCEDURE nombre_procedimiento


[(parámetro {IN/OUT/IN OUT} tipo, ...)]
{IS/AS} bloque PL/SQL;

OR REPLACE

Reemplaza la descripción del procedimiento, si existe.

parámetro
Especifica una variable pasada como parámetro que puede utilizarse en el bloque.

IN

El parámetro que se pasa es un dato de entrada para el procedimiento.

OUT

El procedimiento asigna un valor al parámetro especificado y lo devuelve al entorno que haya


hecho la llamada.

tipo

Tipo de variable (SQL o PL/SQL).

Ejemplo

Procedimiento para eliminar un artículo:

SQL> create or replace procedure elim_art (numero in char) is


2 begin
3 delete from lineasped where refart=numero;
4 delete from articulos where refart=numero;
5 end;
6 /

Procedimiento creado.

SQL>

Uso en SQL*Plus:

SQL> execute elim_art (’AB01’)


Procedimiento PL/SQL terminado correctamente.

Uso en un bloque PL/SQL:

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

CREATE [OR REPLACE] FUNCTION nombre_función


[(parámetro [IN] tipo, …)]
RETURN tipo {IS/AS} Bloque PL/SQL;

OR REPLACE

Si la función existe, se reemplaza su descripción.

parámetro

Especifica un parámetro que se pasa como dato de entrada y que se usa como una variable
dentro del bloque.

tipo

Tipo de parámetro (SQL o PL/SQL).

RETURN tipo

Tipo del valor devuelto por la función.

Ejemplo

Función factorial:

CREATE FUNCTION factorial (n IN NUMBER)


RETURN NUMBER
IS BEGIN
if n = 0 then
return (1) ;
else
return ((n * factorial (n-1))) ;
end if ;
END ;
Uso en SQL*Plus:

SQL> select factorial(5) from DUAL;

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

RESULT_CACHE [RELIES_ON (nombre_tabla_o_vista[,...])]

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

SQL> create or replace function valor_parametro(n in number)


2 return varchar2
3 resultado_cache_relies_on (parametros)

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.

SQL> set timing on


SQL> select valor_parametro(1) from dual;

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).

El administrador de la base de datos dispone de varios parámetros para regular el


funcionamiento de la caché del resultado.

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

SQL> -- creación de una función


SQL> create or replace function may(p varchar2)
2 return varchar2
3 is
4 begin
5 return upper(p);
6 end;
7 /

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

Tiempo transcurrido: 00 :00 :02.05


SQL>
SQL> -- recreación de la función con la directiva UDF
SQL> create or replace function may(p varchar2)
2 return varchar2
3 is
4 pragma udf;
5 begin
6 return upper(p);
7 end;
8 /

Función creada.

Tiempo transcurrido: 00:00:00.02


SQL>
SQL> -- Llamada a la función modificada en una sentencia SQL
SQL> select count(distinct may(nombre)) from employees;

COUNT(DISTINCTMAY(NOMBRE))
-----------------------
43092

Tiempo transcurrido: 00:00:00.35

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

SQL> -- llamada de una función definida en la cláusula WITH


SQL> with
2 function may(p varchar2)
3 return varchar2
4 is
5 begin
6 return upper(p);
7 end;
8 select count(distinct may(nombre)) from employees
9 /

COUNT(DISTINCTMAY(NOMBRE))
-----------------------
43092

Tiempo transcurrido: 00:00:00.48

Comparando ambos ejemplos, observamos que la llamada a la función definida en la cláusula


WITH presenta un mejor rendimiento que la llamada a una función almacenada «normal», y es
ligeramente con menor rendimiento que la llamada a la función compilada con la directiva UDF.

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.

Los paquetes ofrecen numerosas ventajas:

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.

Simplificación del desarrollo

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.

Mejora del rendimiento

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

CREATE PACKAGE nombre_paquete AS


--Definición de tipos
--Declaraciones de variables públicas
--Prototipos de los cursores públicos
--Prototipos de los procedimientos y funciones públicas
END [nombre_paquete];

Ejemplo

Cabecera de un paquete de gestión de clientes:


SQL> create or replace package GESTION_CLIENTES as
2 type T_CLIREC is record (
3 NUMCLI number(4),
4 NOMBRE char(20),
5 DIREC char(20),
6 CODPOST number(5),
7 CIUDAD char(30));
8 cursor C_CLIENTES return T_CLIREC;
9 function CRE_CLI (NOMBRE char, DIREC char, CODPOST number,
10 CIUDAD char)
11 return number;
12 procedure Elim_CLI (NUMCLIENTE number);
13 end GESTION_CLIENTES;
14 /

Paquete creado.

SQL>

2. Cuerpo del paquete

El cuerpo del paquete (PACKAGE) contiene la implementación de los procedimientos y funciones


descritos en la cabecera. También contiene definiciones de tipos y declaraciones de variables
cuyo ámbito está limitado al cuerpo del paquete.

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

CREATE PACKAGE BODY nombre_paquete AS


--Definición de los tipos locales al paquete
--Declaraciones de las variables locales al paquete
--Implementación de los cursores públicos
--Cuerpo de los procedimientos y funciones locales al paquete
--Cuerpo de los procedimientos y funciones públicas
END [nombre_paquete];

Ejemplo

Cuerpo del paquete para la gestión de clientes:

SQL> create or replace package body GESTION_CLIENTES as


2 NUMERO_CLI integer; -- Definición de una variable local
3
4 -- Implementación del cursor
5 cursor C_CLIENTES return T_CLIREC is
6 select NUMCLI, NOMCLI, DIRECCLI, CODPOSTAL, CIUDAD
7 from CLIENTES
8 order by NUMCLI;
9
10 -- Función de creación de un nuevo cliente
11 function CRE_CLI (NOMBRE char, DIREC char, CODPOST number,
12 CIUDAD char)
13 return number
14 is
15 NUEVO_NUMCLI number;
16 begin
17 select C_NUMCLI.nextval into NUEVO_NUMCLI from DUAL;
18 insert into CLIENTES
19 values(NUEVO_NUMCLI, NOMBRE, DIREC, CODPOST, CIUDAD);
20 NUMERO_CLI := NUMERO_CLI + 1;
21 return NUEVO_NUMCLI;
22 end;
23
24 -- Procedimiento de eliminación de un cliente
25 procedure Elim_CLI (NUMCLIENTE number)
26 is
27 begin
28 delete from CLIENTES where NUMCLI = NUMCLIENTE;
29 end;
30 end GESTION_CLIENTES;
31 /

Cuerpo del paquete creado.

SQL>

3. Uso

Se hace referencia a los elementos de un paquete (variables, procedimientos, funciones)


utilizando el nombre del paquete y el operador ".".

Ejemplo

Uso del paquete para la gestión de clientes:

SQL> var V_NUMCLI number

SQL> begin
2 :V_NUMCLI := GESTION_CLIENTES.CRE_CLI
3 (’CESAR’,’Cava Baja’,13000,’MARBELLA’);
4 end;
5 /

Procedimiento PL/SQL terminado correctamente.

SQL> print V_NUMCLI

V_NUMCLI
----------
2003
SQL> select NUMCLI, ltrim(NOMCLI) NOMCLI, CIUDAD
2 from CLIENTES order by NUMCLI
3 /

NUMCLI NOMCLI CIUDAD


---------- ------------------------------ --------------------
13 PEDRO ORENSE
15 GÓMEZ S.A. ORENSE
20 M. GARCÍA TOLEDO
35 MARTÍN JUAN ORENSE
36 DEL PINO S.A. TOLEDO
37 E. LACALLE CACERES
100 NEWTON MADRID
138 MARTÍN JUAN MADRID
152 LACALLE CACERES
2003 CESAR MARBELLA

10 filas seleccionadas.

SQL> begin
2 GESTION_CLIENTES.ELIM_CLI(152);
3 end;
4 /

Procedimiento PL/SQL terminado correctamente.

SQL> select NUMCLI, ltrim(NOMCLI) NOMCLI, CIUDAD


2 from CLIENTES order by NUMCLI
3 /
NUMCLI NOMCLI CIUDAD
---------- ------------------------------ --------------------
13 PEDRO ORENSE
15 GÓMEZ S.A. ORENSE
20 M. GARCÍA TOLEDO
35 MARTÍN JUAN ORENSE
36 DEL PINO S.A. TOLEDO
37 E. LACALLE CACERES
100 NEWTON MADRID
138 MARTÍN JUAN MADRID
2003 CESAR MARBELLA

9 filas seleccionadas.
SQL>

4. Cursores

Es posible separar la declaración de un cursor (la especificación) de su definición (el cuerpo).


Con esta técnica, será posible cambiar la definición del cursor sin tener que modificar su
declaración. La declaración del cursor contenida en la cabecera del paquete debe respetar la
sintaxis siguiente:

CURSOR nombre_cursor [(parámetro, ...)] RETURN


tipo_valor_devuelto

El valor devuelto debe ser un registro.

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.

No se puede incluir la directiva de compilación pragma AUTONOMOUS_TRANSACTION en el nivel


de paquete. Sin embargo, cada función y procedimiento del paquete se puede declarar como
transacción autónoma.

Ejemplo

Procedimiento que define una transacción autónoma: en el siguiente ejemplo, la función de


actualización de clientes constituye una transacción autónoma.

SQL> create or replace procedure nombre_correcto as


2 PRAGMA AUTONOMOUS_TRANSACTION;
3 begin
4 update clientes set nomcli=initcap(nomcli);
5 commit;
6 end;
7 /
Procedimiento creado.

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.

Las transacciones autónomas se controlan mediante las instrucciones COMMIT, ROLLBACK y


SAVEPOINT. En un bloque PL/SQL definido como transacción autónoma se pueden llevar a cabo
varias transacciones una tras otra. Para la transacción principal que realiza la invocación, es este
conjunto de transacciones del bloque invocado el que es autónomo.

Ejemplo

Procedimiento que define una transacción autónoma; en el siguiente ejemplo se invoca el


procedimiento de actualización de clientes desde un bloque PL/SQL anónimo cuya transacción
en curso se anula. Se puede comprobar que el trabajo realizado por el procedimiento sigue
siendo válido.

SQL> begin
2 insert into clientes(numcli,nomcli)
3 values (14,’pablo’);
4 nombre_correcto();
5 rollback;
6 end;
7 /

Procedimiento PL/SQL terminado correctamente.

SQL> select numcli,nomcli from clientes;


NUMCLI NOMCLI
---------- ------------------------------
15 Gómez S.A.
20 M. García
35 Martín Juan
36 Del Pino S.A.
152 Lacalle
138 Martín Juan
37 E. Lacalle
10 Torres
12 Toni
11 Torres
100 Newton
13 Pedro

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

INSERT INTO tabla[(columna, ...)] VALUES (expresión, ...)


RETURNING columna INTO variable

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.

SQL> create function crearCliente(vnom char, vdir char, vcodpostal number,


vciudad char)
2 return number is
3 vnumero number(6);
4 begin
5 insert into clientes(numcli, nomcli, dircli, cod_postal, ciudad)
6 values (seq_cli.nextval, vnom, vdir, vcodpostal, vciudad)
7 returning numcli into vnumero;
8 return vnumero;
9 end;
10 /

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

DELETE FROM tabla[WHERE ...] RETURNING columna INTO variable

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

UPDATE tabla SET columna=valor [,... WHERE ...] RETURNING


columna[,...] INTO variable [,...]

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.

Por tanto, el SQL dinámico se empleará en los siguientes casos:

 La instrucción SQL no es conocida en tiempo de compilación.


 La instrucción que se desea ejecutar no está soportada por el código SQL estático.
 Para ejecutar consultas construidas durante la ejecución.
 Para hacer referencia a un objeto de la base de datos que no existe en tiempo de
compilación.
 Para optimizar la consulta durante su ejecución.
 Para crear bloques PL/SQL de forma dinámica.
 Para gestionar los permisos de usuario de forma dinámica.

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

EXECUTE IMMEDIATE cadena_dinámica


[ INTO {variable, ...| registro}]
[ USING [IN|OUT|IN OUT] argumento ...]
[ {RETURNING|RETURN } INTO argumento, ...]

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

Es la variable que almacenará el valor de una columna seleccionada.

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.

Todos los argumentos pueden especificarse detrás de la cláusula USING. El modo


predeterminado es IN, es decir, que proporcionan un valor a la instrucción dinámica. Los
argumentos de tipo OUT pueden especificarse detrás de la palabra clave RETURN INTO o
RETURNING INTO. Los argumentos pueden contener valores de tipo numérico o cadenas de
caracteres, pero no se pueden especificar valores booleanos (TRUE o FALSE).

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 /

Procedimiento PL/SQL terminado correctamente.

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.

Uso de 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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

Al utilizar la cláusula USING no es obligatorio especificar el modo de uso de los parámetros de


entrada, ya que el modo predeterminado es IN. Con la cláusula RETURNING INTO no puede
especificarse el modo de uso del parámetro ya que, obligatoriamente, es OUT. Cuando sea
necesario se puede especificar el modo de uso de los parámetros como OUT o IN OUT, por
ejemplo en la llamada a un procedimiento.

Definición de un procedimiento con parámetros en modo IN, OUT e IN OUT:

SQL> CREATE OR REPLACE PROCEDURE agregar_ped(


2 vnumped IN OUT number,
3 vnumcli IN number) AS
4 BEGIN
5 SELECT seq_ped.NEXTVAL
6 INTO vnumped
7 FROM dual;
8 INSERT INTO pedidos (numped, numcli, fechaped, estadoped)
9 VALUES (vnumped, vnumcli, sysdate, ’EC’);
10 END;
11 /

Procedimiento creado.

SQL>

En el siguiente ejemplo se llama de forma dinámica al procedimiento que acabamos de definir.


El modo de uso de los diferentes parámetros se define detrás de la cláusula USING.

Modos de uso de los parámetros:

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

2. OPEN FOR, FETCH y CLOSE

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.

a. Apertura de un cursor (OPEN FOR)

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

OPEN {variable_cursor | :variable_host} FOR


consulta_dinámica
[USING argumento, ...]

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.

A partir de la versión 11, el tamaño de la consulta dinámica ya no está limitada a 32 KB ; si es


necesario, puede emplearse una variable de tipo CLOB.

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

Puede completarse el ejemplo anterior añadiendo el código correspondiente para el


procesamiento de las filas.

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;

La variable en la que se almacena un valor procedente de una columna debe corresponderse


exactamente con la definición de la columna (mismo tipo y misma precisión).

Se pueden utilizar cláusulas INTO diferentes en distintas instrucciones FETCH empleando el


mismo cursor.

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

En este ejemplo, después de procesar la última fila, se cierra el cursor:

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.

3. Uso de cursores dinámicos

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.

a. Mejora del rendimiento

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.

create or replace procedure borrar_clientes(vnumcli number) as


begin
execute immediate ’DELETE FROM clientes WHERE numcli=’||
to_char(vnumcli);
end;

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.

create or replace procedure borrar_clientes(vnumcli number) as


begin
execute immediate ’DELETE FROM clientes WHERE numcli= :v’
using vnumcli;
end;

b. Pasar el nombre de un objeto

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:

create or replace procedure borrar_tabla(nombre_tabla in varchar2) as


begin
execute immediate ’DROP TABLE :t’ using nombre_tabla;
end;

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:

CREATE PROCEDURE borrar_tabla(nombre_tabla IN VARCHAR2) AS


BEGIN
EXECUTE IMMEDIATE ’DROP TABLE ’|| nombre_tabla;
END;

c. Uso del mismo argumento varias veces

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.

El código sería entonces el siguiente:

consulta:=’insert into pedidos values (:x, :x, :y, :z)’;


execute immediate consulta using a,a,b,c;

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:

bloque_plsql:=’begin agregar_ped(:x, :x, :y, :z); end;’;


execute immediate bloque_plsql using a,b,c;

d. Atributos de los cursores

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.

SQL> CREATE OR REPLACE FUNCTION borrar_filas(


2 nombre_tabla varchar2,
3 condicion varchar2) RETURN INTEGER AS
4 BEGIN
5 EXECUTE IMMEDIATE
6 ’DELETE FROM ’||nombre_tabla||’ WHERE ’|| condicion;
7 -- se devuelve el número de filas borradas
8 RETURN SQL%ROWCOUNT;
9 END;
10 /

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.

e. Paso de valores NULL

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:

EXECUTE_IMMEDIATE ’UPDATE clientes SET ciudad= :x’ USING NULL;

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:

SQL> CREATE OR REPLACE PROCEDURE borrar


2 (tipo VARCHAR2,
3 nombre VARCHAR2) AS
4 BEGIN
5 EXECUTE IMMEDIATE ’DROP ’||tipo||’ ’||nombre;
6 END;
7 /

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:

Ejecución del procedimiento borrar desde el esquema del usuario María:

SQL> CALL borrar(’VIEW’,’CLIORENSE’);

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.

Para resolver este tipo de problemas y garantizar que el procedimiento almacenado se va a


ejecutar en función de los permisos del usuario que lo usa y no de los permisos del usuario
propietario es preciso emplear la cláusula AUTHID en la definición del procedimiento. De este
modo, los nombres de objetos se resuelven en el esquema del usuario del procedimiento y no
en el de su propietario.
Redefinición del procedimiento usando la cláusula AUTHID:

SQL> CREATE OR REPLACE PROCEDURE borrar


2 (tipo VARCHAR2,
3 nombre VARCHAR2)
4 AUTHID CURRENT_USER AS
5 BEGIN
6 EXECUTE IMMEDIATE ’DROP ’||tipo||’ ’||nombre;
7 END;
8 /

Procedimiento creado.

SQL>

g. Directiva de compilación RESTRICT_REFERENCES

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.

h. Cómo evitar los interbloqueos

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.

create procedure calculo_ca (numcli number) as


begin
...
execute immediate ’DROP PROCEDURE calculo_ca’;
...
end;
4. El paquete DBMS_SQL

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:

 Está soportado en las aplicaciones cliente,


 Soporta el procedimiento DESCRIBE_COLUMNS, que permite conocer los datos relativos a
las columnas de un cursor abierto a través de DBMS_SQL.

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> -- Definición de un procedimiento que devuelve


SQL> -- un resultado implícito
SQL> CREATE OR REPLACE PROCEDURE lista_articulos
2 IS
3 cur_articulos SYS_REFCURSOR;
4 BEGIN
5 OPEN cur_articulos FOR
6 SELECT refart,nombre
7 FROM articulos;
8 dbms_sql.return_result(cur_articulos);
9 END lista_articulos;
10 /
Procedimiento creado.

SQL>
SQL> -- Llamada al procedimiento
SQL> EXECUTE lista_articulos

Procedimiento PL/SQL terminado con éxito.

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

La colección no está inicializada.

NO_DATA_FOUND

El elemento al que se intenta acceder no existe.

SUBSCRIPT_BEYOND_COUNT

El índice del elemento al que se intenta acceder ha sido eliminado.

SUBSCRIPT_OUTSIDE_LIMIT

El índice se encuentra fuera del rango de valores permitidos.

VALUE_ERROR

El índice es NULL o no puede convertirse en un entero.

El siguiente ejemplo ilustra la generación de estas excepciones en PL/SQL.

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.

Reparto del trabajo entre los 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.

Creación de la tabla Componentes:

SQL> CREATE TABLE Componentes(


2 numero number(5),
3 nombre char(5));

Tabla creada.
SQL>

La tabla creada en el ejemplo anterior se va a rellenar mediante un bloque PL/SQL. Se mide el


tiempo de ejecución para cada uno de los métodos de inserción de datos utilizado.

Ventajas del procesamiento por bloques:

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

FORALL índice IN límite_inferior..límite_superior


instrucción_SQL;

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 /

Procedimiento PL/SQL terminado correctamente

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.

create table tabla1(col1 number, col2 char(30));


create table tabla2(col1 number, col2 char(30));

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);

-- actualización de los datos de tabla de registros


for i in tabreg.first..tabreg.last loop
tabreg(i).col1:=tabreg(i).col1*2;
end loop;

-- uso del cursor


open ctabla2;
fetch ctabla2 bulk collect into tabreg;
close ctabla2;

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

En un comando FORALL, si alguna de las instrucciones SQL provoca un error de ejecución,


entonces todas las instrucciones ejecutadas dentro del bucle FORALL quedan anuladas
(ROLLBACK).

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

FORALL índice IN límite_inferior..límite_superior SAVE EXCEPTIONS


comando_SQL;

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).

La colección SQL%BULK_EXCEPTIONS es una colección de registros que da información acerca


de los errores que aparecen durante la ejecución de la instrucción FORALL.
SQL%BULK_EXCEPTIONS.COUNT da el número de sentencias SQL que han fallado y, para cada
índice i incluido entre 1 y SQL%BULK_EXCEPTIONS.COUNT, tenemos la siguiente información:

 SQL%BULK_EXCEPTIONS(i).ERROR_INDEX: número de la instrucción que ha fallado.


 SQL%BULK_EXCEPTIONS(i).ERROR_CODE: código del error.
c. Las cláusulas INDICES OF y VALUES OF

El recorrido de las listas no siempre es tan fácil como en el ejemplo anterior.

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>

Por el contrario, si se quiere recorrer simplemente un subconjunto de una colección entonces es


necesario utilizar la cláusula VALUES OF. Esta cláusula permite recuperar los índices desde otra
colección que debe ser de tipo NESTED TABLE o bien una tabla asociada a un índice numérico.
Esta colección es pues una colección de recorrido.

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.

Ejemplo de uso del atributo %BULK_ROWCOUNT:

SQL> SET SERVEROUTPUT ON


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 UPDATE componentes set nombre=LosNombres(i) WHERE numero=LosNumeros(i);
9 DBMS_OUTPUT.PUT_LINE(’Instrucción1: ’||TO_CHAR(SQL%BULK_ROWCOUNT(1))||’
filas modificadas’);
10 END;
11 /
Instrucción1: 9 filas modificadas

Procedimiento PL/SQL terminado correctamente.

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

... BULK COLLECT INTO nombre_colección [,nombre_colección, ...]

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> SET SERVEROUTPUT ON


SQL> DECLARE
2 TYPE tabla_numeros IS TABLE OF NUMBER(4);
3 LosClientes tabla_numeros;
4 BEGIN
5 SELECT numcli
6 BULK COLLECT INTO LosClientes
7 FROM clientes;
8 DBMS_OUTPUT.PUT_LINE (’Un número: ’||TO_CHAR(LosClientes(1)));
9 END;
10 /
Un número: 15

Procedimiento PL/SQL terminado correctamente.

SQL>

Por supuesto, se puede realizar el mismo tipo de operación con un cursor.

La mejora en el tiempo de ejecución de los bloques PL/SQL es espectacular para volúmenes de


datos importantes si se trabaja con las colecciones. Es fácil recuperar los datos de la tabla
mediante la instrucción BULK COLLECT. A continuación, el tratamiento de los datos se efectúa
directamente en la colección y finalmente las modificaciones se propagan en la tabla mediante
la instrucción FORALL para recorrer la colección.
4. LIMIT

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

FETCH ... BULK COLLECT INTO ... [LIMIT número_filas]

El número de filas tiene que ser un número entero.

Ejemplo

Uso de LIMIT: en el siguiente ejemplo, las filas se extraen en paquetes de 10.

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 /

Procedimiento PL/SQL terminado correctamente.

SQL>

5. Comparar las colecciones

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.

SQL> create or replace type Nombres


2 is table of varchar2(80);
3 /

Type created.

SQL>

A continuación, es necesario definir la cabecera del paquete.

SQL> CREATE OR REPLACE PACKAGE pkg_test IS


2 misAmigos Nombres:=Nombres(’Damian’,
3 ’Duran’,
4 ’Martin’);
5 susAmigos Nombres:=Nombres(’Damian’,
6 ’Dalmau’,
7 ’Sansos’,
8 ’Luis’,
9 ’Mariano’);
10 procedure mostrar(lista in Nombres);
11 end;
12 /

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> CREATE OR REPLACE PACKAGE BODY pkg_test IS


2 PROCEDURE mostrar(lista IN Nombres) IS
3 i NUMBER;
4 BEGIN
5 FOR i IN lista.FIRST..lista.LAST LOOP
6 DBMS _OUTPUT.PUT_LINE(TO_CHAR(i)||’--’||lista(i));
7 END LOOP;
8 END;
9 END;
10 /

Package body created.

SQL>

Ahora que la base está a punto, es posible ilustrar las instrucciones.

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

PL/SQL procedure successfully completed.

SQL>

El ejemplo anterior ilustra el resultado de la ejecución de la instrucción MULTISET UNION. Se


observa que Damian aparece dos veces, en primera y en cuarta posición.

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

PL/SQL procedure successfully completed.

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

PL/SQL procedure successfully completed.

SQL>

El ejemplo anterior permite obtener la lista de amigos comunes.

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

PL/SQL procedure successfully completed.

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

PL/SQL procedure successfully completed.

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.

Funciones y conjuntos de filas


Ahora es posible definir en PL/SQL funciones que aceptan parámetros de entrada y/o que
devuelven no un solo valor, sino un conjunto de filas. La ventaja de estas funciones es que ya
no es necesario almacenar los datos en una tabla temporal antes de llamar a la función para que
se ejecute. Estas funciones se pueden emplear en todos los casos en que es posible hacer
referencia a un nombre de tabla y, especialmente, en la cláusula FROM de una consulta SELECT.

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.

En la declaración de la función se añade la palabra clave PIPELINED en la cabecera y los datos


se devuelven mediante el comando PIPE ROW.

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:

SQL> -- creación del tipo


SQL> create type ImpLinea as object(
2 numlin number(2),
3 importe number(12,2)
4 );
5 /

Tipo creado.

SQL> -- creación de la tabla


SQL> create type ImpLineasTab as table of ImpLinea;
2 /

Tipo creado.

SQL> -- ejemplo de extracción en modo pipelined


SQL> create or replace function LineaVal (clin in SYS_REFCURSOR)
2 return ImpLineasTab pipelined is
3 out_mt ImpLinea:=ImpLinea(NULL, NULL);
4 vlin lineasped%rowtype;
5 vprecio number(12,2);
6 vimporte number(12,2);
7 BEGIN
8 loop
9 fetch clin into vlin;
10 exit when clin%notfound;
11 -- precio de cada artículo
12 select precio into vprecio
13 from articulos
14 where refart=vlin.refart;
15 -- cálculo del importe de la línea
16 vimporte:=vlin.cantped*vprecio;
17 -- creación del valor de retorno
18 out_mt.numlin:=vlin.numlin;
19 out_mt.importe:=vimporte;
20 -- devolver el valor
21 pipe row(out_mt);
22 end loop;
23 return;
24 END;
25 /

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.

Esta utilidad es completamente compatible dentro de Oracle. Sin embargo, la compatibilidad


descendente no está asegurada.

Esta utilidad recibe dos parámetros:

iname

Permite especificar el archivo que contiene el código PL/SQL que se va a cifrar.

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

wrap iname=archivo_entrada [oname=archivo_salida]

Ejemplo de uso de la utilidad Wrap

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.

Si no se gestiona la recuperación y presentación de los datos incluidos en el búfer y si la ejecución


no se realiza bajo SQL*Plus, los datos se ignoran. El principal interés de este paquete es facilitar
la depuración de los programas.

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á.

No es necesario llamar a este procedimiento cuando el parámetro SERVEROUTPUT se ha activado


desde SQL*Plus.

Sintaxis

DBMS_OUTPUT.ENABLE (tamaño_búfer IN INTEGER DEFAULT 20000) ;

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.

No es necesario llamar a este procedimiento cuando el parámetro SERVEROUTPUT se activa


desde SQL*Plus.

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.

El procedimiento PUT_LINE permite insertar automáticamente el carácter de fin de línea después


de cada adición de datos al búfer. Por el contrario, si se usa el procedimiento PUT, habrá que
incluir el carácter de fin de línea llamando al procedimiento NEW_LINE. Los procedimientos
GET_LINE y GET_LINES, que permiten leer los datos colocados en el búfer, solo son capaces de
leer las líneas de datos que terminan con un carácter de fin de línea.

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

Este procedimiento permite incluir un marcador de fin de línea en el búfer.

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)

Los parámetros son los siguientes:

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

Si la llamada se ha ejecutado correctamente, el estado toma el valor 0. Si toma el valor 1,


significa que el búfer no contiene más líneas de datos.

líneas

Es una tabla con tipos de datos VARCHAR2(32767).

num_líneas

Especifica el número de líneas de datos contenidas en la tabla.

En general, el paquete DBMS_OUTPUT se emplea para depurar funciones y procedimientos


almacenados ya que, desde SQL*Plus, la visualización de los datos incluidos en el búfer es
automática.

Ejemplo

Procedimiento que utiliza el paquete DBMS_OUTPUT:

SQL> CREATE OR REPLACE PROCEDURE cambiar_nombre


2 AS
3 BEGIN
4 UPDATE CLIENTES set nomcli=UPPER(nomcli);
5 DBMS_OUTPUT.PUT_LINE(’Operación realizada’);
6 END;
7 /

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

Procedimiento PL/SQL terminado correctamente.

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.

Es posible conocer la lista de directorios definidos en el servidor usando la


vista ALL_DIRECTORIES.

Sintaxis

CREATE OR REPLACE DIRECTORY nombre_directorio AS ’ruta’;


En el ejemplo de resumen del paquete se proporciona un ejemplo de cómo emplear esta
instrucción.

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.

No se pueden abrir más de 50 archivos simultáneamente.

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:

 r abre el archivo en modo lectura.


 w abre el archivo en modo escritura.
 a abre un archivo existente en modo de adición de datos.

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 puede generar las siguientes excepciones: INVALID_PATH, INVALID_MODE


oINVALID_OPERATION.

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

UTL_FILE.FCLOSE(ptr_archivo IN OUT FILE_TYPE);

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;

5. GET_LINE, GET_LINE_NCHAR, GET_RAW

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);

El procedimiento GET_LINE_NCHAR permite leer texto en formato UNICODE desde un archivo


abierto mediante FOPEN_NCHAR.

Sintaxis

UTL_FILE.GET_NCHAR(
ptr_archivo IN FILE_TYPE,
búfer OUT NVARCHAR2,
bytes_a_leer IN PLS_INTEGER DEFAULT NULL);

La operación GET_RAW permite leer datos de tipo RAW de un archivo.


Sintaxis

UTL_FILE.GET_LINE_RAW(
ptr_archivo IN FILE_TYPE,
búfer OUT NOCOPY RAW,
bytes_a_leer IN PLS_INTEGER DEFAULT NULL);

6. PUT, PUT_NCHAR, PUT_RAW

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);

El procedimiento PUT_NCHAR permite escribir una cadena de caracteres UNICODE en un archivo.


El tamaño máximo del búfer es de 32767 bytes. La sintaxis de este procedimiento es idéntica a
la de PUT, excepto en que el búfer es de tipo NVARCHAR2.

El procedimiento PUT_RAW posibilita la inserción de datos de tipo RAW en un archivo. Con el


tercer parámetro se puede especificar el vaciado automático del búfer.

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

Indica si el búfer debe escribirse en disco immediatamente.

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

Este carácter se reemplaza por el parámetro de tipo carácter que le corresponda.

\n

Este carácter incluye un marcador de fin de línea.

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);

-- escribir una línea completa


UTL_FILE.PUT_LINE(f_out,’línea 2’);
-- escritura de 2 líneas con formato
UTL_FILE.PUTF(f_out,’Buenos días\n Ejemplo del %s\n’,’procedimiento PUTF’);
UTL_FILE.FFLUSH(f_out);
-- cerrar el archivo
UTL_FILE.FCLOSE(f_out);
END;
/

El nombre del objeto DIRECTORY debe estar escrito en mayúsculas en la llamada a FOPEN.

El procedimiento PUTF_NCHAR permite escribir cadenas de caracteres UNICODE en el archivo


de destino.

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.

11. FSEEK, FGETPOS

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.

En el caso de un desplazamiento relativo, es el tercer parámetro (offset_relativo) el que contiene


el número de bytes que hay que desplazarse. Si este número es positivo, el desplazamiento es
hacia adelante; si el número es negativo, el desplazamiento se realizará hacia atrás.

Sintaxis

UTL_FILE.FSEEK(
ptr_archivo IN FILE_TYPE,
offset_absoluto IN PLS_INTEGER DEFAULT NULL,
offset_relativo IN PLS_INTEGER DEFAULT NULL);

La función FGETPOS permite conocer el desplazamiento correspondiente a la posición actual en


el archivo.

Sintaxis

UTL_FILE.FGETPOS(ptr_archivo IN FILE_TYPE)
RETURN PLS_INTEGER;

12. FREMOVE, FCOPY, FRENAME

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

Este procedimiento permite leer y devolver los atributos actuales de un archivo.

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

Ruta de acceso o nombre de archivo incorrectos.

INVALID_MODE

El modo de apertura del archivo especificado en FOPEN es incorrecto.

INVALID_FILEHANDLE

El descriptor de archivo no es válido.

INVALID_OPERATION

Se ha realizado una operación no válida con el archivo.

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

Error PL/SQL no especificado.

CHARSETMISMATCH

Se ha abierto un archivo usando el método FOPEN_NCHAR, pero las operaciones siguientes


utilizan las funciones PUTF o GET_LINE y no su equivalente NCHAR.

FILE_OPEN

La operación ha fallado, ya que el archivo ya estaba abierto.

INVALID_MAXLINESIZE

El valor del parámetro MAX_LINESIZE durante la ejecución de FOPEN es incorrecto. Este


parámetro debe tener un valor comprendido entre 1 y 32767.

INVALID_FILENAME

El nombre del archivo es incorrecto.

ACCESS_DENIED

Se ha denegado el permiso de acceso al archivo.

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

Se ha producido un fallo al intentar borrar el archivo.

RENAME_FAILED

Se ha producido un fallo al intentar cambiar el nombre del archivo.

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.

file_readonly CONSTANT BINARY_INTEGER :=0;


lob_readonly CONSTANT BINARY_INTEGER :=0;
lob_readwrite CONSTANT BINARY_INTEGER :=1;
lobmaxsize CONSTANT INTEGER :=18446744073709551615;
call CONSTANT PLS_INTEGER :=12;
session CONSTANT PLS_INTEGER :=10;

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);

6. CREATETEMPORARY, FREETEMPORARY, ISTEMPORARY

El procedimiento CREATETEMPORARY permite crear un objeto CLOB o BLOB temporal. El espacio


necesario se toma del espacio de tablas temporal.

El parámetro caché permite indicar si el LOB debe leerse o no desde el búfer.

El tercer parámetro permite indicar si el elemento es temporal para la sesión (opción


predeterminada) o para la llamada.

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 /

Procedimiento PL/SQL terminado correctamente.

SQL> spool off

7. ERASE

El objetivo de este procedimiento es borrar total o parcialmente un objeto LOB. En el caso de un


borrado parcial, debe especificarse el número de bytes que se desean borrar, así como la
dirección de inicio.

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.

8. FILEOPEN, FILECLOSE, FILECLOSEALL e ISOPEN

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);

Los procedimientos FILECLOSE y FILECLOSEALL permiten cerrar un determinado archivo o todos


los archivos correspondientes a objetos de gran tamaño (LOB) que se han utilizado en la sesión
con ayuda del paquete DBMS_LOB.

Sintaxis

DBMS_LOB.FILECLOSE(archivo IN OUT NOCOPY BFILE);


DBMS_LOB.FILECLOSEALL();

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.

La función devuelve 0 si el archivo no existe físicamente y 1 en caso contrario.

Sintaxis

DBMS_LOB.FILEEXISTS(ptr_archivo IN BFILE) RETURN INTEGER;

La función FILEISOPEN permite determinar si un puntero de archivo (objeto BFILE) corresponde


a un archivo abierto (el valor devuelto es 1) o no (el valor devuelto es 0).

Sintaxis

DBMS_LOB.FILEISOPEN(ptr_archivo IN BFILE) RETURN INTEGER;

10. FILEGETNAME

Este procedimiento permite conocer la ubicación y el nombre del archivo correspondiente a un


objeto de tipo BFILE. Este procedimiento no especifica en ningún caso si el directorio y el archivo
existen físicamente.

Sintaxis

DBMS_LOB.FILEGETNAME(
archivo IN BFILE,
directorio OUT VARCHAR2,
nombrearchivo OUT VARCHAR2);

11. FRAGMENT_DELETE, FRAGMENT_INSERT, FRAGMENT_MOVE,


FRAGMENT_REPLACE

Estos procedimientos permiten manipular fácilmente fragmentos de LOB:

 Eliminar un determinado número de bytes o de caracteres a partir de una posición dada;


 Insertar datos a partir de una posición dada;
 Mover un determinado número de bytes o caracteres a partir de una posición dada hasta
una nueva posición;
 Sustituir un determinado número de bytes o caracteres a partir de una posición dada por
nuevos datos.

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);

12. GETLENGTH, GETCHUNKSIZE

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);

14. LOADFROMFILE, LOADBLOBFROMFILE, LOADCLOBFROMFILE

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:

SQL> -- creación de la tabla de destinos


SQL> create table misfotos (
2 id number,
3 img blob);

Tabla creada.

SQL> create sequence seq_id_fotos;

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 /

Procedimiento PL/SQL terminado correctamente.


SQL>

15. OPEN

Este procedimiento permite abrir un elemento LOB en el modo especificado (lob_readonly o


lob_readwrite) en el segundo parámetro.

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

Este procedimiento permite reducir el tamaño de un elemento LOB al número de bytes o de


caracteres especificado en el parámetro nuevo_tamaño.

Sintaxis

DBMS_LOB.TRIM(
lob_origen IN OUT NOCOPY {BLOB|CLOB CHARACTER SET ANY_CS},
nuevo_tamaño IN INTEGER);

19. WRITE, WRITEAPPEND

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

Las principales excepciones del paquete DBMS_LOB son:

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

Intento de escritura en un objeto LOB que sobrepasa el tamaño límite.

NOEXIST_DIRECTORY

El elemento de tipo DIRECTORY no existe para el archivo actual.

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

La referencia al directorio (DIRECTORY) no es válida en el caso de un primer acceso, o bien el


administrador de bases de datos ha modificado su definición desde su último uso.

OPERATION_FAILED

La operación ha fallado.

UNOPENED_FILE

El archivo no está abierto.

OPEN_TOOMANY

El número de archivos abiertos simultáneamente ha alcanzado el límite superior, por lo que es


necesario cerrar algunos archivos para poder continuar.
Introducción
A partir de la versión 8i del sistema RDBMS de Oracle, el lenguaje Java está totalmente integrado
en el motor de la base de datos. Por tanto, es posible escribir código Java que se almacenará y
ejecutará directamente en la base de datos.

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.

La versión del JDK viene determinada por la versión de Oracle utilizada.

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.

El lenguaje Java puede emplearse en la escritura de procedimientos, funciones y disparadores


(triggers) de base de datos.

Las ventajas de los procedimientos almacenados son numerosas. Las más importantes son:

 rendimiento: el código ejecutable lo gestiona el servidor y se mantiene en la memoria del


mismo.
 facilidad de implementación e implantación: todos los usuarios acceden al mismo código.
 seguridad: utilizando los mecanismos de seguridad de Oracle, es posible obligar a los
usuarios a manipular los datos a través de los procedimientos almacenados y no tener
que conceder ningún otro privilegio sobre las tablas a las que acceden dichos
procedimientos.

En este capítulo solo se aborda el desarrollo de procedimientos almacenados escritos en Java. El


desarrollo de aplicaciones Java completas para bases de datos de Oracle queda fuera del ámbito
de este libro.
Las siguientes secciones exponen las capacidades básicas de Oracle9i a la hora de trabajar con
procedimientos almacenados Java. Este capítulo no puede considerarse una introducción a Java
y se supone que el lector ya dispone de ciertos conocimientos sobre dicho lenguaje.

Cómo cargar procedimientos almacenados


Antes de poder usar los procedimientos, deben cargarse en la base de datos. La carga de
procedimientos y su publicación constituyen dos etapas diferentes. Hay muchas clases Java que
se cargan y nunca se publican, ya que no presentan interfaz de usuario.

En esta situación, el usuario es un programador de PL/SQL.

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.

Este problema se explica en el siguiente ejemplo:


En este ejemplo, los dos usuarios Pedro y Ana utilizan el mismo procedimiento almacenado Java
(Análisis) que se aplica a la tabla Ventas. Dado que el procedimiento almacenado se ejecuta
usando los permisos concedidos al usuario que lo ejecuta, accede a las tablas que el usuario
posee. Por tanto, en este caso, el mismo código se comparte para analizar dos tablas totalmente
diferentes.

3. La utilidad loadjava

Sintaxis

loadjava {-user| -u} nombre_usuario /contraseña[@servicio] [opciones]


nombre_archivo.java | nombre_archivo.sqlj | nombre_archivo.class |
nombre_archivo.jar | nombre_archivo.zip | ...

Opciones (lista no exhaustiva)

-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

Permite generar datos de depuración. Esta opción es similar a javac -g.

-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

Permite conceder permisos de ejecución al procedimiento después de cargarlo. Esta acción es


similar a la de la instrucción SQL 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.

Las opciones -oci y -thin son mutuamente excluyentes.

-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

Activa el modo verboso, es decir, se muestran los mensajes de progreso.

Ejemplo

El código fuente:

import java.sql.*;
import java.io.*;
import oracle.jdbc.driver.*;

public class DropGeneral{


public static void borrar(String tipo, String nombre) throws SQLException{
//Conectarse a la base de datos utilizando el controlador JDBC
Connection conn=new OracleDriver().defaultConnection();
//Crear la instrucción SQL
String consulta;
consulta="Drop"+tipo+""+nombre;
try{
Statement stmt=conn.createStatement();
stmt.execute(consulta);
stmt.close();
}catch(SQLException e){System.err.println(e.getMessage());}
}
}

La clase se carga en la base de datos.

Uso de loadjava para cargar la clase en el esquema del usuario actual:

F:\o9i>loadjava -user scott/tiger@helios:1521:en1 -v -r -t DropGeneral.java


arguments: ’-user’ ’scott/tiger@helios:1521:en1’ ’-v’ ’-r’ ’-t’
’DropGeneral.java’
creating: source DropGeneral
loading: source DropGeneral
creating: DropGeneral
resolving: source DropGeneral
F:\o9i>

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

dropjava {-user| -u} nombre_usuario /contraseña[@servicio] [opciones]


nombre_archivo.java | nombre_archivo.sqlj | nombre_archivo.class |
nombre_archivo.jar | nombre_archivo.zip | ...

Opciones (lista no exhaustiva)

-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

Supresión de la clase desde el esquema del usuario actual:

F:\o9i>dropjava -u scott/tiger@helios:1521:en1 -t DropGeneral


F:\o9i>

5. El acceso a los datos

Independientemente de que el programa Java se ejecute en el equipo cliente o en el servidor de


base de datos, como en este caso, siempre se plantea el problema del acceso a los datos. Con
Java, Oracle ofrece dos soluciones diferentes de acceso a los datos. Puede emplearse la solución
clásica JDBC, que es la que resulta más familiar, siendo esa familiaridad su principal
ventaja. SQLJ ofrece una alternativa a esta solución. Con esta técnica, los comandos SQL se
introducen directamente en el programa Java. A continuación, el archivo se guarda con la
extensión sqlj en lugar de con la extensión java.

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

La implementación de una solución JDBC va a permitir utilizar herramientas conocidas e


independientes de la base de datos Oracle. Este método está especialmente bien adaptado al
desarrollo de herramientas cliente en Java que no deban integrarse de forma demasiado
restrictiva con la base de datos de Oracle.

En la escritura de procedimientos almacenados, la sintaxis de JDBC puede resultar un poco ardua


en comparación con SQLJ.

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;
}
}
}

A continuación, debe compilarse el archivo sqlj para generar el archivo class:


sqlj Contadores.sqlj

Por último, el archivo class tiene que cargarse en la base de datos mediante la utilidad loadjava.

loadjava -user scott/tiger@bdeni -v Contadores.class

Publicación de procedimientos almacenados


Antes de poder utilizar directamente un procedimiento almacenado Java desde SQL, hay que
registrar las referencias a este procedimiento en el diccionario de datos. Esta operación no se
realiza de forma automática, ya que el motor de Oracle no puede saber qué métodos serán
accesibles desde SQL.

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.

1. Correspondencia entre tipos de datos

La correspondencia entre los tipos de datos SQL y Java se rige por la siguiente tabla.

Tipo SQL Clase Java

CHAR - NCHAR - LONG - VARCHAR2 - NVARCHAR2 oracle.sql.CHAR


java.lang.String
java.sql.Date
java.sql.Time
java.sql.Timestamp
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.lang.BigDecimal
byte - short - int - long - float - double

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

RAW - LONG RAW oracle.sql.RAW


byte[ ]

ROWID oracle.sql.CHAR
oracle.sql.ROWID
java.lang.String

BFILE oracle.sql.BFILE

BLOB oracle.sql.BLOB
oracle.jdbc2.Blob

CLOB - NCLOB oracle.sql.CLOB


oracle.jdbc2.Clob

OBJECT oracle.sql.STRUCT
oracle.jdbc2.Struct

REF oracle.sql.REF
oracle.jdbc2.Ref

TABLE - VARRAY oracle.sql.ARRAY


oracle.jdbc2.ArrayArray

Creación de una función Java o de un procedimiento Java

Sintaxis

CREATE [OR REPLACE]


{PROCEDURE nombre_procedimiento [(parámetro, ...)]
| FUNCTION nombre_función [(parámetro, ...)] RETURN type_sql}
[AUTHID {DEFINER|CURRENT_USER}]
[PARALLEL_ENABLE]
[DETERMINISTIC]
{AS | IS } LANGUAGE JAVA
NAME ’nombre_metodo_java (parámetro_java,...)’;

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

Cuando el resultado de la función no depende de ninguna variable de sesión, el optimizador


puede reutilizar el resultado obtenido en una llamada anterior al método en la que se utilizarán
los mismos parámetros.

Ejemplos

Definición del procedimiento asociado con el método Borrar:

SQL*Plus: Release 9.2.0.1.0 - Production on Jue Ene 2 14:10:43 2003

Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

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

SQL> CREATE OR REPLACE PROCEDURE borrar(


2 tipo varchar2, nombre varchar2)
3 AS LANGUAGE JAVA
4 NAME ’DropGeneral.borrar(java.lang.String, java.lang.String)’;
5 /

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.*;

public class Contador{


public static int cuenta(String nombre) throws SQLException{
Connection conn=new OracleDriver().defaultConnection();
String consulta="Select count(*) from "+nombre;
int numero=0;
try{
Statement stmt=conn.createStatement();
ResultSet rset=stmt.executeQuery(consulta);
while (rset.next()) {numero=rset.getInt(1);}
rset.close();
stmt.close();
}catch(SQLException e) {System.err.println(e.
getMessage());}
return numero;
}
}

Mediante la utilidad loadjava, la clase se puede cargar en la base de datos.

A continuación se crea una función de tipo PL/SQL para poder emplear la función Java en la base
de datos.

Definición de la función asociada con el método Contador:

SQL*Plus: Release 9.2.0.1.0 - Production on Jue Ene 2 14:10:43 2003


Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.

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

SQL> CREATE OR REPLACE FUNCTION cuenta(nom_tabla varchar2)


2 RETURN NUMBER
3 AS LANGUAGE JAVA NAME ’Contador.cuenta(java.lang.String) return int’;
4 /

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

CREATE [OR REPLACE] [AND {COMPILE|RESOLVE}]


JAVA {{SOURCE|RESOURCE}NAMED nombre_procedimiento | CLASS}
{AS cod_fuente_java|USING BFILE(directorio,archivo)};

La sintaxis anterior es un extracto de la sintaxis completa de la instrucción CREATE JAVA. Esta


sintaxis servirá en la mayoría de los casos, aunque puede completarse para utilizar datos de tipo
BLOB, CLOB o BFILE, o cuando el procedimiento deba crearse en un esquema diferente al del
usuario actual.

Ejemplo

El siguiente ejemplo muestra la implementación de una función Java usando la instrucción


CREATE JAVA:
create or replace and compile java source named "Cuenta" as
public class Cuenta{
public static int Cuenta(int a, int b){
int resultado;
resultado=a+b;
return resultado;
}
};

En el siguiente ejemplo, se carga un archivo class en la base de datos empleando la instrucción


CREATE JAVA:

create or replace directory bfile_dir as ’c:\O9i’;

create or replace java class using bfile (bfile_dir,’Contadores.class’);


/

Uso de procedimientos almacenados


Una vez cargados y publicados los procedimientos almacenados escritos en Java ya es posible
utilizarlos. El objetivo de esta sección es mostrar los diferentes medios que existen para invocar
a los procedimientos Java.

1. Llamada a un procedimiento Java desde SQL*Plus

La instrucción CALL

La instrucción CALL permite llamar desde el indicador de PL/SQL a un procedimiento almacenado


Java que se haya publicado como función, procedimiento o elemento de un paquete.

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

Uso de la función Cuenta para conocer el número de clientes presentes en la tabla:

SQL> variable numero number


SQL> call cuenta(’CLIENTES’) into:numero;

Llamada terminada.

SQL> print numero

NUMERO
----------
13

SQL>

Creación de la tabla TTEST y eliminación de la misma a continuación usando el procedimiento


Java Borrar:

SQL> create table TTEST (col1 char(5));

Tabla creada.

SQL> call borrar(’TABLE’,’TTEST’);

Llamada terminada.

SQL> desc TTEST


ERROR:
ORA-04043: el objeto TTEST no existe

SQL>

Cómo redirigir la salida

Determinados procedimientos almacenados Java emplean el dispositivo estándar de error


(System.err) o de salida (System.out) para mostrar determinados datos. Estos dispositivos se
pueden redirigir a SQL*Plus utilizando los dos comandos siguientes:

SET SERVEROUTPUT ON [SIZE tamaño]


CALL dbms_java.set_output(tamaño)
Con estos comandos, los datos se muestran una vez que el procedimiento se ha terminado de
ejecutar. El parámetro tamaño, cuyo valor predeterminado es 2000 bytes, permite precisar el
tamaño del búfer. Este tamaño no puede ser mayor de 1.000.000 bytes.

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.*;

public class Mostrar{


public static void leerClientes() throws SQLException{
Connection conn=new OracleDriver().defaultConnection();
String consulta="Select nomcli from clientes";
try{
Statement stmt=conn.createStatement();
ResultSet rs=stmt.executeQuery(consulta);
while (rs.next()){
System.out.println(rs.getString(1));
}
rs.close();
stmt.close();
}catch(SQLException e){System.err.println(e.getMessage());}
}
}

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:

SQL> CREATE PROCEDURE nomClientes


2 AS LANGUAGE JAVA
3 NAME ’Mostrar.leerClientes()’;
4 /

Procedimiento creado.

SQL>

Uso del procedimiento desde SQL*Plus:

SQL> SET SERVEROUTPUT ON SIZE 5000


SQL> call dbms_java.set_output(5000);

Llamada terminada.

SQL> call nomClientes();


Gómez S.A.
M. García
Martín Juan
Del Pino S.A.
Lacalle
Martín Juan
E. Lacalle
Torres

Llamada terminada.

SQL>

2. Llamada de un procedimiento Java desde un disparador de


base de datos

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:

SQL> CREATE OR REPLACE PROCEDURE ACTALMACEN(


2 ref CHAR, cantidad number)
3 AS LANGUAGE JAVA
4 NAME ’Disparador.actalmacen(Java.lang.String,int)’;
5 /

Procedimiento creado.

SQL>

El disparador se aplica a la tabla LINPEDIDOS y se asocia a la instrucción INSERT. El disparador


se ejecuta para cada fila creada. Creación del disparador:

SQL> CREATE OR REPLACE TRIGGER tr_af_ins_linpedidos


2 AFTER INSERT ON LINPEDIDOS
3 FOR EACH ROW
4 CALL ACTALMACEN(:new.refart, :new.cantped)
5 /
Disparador creado.

SQL>

3. Llamada a un procedimiento Java desde una instrucción SQL


DML o un bloque PL/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

Creación de la clase Pedidos:

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());}
}
}

La clase se carga en la base de datos mediante el comando Loadjava. El paquete correspondiente


se creará en dos etapas. En primer lugar, se define la cabecera del paquete:

SQL> CREATE OR REPLACE PACKAGE pkg_pedidos AS


2 FUNCTION importe (numped NUMBER) RETURN NUMBER;
3 PROCEDURE suministro (numped NUMBER);
4 PROCEDURE saldado (numped NUMBER);
5 END pkg_pedidos;
6 /

Paquete creado.

SQL>

A continuación se define el cuerpo del paquete.

SQL> CREATE OR REPLACE PACKAGE BODY pkg_pedidos AS


2 FUNCTION importe (numped NUMBER) RETURN NUMBER
3 AS LANGUAGE JAVA
4 NAME ’Pedidos.importe(int) return float’;
5 PROCEDURE suministro (numped NUMBER) AS LANGUAGE JAVA
6 NAME ’Pedidos.suministro(int)’;
7 PROCEDURE saldado (numped NUMBER) AS LANGUAGE JAVA
8 NAME ’Pedidos.saldado(int)’;
9 END pkg_pedidos;
10 /

Cuerpo del paquete creado.

SQL>

El uso de un procedimiento o de una función de este paquete es completamente idéntico al de


un paquete escrito en PL/SQL.

Ejemplo

Uso de la función Importe para calcular el importe del pedido número 1:

SQL> select pkg_pedidos.importe(1) from dual;

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 analizador se encuentra en el directorio $ORACLE_HOME\xdk\plsql\parser y se incluye como


estándar desde la versión 9i.

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.

Para comprender el funcionamiento del analizador, evidentemente, el método más sencillo


consiste en emplear un programa simple de ejemplo. No se ilustran todas las funcionalidades
del analizador pero, a partir de un ejemplo funcional, siempre es posible completar los elementos
omitidos de forma relativamente sencilla.

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.

-- Este procedimiento permite mostrar los diferentes elementos


del documento xml
create or replace procedure MostrarElementos(doc xmlDom.DOMDocument) is
Nodos xmlDom.DOMNodeList;
longitud number;
nodo xmlDom.DOMNode;
begin
-- obtener todos los elementos del documento
Nodos:=xmlDom.getElementsByTagName(doc,’*’);
longitud :=xmlDom.getLength(Nodos);

-- recorrer todos los elementos usando un bucle


for i in 0 ..longitud -1 loop
nodo:=xmlDom.item(Nodos, i);
dbms_output.put(xmlDom.getNodeName(nodo)||’ ’);
end loop;
-- analizar la siguiente línea
dbms_output.put_line(’ ’);
end;
/
show errors;

create or replace procedure mostrarAtributos(doc xmlDom.DOMDocument) is


Nodos xmlDom.DOMNodeList;
lg1 number;
lg2 number;
nodo xmlDom.DOMNode;
elemento xmlDom.DOMElement;
Atributos xmlDom.DOMNamedNodeMap;
nomAtr varchar2(100);
valorAtr varchar2(100);
begin

-- obtener todos los elementos


Nodos:=xmlDom.getElementsByTagName(doc,’*’);
lg1:=xmlDom.getLength(Nodos);

-- recorrer todos los elementos


for i in 0..lg1-1 loop
nodo:=xmldom.item(Nodos, i);
elemento:=xmldom.makeElement(nodo);
-- nombre de la etiqueta
dbms_output.put_line(xmldom.getTagName(elemento)||’:’);
-- obtener todos los atributos de este elemento
Atributos :=xmldom.getAttributes(nodo);

if (xmldom.isNull(Atributos)= FALSE) then


lg2:=xmldom.getLength(Atributos);

-- recorrer todos los atributos


for j in 0..lg2-1 loop
nodo:=xmldom.item(Atributos,j);
nomAtr := xmldom.getNodeName(nodo);
valorAtr := xmldom.getNodeValue(nodo);
dbms_output.put(’ ’||nomAtr||’=’||valorAtr);
end loop;
dbms_output.put_line(’ ’);
end if;
end loop;
end;
/
show errors;
create or replace procedure leerxml(directorio in varchar2,
archivo in varchar2) is
p xmlparser.parser;
doc xmldom.DOMDocument;
begin
-- nuevo analizador
p:=xmlparser.NewParser;

-- definición de algunas características del analizador


xmlParser.SetValidationMode(p,FALSE);
xmlParser.setBaseDir(p, directorio);

--analizar el archivo XML


xmlParser.Parse(p, archivo);

-- obtener el documento
doc:=xmlParser.GetDocument(p);

-- mostrar los diferentes elementos


dbms_output.put_line(’Los elementos del documento son: ’);
MostrarElementos(doc);

-- mostrar los atributos de cada elemento


dbms_output.put_line(’Los atributos de los elementos son:’);
MostrarAtributos(doc);

-- liberar el documento
xmlDom.freeDocument(doc);
-- liberar el analizador
xmlParser.freeParser(p);
end;
/
show errors;

El procedimiento leerXml permite leer y analizar un documento XML. El documento XML se


especifica como parámetro del procedimiento:
<?xml version ="1.0" standalone="no"?>
<!DOCTYPE equipo SYSTEM "equipo.dtd">
<nombre equipo="US Postal" pais="USA">
<corredor numero="001">ARMSTRONG</corredor>
<corredor numero="002">EKIMOV</corredor>
<corredor numero="003">HERAS</corredor>
<corredor numero="004">HINCAPIE</corredor>
<corredor numero="005">JOACHIM</corredor>
<corredor numero="006">LANDIS</corredor>
<corredor numero="007">PADRNOS</corredor>
<corredor numero="008">PENA</corredor>
<corredor numero="009">RUBIERA</corredor>
</equipo>

La ejecución del procedimiento y el resultado del mismo son los siguientes:

SQL> set serveroutput on


SQL> execute leerXml(XML DIR,’equipo.xml’,);
Los elementos del documento son:
equipo corredor corredor corredor corredor corredor corredor corredor corredor
Los atributos de los elementos son:
nombre:
equipo=US Postal pais=USA
corredor:
numero=001
corredor:
numero=002
corredor:
numero=003
corredor:
numero=004
corredor:
numero=005
corredor:
numero=006
corredor:
numero=007
corredor:
numero=008
corredor:
numero=009

Procedimiento PL/SQL terminado correctamente.

SQL>

XML_DIR es el nombre de un objeto DIRECTORY que se corresponde con el directorio en el que


se almacena el archivo equipo.xml.

Aplicación de una hoja de estilos a un documento XML


Una de las principales ventajas del lenguaje XML es la de poder separar de forma muy clara los
datos de la presentación, lo que también es posible hacer en HTML. El siguiente ejemplo, que
utiliza las funcionalidades del analizador XML para PL/SQL, permite generar un archivo de salida.
xslProcessor es un sinónimo público del paquete DBMS_XSLPROCESSOR.

set serveroutput on;


create or replace procedure aplicarXSL(
directorio varchar2, archivoXml varchar2,
archivoXsl varchar2, archivoResultado varchar2,
) is
-- las variables
p xmlParser.Parser;
-- el analizador
documentoXML xmlDom.DOMDocument; -- documento
nodo xmlDom.DOMNode;
---- elementos para la hoja de estilos
motor xslProcessor.Processor;
hojaEstilo xslProcessor.Stylesheet;
documentoXSL xmlDom.DOMDocument;
elementoXsl xmlDom.DOMElement;

espacioNombre varchar2(50);
-- elementos para generar el resultado
documentoF xmlDom.DOMDocumentFragment;
elementoF xmlDom.DomNode;

begin
-- creación de un nuevo analizador
p:=xmlParser.newParser;

-- definición de algunas características de funcionamiento


xmlParser.setValidationMode(p,FALSE); -- sin validación del documento
xmlParser.setPreserveWhiteSpace(p, TRUE); -- conservar los espacios
xmlParser.setBaseDir(p, directorio); -- directorio de trabajo

-- análisis del documento XML


xmlParser.parse(p, archivoXml);

-- obtención del documento


documentoXml:=xmlParser.getDocument(p);

-- análisis del documento XML


xmlParser.parse(p, archivoXsl);

-- obtener el documento
documentoXsl:=xmlParser.getDocument(p);

-- obtener los nodos de la hoja de estilos


elementoXsl:= xmlDom.getDocumentElement(documentoXsl);

-- obtener el espacio de nombres


espacioNom:=xmlDom.getNamespace(elementoXsl);

-- crear la hoja de estilos


hojaEstilo:=xslProcessor.newStylesheet(documentoXsl,directorio||’\’||
archivoXsl);

-- aplicar la hoja de estilos


motor :=xslProcessor.newProcessor;
xslProcessor.showWarnings(motor, true);

-- generación del documento final


documentoF:=xslProcessor.processXSL(motor, hojaEstilo, documentoXML);
elementoF:=xmlDom.makeNode(documentoF);
xmlDom.writeTofile(elementoF, archivoResultado);
end;
/
show errors

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.

La llamada al procedimiento puede realizarse del siguiente modo:

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.

1. Generación de código XML con DBMS_XMLQuery

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:

 Crear un puntero a un contexto llamando al método DBMS_XMLQuery.getCtx y pasándole


como parámetro la consulta.
 Introducir los valores de los distintos parámetros de la consulta
usando DBMS_XMLQuery.bind.
 Definir los argumentos opcionales, como el nombre de la etiqueta ROW o ROWSET, el
número de filas que se van a extraer...
 Escribir los datos XML en un elemento CLOB (LOB de caracteres) usando la
funciónDBMS_XMLQuery.getXML. Esta función puede trabajar con o sin un archivo DTD o
un esquema.
 Cerrar el contexto.
a. Generación de código XML a partir de una consulta

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);

-- cerrar el contexto de la consulta


DBMS_XMLQuery.closeContext(contextConsulta);
end;
/

Con el fin de facilitar la presentación de los elementos en formato CLOB, se ha escrito el método
mostrarCLOB:

create or replace procedure mostrarClob(cadena in out nocopy CLOB) is


cadenaXml varchar2(32767);
linea varchar2(2000);
begin
-- copiar el documento CLOB en un VARCHAR2
cadenaXml:=dbms_lob.SUBSTR(cadena, 32767);
loop
exit when cadenaXml is null;
-- Búsqueda de los finales de línea
linea:=substr(cadenaXml,1,instr(cadenaXml,chr(10))-1);
dbms_output.put_line(’| ’||linea);
cadenaXml:=substr(cadenaXml, instr(cadenaXml,chr(10))+1);
end loop;
end;
/

La ejecución de este script proporciona el siguiente resultado:

<?xml version = ’1.0’?>


<ROWSET>
<ROW num="1">
<NUMCLI>1</NUMCLI>
<APELLIDO>RAMOS</APELLIDO>
<NOMBRE>Guillermo</NOMBRE>
<DIRECCION>C/ ENI</DIRECCION>
<TEL>935777777</TEL>
</ROW>
<ROW num="2">
<NUMCLI>2</NUMCLI>
<APELLIDO>LACALLE</APELLIDO>
<NOMBRE>Maria</NOMBRE>
<DIRECCION>C/ Paredes</DIRECCION>
<TEL>935777777</TEL>
</ROW>
<ROW num="3">
<NUMCLI>3</NUMCLI>
<APELLIDO>MARTIN</APELLIDO>
<NOMBRE>Bruno</NOMBRE>
<DIRECCION>C/ Mayor</DIRECCION>
<TEL>935777777</TEL>
</ROW>
<ROW num="4">
<NUMCLI>4</NUMCLI>
<APELLIDO>GAMEZ</APELLIDO>
<NOMBRE>Jeronimo</NOMBRE>
<DIRECCION>C/ Madrid</DIRECCION>
<TEL>935777777</TEL>
</ROW>
</ROWSET>

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.

Ahora el script para generar código XML será como sigue:

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’);

--modificación del nombre de la etiqueta ROW


DBMS_XMLQuery.setRowTag(contextConsulta,’CLIENTE’);

--modificación del nombre de la etiqueta ROWSET


DBMS_XMLQuery.setRowSetTag(contextConsulta,’CLIENTES’);

-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);

-- mostrar el resultado
mostrarCLOB(resultado);

-- cerrar el contexto de la consulta


DBMS_XMLQuery.closeContext(contextConsulta);
end;
/

Y el resultado de la ejecución del script es el siguiente:

<?xml version = ’1.0’?>


<CLIENTES>
<CLIENTE num="1">
<NUMCLI>1</NUMCLI>
<APELLIDO>RAMOS</APELLIDO>
<NOMBRE>Guillermo</NOMBRE>
<DIRECCION>C/ ENI</DIRECCION>
<TEL>935777777</TEL>
</CLIENTE>
<CLIENTE num="2">
<NUMCLI>2</NUMCLI>
<APELLIDO>LACALLE</APELLIDO>
<NOMBRE>Maria</NOMBRE>
<DIRECCION>C/ Paredes</DIRECCION>
<TEL>935777777</TEL>
</CLIENTE>
<CLIENTE num="3">
<NUMCLI>3</NUMCLI>
<APELLIDO>MARTIN</APELLIDO>
<NOMBRE>Bruno</NOMBRE>
<DIRECCION>C/ Mayor</DIRECCION>
<TEL>935777777</TEL>
</CLIENTE>
<CLIENTE num="4">
<NUMCLI>4</NUMCLI>
<APELLIDO>GAMEZ</APELLIDO>
<NOMBRE>Jeronimo</NOMBRE>
<DIRECCION>C/ Madrid</DIRECCION>
<TEL>935777777</TEL>
</CLIENTE>
</CLIENTES>

c. Limitación del número de filas

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’);

--modificación del nombre de la etiqueta ROW


DBMS_XMLQuery.setRowTag(contextConsulta,’CLIENTE’);

--modificación del nombre de la etiqueta ROWSET


DBMS_XMLQuery.setRowSetTag(contextConsulta,’CLIENTES’);

-- definición del número filas por documento XML


DBMS_XMLQuery.setMaxRows(contextConsulta,10);
DBMS_XMLQuery.setRaiseNoRowsException(contextConsulta, true);

-- extracción de los datos


begin
loop -- bucle infinito
-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);

-- mostrar el resultado
mostrarCLOB(resultado);
end loop;
exception
when others then
null; --salir del bloque en caso de error
end;

-- cierre del contexto de la consulta


DBMS_XMLQuery.closeContext(contextConsulta);
end;
/

d. Hojas de estilo

La API XSU permite utilizar hojas de estilo en la generación de documentos XML.

El procedimiento setStyleSheetHeader() permite añadir la referencia a la hoja de estilos


en la cabecera del documento resultante.

El procedimiento useStyleSheet() permite aplicar la hoja de estilos directamente al


documento resultante.

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 (:).

El método setBindValue permite especificar el valor que tomará un parámetro. Lógicamente,


es necesario inicializar el conjunto de parámetros antes de solicitar la primera generación del
documento XML. Sin embargo, entre dos solicitudes de generación de documento, no es preciso
reinicializar todos los parámetros, sino solamente aquellos que hayan cambiado.

Ejemplo

El siguiente ejemplo ilustra la implementación de consultas parametrizadas para trabajar con la


API XSU. Se generan dos documentos XML, correspondiendo cada uno de ellos a un determinado
cliente, pero solo se establece un contexto XSU, ya que los datos proceden de la misma consulta,
que dispone de un parámetro de restricción.

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’);

-- especificar el valor del parámetro


DBMS_XMLQuery.setBindValue(contextConsulta,’numero’,15);

-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);
-- mostrar el resultado
mostrarCLOB(resultado);

-- especificar otro valor para el parámetro


DBMS_XMLQuery.setBindValue(contextConsulta,’numero’,20);

-- obtener el resultado
resultado:= DBMS_XMLQuery.getXML(contextConsulta);
-- mostrar el resultado
mostrarCLOB(resultado);
-- cierre del contexto de la consulta
DBMS_XMLQuery.closeContext(contextConsulta);
end;
/

3. Almacenamiento de datos en formato XML con


DBMS_XMLSave

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:

 Creación de un contexto de ejecución mediante la función DBMS_XMLSave.getCtx. Esta


función recibe como parámetro el nombre de la tabla sobre la que se realizarán las
operaciones de inserción (INSERT), borrado (DELETE) o actualización (UPDATE).
 Si el documento XML se utiliza como soporte en la adición de datos (INSERT) a la tabla,
es posible especificar las columnas para las que se van a suministrar valores mediante la
función setUpdateColNames. Por omisión, los valores se proporcionan para todas las
columnas de la tabla.
 Si el documento XML se emplea como soporte de una operación de actualización de datos
(UPDATE), hay que proporcionar la o las columnas que se van a utilizar, con el fin de
identificar de forma exacta los datos que hay que modificar. También se pueden especificar
la o las columnas que se van a actualizar.
 Si el documento XML se emplea como soporte de una operación de borrado (DELETE), se
pueden especificar la o las columnas que se utilizarán con el fin de identificar de forma
precisa los datos que hay que eliminar. Por omisión, todos los datos del documento XML
sirven para identificar los datos que se van a eliminar.
 Proporcionar un documento XML a uno de los métodos insertXML, updateXML o deleteXML
para llevar a cabo la operación deseada con el documento XML.
 Cerrar el contexto.
a. Adición de datos

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

El siguiente ejemplo ilustra el uso de la función insertXML:

create or replace procedure agregar(documentoXML in CLOB, nomTabla


in varchar2) is
contextAgregar DBMS_XMLSave.ctxType;
numFilas number;
begin
-- creación del contexto de inserción
contextAgregar:=DBMS_XMLSave.newContext(nomTabla);

-- añadir filas
numFilas:=DBMS_XMLSave.insertXML(contextAgregar, documentoXML);

-- cerrar el contexto
DBMS_XMLSave.closeContext(contextAgregar);
end;
/

El documento XML usado para agregar los datos es:

<?xml version = ’1.0’?>


<ROWSET>
<ROW num="1">
<NUMCLI>200</NUMCLI>
<NOMCLI>E. GONZALEZ</NOMCLI>
<COD_POSTAL>28000</COD_POSTAL>
<CIUDAD>MADRID</CIUDAD>
</ROW>
</ROWSET>

La llamada al procedimiento se realiza del siguiente modo:

-- establecer el directorio
create or replace directory "xml_dir" as ’C:\xml’;

-- carga de los datos


declare

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

-- tamaño del archivo


tamaño:=dbms_lob.getlength(archivo_in);

-- leer los datos y almacenarlos en una variable


contexto_idioma:=1;
dbms_lob.createtemporary(dest_clob, true);
dbms_lob.loadclobfromfile(dest_clob,
archivo_in,
tamaño,
inicio_destino,
inicio_origen,
juego_caracteres,
contexto_idioma,
aviso);

-- cerrar el archivo
dbms_lob.fileclose(archivo_in);

-- llamar al procedimiento para agregar datos


agregar(dest_clob, ’CLIENTES’);
-- validar las modificaciones
commit;

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;

-- variables para la adición de datos


contextAgregar DBMS_XMLSave.ctxType;
numFilas number;

begin
archivo_in:= bfilename(’xml_dir’,’datos2.xml’);

-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);

-- tamaño del archivo


tamaño:=dbms_lob.getlength(archivo_in);

-- leer los datos y almacenarlos en una variable


contexto_idioma:=1;
dbms_lob.createtemporary(documentoXML, true);
dbms_lob.loadclobfromfile(documentoXML,
archivo_in,
tamaño,
inicio_destino,
inicio_origen,
juego_caracteres,
contexto_idioma,
aviso);

-- cerrar el archivo
dbms_lob.fileclose(archivo_in);

-- creación del contexto de inserción


contextAgregar:=DBMS_XMLSave.newContext(’CLIENTES’);
-- borrar los parámetros
DBMS_XMLSave.clearUpdateColumnList(contextAgregar);
-- columnas para las que existe un valor
DBMS_XMLSave.setUpdateColumn(contextAgregar,’NUMCLI’);
DBMS_XMLSave.setUpdateColumn(contextAgregar,’NOMCLI’);
-- realizar las inserciones
numFilas:=DBMS_XMLSave.insertXML(contextAgregar,documentoXML);
--cerrar el contexto
DBMS_XMLSave.closeContext(contextAgregar);

-- validar las modificaciones


commit;

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.

Las columnas que se usan en la identificación de filas se especifican mediante el


procedimientosetKeyColumn y aquellas que van a actualizarse mediante el
procedimiento setUpdateColumn. Si no se especifican las columnas que van a actualizarse,
se actualizarán todas las columnas de la tabla.

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;

-- variables para la actualización


contextAct DBMS_XMLSave.ctxType;
numFilas number;

begin
archivo_in:= bfilename(’xml_dir’,’datos3.xml’);

-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);

-- tamaño del archivo


tamaño:=dbms_lob.getlength(archivo_in);

-- leer los datos y almacenarlos en una variable


contexto_idioma:=1;
dbms_lob.createtemporary(documentoXML, true);
dbms_lob.loadclobfromfile(documentoXML,
archivo_in,
tamaño,
inicio_destino,
inicio_origen,
juego_caracteres,
contexto_idioma,
aviso);
-- cerrar el archivo
dbms_lob.fileclose(archivo_in);

-- creación del contexto de actualización


contextAct:=DBMS_XMLSave.newContext(’CLIENTES’);
-- borrar los parámetros
DBMS_XMLSave.clearUpdateColumnList(contextAct);
-- Columna de identificación
DBMS_XMLSave.setKeyColumn(contextAct,’NUMCLI’);
-- Columnas de actualización
DBMS_XMLSave.setUpdateColumn(contextAct,’COD_POSTAL’);
DBMS_XMLSave.setUpdateColumn(contextAct,’CIUDAD’);
-- efectuar las actualizaciones
numFilas:=DBMS_XMLSave.updateXML(contextAct,documentoXML);
--cerrar el contexto
DBMS_XMLSave.closeContext(contextAct);
-- validar las modificaciones
commit;

end;
/

El archivo XML que sirve de base para la actualización:

<?xml version = ’1.0’?>


<ROWSET>
<ROW>
<NUMCLI>200</NUMCLI>
<COD_POSTAL>27000</COD_POSTAL>
<CIUDAD>PONTEVEDRA</CIUDAD>
</ROW>
<ROW>
<NUMCLI>201</NUMCLI>
<COD_POSTAL>28000</COD_POSTAL
<CIUDAD>MADRID</CIUDAD>
</ROW>
</ROWSET>

c. Borrado de los datos

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;

-- variables para el borrado


contextBorrar DBMS_XMLSave.ctxType;
numFilas number;

begin
archivo_in:= bfilename(’xml_dir’,’datos4.xml’);

-- abrir el archivo
dbms_lob.fileopen(archivo_in, dbms_lob.file_readonly);

-- tamaño del archivo


tamaño:=dbms_lob.getlength(archivo_in);

-- leer los datos y almacenarlos en una variable


contexto_idioma:=1;
dbms_lob.createtemporary(documentoXML, true);
dbms_lob.loadclobfromfile(documentoXML,
archivo_in,
tamaño,
inicio_destino,
inicio_origen,
juego_caracteres,
contexto_idioma,
aviso);
-- cerrar el archivo
dbms_lob.fileclose(archivo_in);

-- creación del contexto de borrado


contextBorrar:=DBMS_XMLSave.newContext(’CLIENTES’);

-- borrar los parámetros


DBMS_XMLSave.clearUpdateColumnList(contextBorrar);
-- Columna de identificación
DBMS_XMLSave.setKeyColumn(contextBorrar,’NUMCLI’);
-- realizar el borrado
numFilas:=DBMS_XMLSave.deleteXML(contextBorrar,documentoXML);
--cierre del contexto
DBMS_XMLSave.closeContext(contextBorrar);
-- validar las modificaciones
commit;

end;
/

El uso del paquete DBMS_XMLSave es un tanto tedioso en lo que se refiere a la escritura de


procedimientos, especialmente en el nivel de inicialización del contexto. Dado que el contexto
está relacionado con una tabla determinada, es posible crear un único contexto y utilizarlo a
continuación para llevar a cabo todas las operaciones de actualización o de borrado. Esto se
realiza agrupando los procedimientos relativos a las diferentes operaciones en un mismo paquete
y declarando como variable global del paquete el contexto de ejecución de las instrucciones del
paquete DBMS_XMLSave.
Introducción
Desde la versión 11g de la base de datos, Oracle instala por defecto el servicio Oracle Application
Express (APEX). Este servicio permite crear una estructura de bases de datos y gestionar los
datos contenidos en las tablas mediante interfaces intuitivas.

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.

Para activar APEX es necesario proceder de la manera siguiente:

Inicie SQL*Plus en el servidor y conéctese como SYS.

C:\>sqlplus /nolog

SQL*Plus: Release 12.1.0.2.0 - Production on Thu. Apr. 30 15:29:32 2009

Copyright (c) 1982, 2014, Oracle. All rights reserved.

SQL> CONNECT / AS SYSDBA

Conectado.a

Ejecute el script apxconf.sql situado en el directorio apex de la instalación de Oracle y defina


una contraseña para el administrador APEX, así como el puerto que es necesario utilizar para el
servidor HTTP (8080 por defecto).

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

Enter a password for the ADMIN user [] admin

Sesión modificada.

...changing password for ADMIN


Procedimiento PL/SQL terminado correctamente.

Enter a port for the XDB HTTP listener [ 8080]


...changing HTTP Port

Procedimiento PL/SQL terminado correctamente.

Desbloquee la cuenta ANONYMOUS.

SQL> ALTER USER ANONYMOUS ACCOUNT UNLOCK;

Usuario modificado.

Por defecto, APEX solo se instala en idioma inglés.

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

SQL*Plus: Release 12.1.0.2.0 - Production on Thu. Apr. 30 15: 30:12


2009

Copyright (c) 1982, 2014, Oracle. All rights reserved.

SQL> CONNECT / AS SYSDBA


Conectado.

SQL> ALTER SESSION SET CURRENT_SCHEMA = APEX_040200;

Sesión modificada.

Ejecute el script correspondiente al idioma elegido.

SQL> @?/apex/builder/es/load_es.sql
...
La carga del idioma dura varios minutos.

Crear un espacio de trabajo


En la terminología de APEX, un espacio de trabajo (workspace) hace referencia al entorno
utilizado para desarrollar aplicaciones. Un espacio de trabajo puede contener varias aplicaciones
y estar compartido por varios desarrolladores. Un espacio de trabajo se asocia a un esquema.

Para crear un espacio de trabajo es necesario conectarse a la interfaz de administración de APEX


con una URL del tipo http://servidor:puerto/apex/apex_admin, donde servidor hace referencia
al nombre del servidor Oracle y puerto hace referencia al puerto de escucha del servidor HTTP
indicado en la configuración (8080 por defecto).

Puede conectarse con el nombre de usuario admin y la contraseña indicada en la configuración.

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.

La página de inicio de la interfaz tiene el siguiente aspecto:


Para crear un espacio de trabajo nuevo, pulse el botón Crear Espacio de Trabajo.

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:

Pulse el botón Listo.

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.

También podría gustarte