Curso Completo de Oracle SQL
Curso Completo de Oracle SQL
1/323
Índice
2/306
SQL
3/306
SQL
4/306
SQL
5/306
SQL
6/306
SQL
La combinación de las tecnologías de servidor y las herramientas de desarrollo conforman una plataforma
para el desarrollo y entrega de aplicaciones que permite la nube. La nube es un enfoque para la entrega
de servicios de IT que maximiza la eficiencia de costes de todo el entorno mediante la entrega de potencia
de computación a partir de un conjunto de recursos disponibles, bajo demanda.
7/306
SQL
El cliente lo forman dos componentes: los usuarios y los procesos de usuario. El servidor tiene tres
componentes: los procesos del servidor que ejecutan el SQL, la instancia, y la propia base de datos.
Cada usuario interactúa con un proceso de usuario. Cada proceso de usuario interactúa con un proceso
del servidor, normalmente a través de una red de área local. Los procesos del servidor interactúan con
la instancia y la instancia con la base de datos. La siguiente figura muestra esta relación en forma de
diagrama.
Una sesión es un proceso de usuario en comunicación con un proceso servidor. Normalmente habrá un
proceso de usuario por usuario y un proceso de servidor por proceso de usuario. Los procesos de usuario
y servidor que conforman las sesiones se inician a petición de los usuarios y se terminan cuando ya no
son necesarias; este es el ciclo de conexión y desconexión. Los procesos de instancia y las estructuras
de memoria son lanzados por el administrador de la base de datos y persisten hasta que el administrador
los termina deliberadamente; éste es el ciclo de inicio y cierre de la base de datos.
El proceso de usuario puede ser cualquier software del lado del cliente que sea capaz de conectar a un
proceso de servidor Oracle. A lo largo de este libro se utilizarán dos procesos de usuario extensivamente:
SQL* Plus y SQL Developer. Estos son procesos sencillos proporcionados por Oracle para establecer
sesiones contra un servidor Oracle y emitir SQL ad hoc. La alternativa más utilizada es TOAD (la
herramienta para desarrolladores de aplicaciones) de Quest Software, aunque se trata de software con
licencia. Las aplicaciones de usuario final tendrán que ser más sofisticadas que estas herramientas, algo
capaz de gestionar las ventanas, menús, diálogos adecuados en pantalla, etc. Dicha aplicación puede ser
escrita con las Herramientas de Desarrollo de Oracle, con Microsoft Access enlazado a los drivers ODBC
de Oracle, con cualquier lenguaje de tercera generación (como C o Java) para el que Oracle haya
proporcionado una librería de funciones que le permita interactuar con el servidor, o con cualquier número
de herramientas de terceros compatibles con Oracle. Lo que realmente es el proceso de usuario no le
importa en absoluto al servidor Oracle. Cuando un usuario final rellena un formulario y pulsa el botón
Enviar, el proceso de usuario generará una sentencia INSERT (detallada en el Capítulo 10) y la enviará a
un proceso del servidor para su ejecución contra la instancia y la base de datos. En lo que concierne al
servidor, la sentencia INSERT podría haber sido escrita en SQL* Plus, como lo que se conoce como SQL
ad hoc.
Toda comunicación con un servidor Oracle sigue este modelo cliente-servidor. La separación del código
de usuario del código del servidor se remonta a las primeras versiones de la base de datos y es inevitable,
incluso si el proceso de usuario se está ejecutando en la misma máquina que el servidor, la división
cliente-servidor se sigue aplicando. Las aplicaciones que se ejecutan en un entorno de servidor de
aplicaciones (descrito en la siguiente sección) también siguen el modelo cliente-servidor para su acceso
a la base de datos.
8/306
SQL
La forma más simple del servidor de base de datos es una instancia conectada a una base de datos, pero
en un entorno más complejo una base de datos puede ser abierta por muchas instancias
simultáneamente. Esto se conoce como RAC (Real Application Cluster). RAC puede traer muchos
beneficios potenciales, que pueden incluir escalabilidad, rendimiento y tiempos de inactividad cero. La
capacidad de añadir dinámicamente más instancias que se ejecutan en nodos suplementarios a una base
de datos es una parte importante de la contribución de la base de datos a la nube.
Oracle WebLogic Server es una plataforma para el desarrollo, la implantación y la gestión de aplicaciones
web. Una aplicación web puede definirse como cualquier aplicación con la que los usuarios se comunican
mediante HTTP. Las aplicaciones Web normalmente se ejecutan en al menos tres niveles: un nivel de
base de datos gestiona el acceso a los datos, el nivel de cliente (a menudo implementado como un
navegador web) maneja la gestión de ventanas locales para las comunicaciones con los usuarios, y un
nivel de aplicación en medio ejecuta la lógica del programa que genera la interfaz de usuario y las
llamadas SQL a la base de datos.
Las aplicaciones web se pueden desarrollar con diversas tecnologías, entre las que predomina Java. Las
aplicaciones escritas en Java deben cumplir con el estándar Java EE (Java Enterprise Edition), que define
cómo deben empaquetarse e implementarse dichas aplicaciones. JEE y los estándares relacionados son
controlados por Oracle y aceptados por prácticamente todos los desarrolladores de software. Oracle
WebLogic Server es un servidor de aplicaciones compatible con JEE. La implementación de los estándares
por parte de Oracle permite el equilibrio de carga automático y la tolerancia a fallos en múltiples
servidores de aplicaciones en múltiples máquinas a través de la agrupación JEE. La agrupación en cluster
virtualiza la prestación del servicio de aplicaciones; los usuarios solicitan una aplicación que puede estar
disponible en varias ubicaciones y el cluster funciona desde donde mejor se puede prestar servicio a
cualquier sesión o solicitud. Si una ubicación falla, otras asumirán la carga y se podrán poner más
recursos a disposición de una aplicación según sea necesario. La capacidad de separar la solicitud de un
servicio de la ubicación de su prestación y de añadir o eliminar servidores JEE de un cluster de forma
dinámica es una parte importante de la contribución de Oracle WebLogic Server a la nube.
Es importante señalar que el compromiso de Oracle con los estándares internacionales es muy fuerte.
Las aplicaciones que se ejecutan en el entorno Oracle WebLogic Server pueden conectarse a cualquier
base de datos para la que existan controladores compatibles con Java, no es necesario utilizar una base
de datos Oracle. Las aplicaciones desarrolladas con las herramientas de Oracle WebLogic Server se
pueden implementar en cualquier servidor de aplicaciones de terceros compatible con JEE.
El modelo de procesamiento más simple de las aplicaciones web es de tres niveles: un nivel de cliente
que gestiona la interfaz de usuario, un nivel medio que genera la interfaz y emite sentencias SQL al nivel
de datos, y un nivel de datos que gestiona los propios datos. En el entorno Oracle, el nivel de cliente
será un navegador (como Mozilla Firefox o Microsoft Internet Explorer) que se encarga de la gestión local
de ventanas, controla el teclado y realiza un seguimiento de los movimientos del ratón. El nivel medio
9/306
SQL
será un Oracle WebLogic Server ejecutando el software (probablemente escrito en Java) que genera las
ventanas enviadas al nivel de cliente para su visualización y las sentencias SQL enviadas al nivel de datos
para su ejecución. El nivel de datos será un servidor Oracle: una instancia y una base de datos. En este
entorno de tres niveles, hay dos tipos de sesiones: sesiones de usuario final desde el nivel del cliente
hasta el nivel medio, y sesiones de base de datos desde el nivel medio hasta el nivel de datos. Las
sesiones de usuario final se establecerán con HTTP. Las sesiones de base de datos son sesiones cliente-
servidor que consisten en un proceso de usuario y un proceso de servidor, como se describe en la sección
anterior.
Es posible que una aplicación utilice un mapeo uno a uno de sesión de usuario final a sesión de base de
datos: cada usuario, desde su navegador, establecerá una sesión contra el servidor de aplicación, y el
servidor de aplicación establecerá entonces una sesión contra el servidor de base de datos en nombre
del usuario. Sin embargo, este modelo ha demostrado ser muy ineficiente en comparación con el modelo
de pool de conexiones. Con el pool de conexiones, el servidor de aplicaciones establece un número
relativamente pequeño de sesiones de base de datos persistentes y las pone a disposición de un número
relativamente grande de sesiones de usuario final en el servidor de aplicaciones. La Figura anterior ilustra
la arquitectura de tres niveles usando el pool de conexiones. Desde el punto de vista de la base de datos,
no importa si una sentencia SQL proviene de un proceso del lado del cliente como SQL* Plus o Microsoft
Access o de una sesión combinada a un servidor de aplicaciones. En el primer caso, todo el proceso de
usuario ocurre en una máquina; en el segundo, el proceso de usuario se ha dividido en dos niveles: un
nivel de aplicación que genera la interfaz de usuario y un nivel de cliente que la muestra.
10/306
SQL
• Database Express
• Fusion Middleware Control
• Control de la nube
Oracle Enterprise Manager Database Express es una herramienta gráfica para administrar una base de
datos, que puede ser una base de datos en clúster RAC. Consiste en un proceso Java que se ejecuta en
el equipo servidor de la base de datos. Los administradores se conectan a Database Express desde un
navegador y Database Express se conecta al servidor de base de datos. Database Express tiene un buen
desempeño en campos como la administración en tiempo real, monitoreo de desempeño y ejecución de
trabajos programados.
Oracle Enterprise Manager Fusion Middleware Control es una herramienta gráfica para gestionar la
implementación de Fusion Middleware. Estas implementaciones suelen incluir Oracle WebLogic Server,
un servidor de aplicaciones líder del sector que proporciona las máquinas virtuales de Java (JVM) que
alojan aplicaciones Oracle o Java personalizadas.
Oracle Enterprise Manager Cloud Control globaliza el entorno de gestión. Un repositorio de gestión
(residente en una base de datos Oracle) y uno o varios servidores de gestión gestionan el entorno
completo: todas las bases de datos y servidores de aplicaciones, estén donde estén. Cloud Control
también puede gestionar los nodos, o equipos, en los que se ejecutan los servidores. Cada nodo
gestionado ejecuta un proceso de agente, que es responsable de supervisar el objetivo gestionado en el
nodo, la ejecución de trabajos contra él y la generación de informes sobre el estado, los niveles de
actividad y las condiciones de alerta al servidor o servidores de gestión.
Cloud Control proporciona una visión holística del entorno y si está bien configurado, hace que el personal
de administración sea mucho más productivo de lo que es sin él. Es posible que un administrador gestione
de forma eficaz cientos de objetivos.
11/306
SQL
La nube no es exclusiva de Oracle. A nivel físico, algunos proveedores de sistemas operativos y hardware
están proporcionando capacidades similares a las de la nube. Éstos incluyen la capacidad de ‘particionar’
servidores en máquinas virtuales y agregar o quitar dinámicamente CPU(s) y RAM de las máquinas
virtuales según la demanda. Esto es conceptualmente similar al enfoque de Oracle de asignar
dinámicamente los recursos del servidor de aplicaciones y del servidor de bases de datos a los servicios
lógicos. No hay ninguna razón por la que los dos enfoques no puedan combinarse. Ambos están
trabajando hacia la misma meta y pueden trabajar juntos. El resultado debería ser un entorno en el que
siempre se dispusiera de recursos adecuados a petición, sin tener que hacer frente a problemas de exceso
de capacidad en algunos momentos y de rendimiento insuficiente en otros. También debería ser posible
diseñar un entorno de nube sin un único punto de fallo, logrando así el objetivo de un tiempo de actividad
del 100% que está siendo demandado por muchos usuarios.
El desarrollador de aplicaciones SQL no necesita saber cómo se ha implementado la nube, el SQL será
invocado desde un servidor de aplicaciones y ejecutado por una instancia de una base de datos; la nube
se encargará de que en todo momento se disponga de pools de servidores de aplicaciones e instancias
del tamaño adecuado para la carga de trabajo actual.
Dentro de la base de datos, es posible utilizar tres idiomas. El que es inevitable, y el tema de este curso,
es SQL. SQL se utiliza para el acceso a los datos, pero no es suficiente para el desarrollo de aplicaciones
completas. No tiene facilidades reales para desarrollar interfaces de usuario, y también carece de las
estructuras procesales necesarias para manipular filas individualmente. Los otros dos idiomas disponibles
en la base de datos colman estas lagunas. Son PL/SQL y Java, aunque también se puede utilizar Java
fuera de la base de datos. PL/SQL es un lenguaje de tercera generación (3GL) propiedad de Oracle. Tiene
las construcciones procesales usuales (como if-then-else y looping) y facilidades para el diseño de la
interfaz de usuario. En el código PL/SQL, se pueden incrustar llamadas a SQL. Por lo tanto, una aplicación
PL/SQL puede usar SQL para recuperar una o más filas de la base de datos, luego realizar varias acciones
basadas en su contenido, y luego emitir más SQL para volver a escribir filas en la base de datos. Java
ofrece una capacidad similar para incrustar llamadas SQL dentro del código Java.
Se trata de una tecnología estándar del sector: cualquier programador Java debería ser capaz de escribir
código que funcione con una base de datos Oracle (o con cualquier otra base de datos compatible con
Java).
Otros lenguajes están disponibles para el desarrollo de aplicaciones cliente-servidor que se ejecutan
externamente a la base de datos. Los más utilizados son C y Java, pero es posible utilizar la mayoría de
los 3GL convencionales. Para todos estos lenguajes, Oracle Corporation proporciona bibliotecas OCI
(Oracle Call Interface) que permiten que el código escrito establezca sesiones contra una base de datos
Oracle e invoque comandos SQL. Muchas organizaciones no querrán usar un 3GL para desarrollar
aplicaciones de bases de datos. Oracle Corporation proporciona herramientas de desarrollo rápido de
aplicaciones como Oracle Application Express o JDeveloper. Esto puede hacer que los programadores
sean mucho más productivos que si trabajaran con un 3GL. Al igual que los lenguajes, todas estas
herramientas de desarrollo de aplicaciones terminan haciendo lo mismo: construir sentencias SQL que
se envían al servidor de base de datos para su ejecución.
12/306
SQL
Concesionario de automóviles
Sid dirige un concesionario de coches y necesita un sistema para hacer un seguimiento de los coches
que compra y vende. Ha notado que la empresa se está hundiendo y quiere entrar en el siglo XXI y crear
un sitio web que anuncie las existencias disponibles. Necesita un sistema para llevar un registro de los
coches que ha comprado y vendido y los detalles de estas transacciones.
Núcleos geológicos
Se han recogido muestras de tierra por la agencia local de estudios geológicos. Para asegurar el rigor
científico, los desarrolladores de GeoCore han determinado que el sistema debe rastrear la ubicación
geográfica exacta, el contenido elemental de las muestras, y las fechas de recogida.
Entrada de pedidos
El escenario de Entrada de pedidos (OE) proporcionado como ejemplo por Oracle contiene información
para un sistema comercial ficticio que realiza un seguimiento de productos, clientes y pedidos de cliente
que han sido realizados.
Recursos humanos
El escenario de Recursos Humanos (HR) proporcionado como ejemplo por los registros de Oracle contiene
información de empleados, departamentos, oficinas e información relacionada con el trabajo para un
típico Departamento de RRHH.
Aunque los escenarios hipotéticos descritos anteriormente varían en complejidad, comparten varias
características, incluyendo un crecimiento potencial de los datos que, eventualmente, puede sobrepasar
a una solución de organización de datos basada en papel o en hojas de cálculo, así como un requisito
para que los datos sean manipulados (insertados, actualizados y borrados) y recuperados de manera
eficiente. El reto de producir un diseño de organización de datos eficiente (también conocido como un
modelo de datos) puede ser superado tanto con una comprensión de cómo es probable que se utilicen
los datos que se están organizando y algunas técnicas básicas de modelado de datos. El objetivo es
13/306
SQL
lograr un equilibrio óptimo entre almacenamiento de datos y acceso a los mismos, lo que supondrá un
ahorro a largo plazo en los costes y posteriores beneficios.
Las relaciones en los modelos relacionales suelen representarse como rectángulos. En esta etapa se dan
más detalles en términos de tipificación de datos para los atributos y los atributos de la clave primaria y
externa se reflejan respectivamente con una "P" y una "F" en el modelo relacional. Finalmente, el modelo
relacional se convierte en un modelo físico mediante la implementación del diseño en una base de datos
relacional.
La notación “pata de gallo” es un estilo que se utiliza a menudo para representar relaciones en modelos
de datos lógicos y relacionales, ya que muestra tanto la cardinalidad máxima como la mínima en un
formato fácil de leer. A continuación, se verán las relaciones entre entidades y serán exploradas en el
contexto del Concesionario de automóviles.
- 1:N One-to-many
- N:1 Many-to-one
14/306
SQL
- 1:1 One-to-one
- M:N Many-to-many
Se considera el escenario del concesionario de Sid presentado anteriormente. Se podría modelar los
datos probables como una entidad que consiste en los siguientes atributos relacionados con el automóvil:
Fabricación, Modelo, Capacidad del motor y Color. También es necesaria información sobre la
compraventa de los coches, por lo que se podría añadir Fecha de compra, Fecha de venta, Nombre del
vendedor, SSN (Número de Seguro Social) , Compañía Vendedora, los mismos detalles para el comprador,
y finalmente el Precio de Compra y el Precio de Venta, como en la tabla siguiente:
CarDealership
Make
Model
Engine Capacity
Color
Purchase Date
Sold Date
Sellers Name
Seller_SSN
Sellers_Company
Buyers Name
Buyers_SSN
Buyers Company
Selling price
Purchase price
Los datos transaccionales de muestra almacenados en una tabla basada en esta entidad pueden tener el
aspecto que se observa a continuación: tres filas de datos en una tabla de catorce columnas llamado
CAR_DEALERSHIP. Los comandos para crear tablas y rellenarlas con los datos serán discutidos más
adelante en este curso. Por ahora, hay aspectos fundamentales que hay que tener en cuenta. Las tablas
almacenan datos en filas, también llamados registros. Cada dato se encuentra en la intersección de una
fila y una columna, también llamada celda. Es bastante intuitiva y muy parecida a una hoja de cálculo.
15/306
SQL
- Un Mercedes A160 plateado con un motor de 1600cc que pertenecía a Sid, un con Customer_SSN
12346, fue comprado por Wags con Customer_SSN 12347 con su compañía Wag´s Auto por 12,000$
el 1 de Agosto de 2013.
Observar la repetición de los datos. Cada registro contiene información duplicada de los coches que se
compran o venden y del cliente que los compra o vende. La duplicación innecesaria de datos por lo
general indica un diseño deficiente, ya que es un desperdicio y una pérdida de tiempo y a menudo
requiere un mantenimiento innecesario. Si el mantenimiento no se hace con cuidado, este diseño
permitirá que los errores (a menudo denominados anomalías de inserción, modificación y borrado) se
introduzcan, sin que nadie se percate de ello, y reduzcan la integridad general de los datos.
La normalización de la base de datos se refiere al modelado de datos usando múltiples entidades con
relaciones entre ellos, lo que puede reducir o eliminar por completo la redundancia de datos. Hay muchos
tipos de formas normalizadas que han sido definidas teóricamente, pero el diseño de bases de datos
relacionales se centra principalmente en las tres siguientes:
16/306
SQL
17/306
SQL
un cliente utilizando el atributo de clave primaria de Client ID, donde la información como el nombre
del cliente y la empresa se almacenara.
A menudo hay varios modelos normalizados posibles para una aplicación. Es importante
utilizar el más apropiado. Si el analista de sistemas se equivoca, las implicaciones pueden ser
serias para el rendimiento, las necesidades de almacenamiento y el esfuerzo de desarrollo.
Nota: En el contexto de la optimización del rendimiento, es intencional y aceptable duplicar
datos en entidades. Cuando los datos se normalizan a través de múltiples entidades
instanciadas como múltiples tablas que deben unirse, los procesos del servidor Oracle
necesitan obtener físicamente datos de múltiples tablas y unirlas en un espacio de memoria
para producir el conjunto de resultados requerido. El IO adicional requerido para consultar o
manipular datos normalizados a veces justifica la desnormalización de los datos para reducir
las operaciones de E/S de disco y, por lo tanto, aumentar el rendimiento. Este es común en
Data Warehouse (DWH) y Sistemas de Soporte de Decisiones (DSS) pero es una excepción a
la regla en los sistemas de Procesamiento de Transacciones Online (OLTP).
Considérese el modelo de datos lógico en la siguiente imagen. Los datos relacionados con el coche se
han modelado como la entidad Cars. La información del cliente (compradores y vendedores) es
esencialmente la misma, por lo que han sido modelados como la entidad Customers con el atributo tipo
de Customer para diferenciar entre Compradores y Vendedores. Las ventas y compras se registran en la
entidad Transactions, mientras que una entidad de búsqueda llamada Colors realiza un seguimiento de
los diferentes colores.
Hay varias ventajas en conceptualizar este diseño como cuatro entidades interrelacionadas. En primer
lugar, los datos se han normalizado y no hay duplicidad de datos.
Una ventaja práctica de las entidades múltiples radica en que cada una sigue una sola construcción como
coches, clientes, colores, e incluso transacciones, lo que facilita el mantenimiento de los datos. Se pueden
añadir nuevos colores, cada uno con un código único, y a medida que se compran coches nuevos, estos
colores definidos y mantenidos en un solo lugar se pueden utilizar para describir varios coches con el
mismo color. Se puede mejorar la sofisticación de este modelo definiendo entidades para neumáticos,
sistemas de seguridad, dispositivos de seguimiento o complementos audiovisuales. También se podría
aumentar los detalles recogidos para cada coche, como el número de bastidor y el número de motor; o
para cada cliente, como la dirección y los datos bancarios. Pero este escenario hipotético sirve para
ilustrar varios conceptos y obviamente, no se puede utilizar en un escenario de aplicación de producción
sin más ampliaciones.
18/306
SQL
a. Claves primarias
Cada entidad en la anterior figura tiene un atributo ‘clave primaria’ que identifica de manera única una
tupla o registro denotado por un #* adyacente al nombre del atributo. Cada valor de la clave primaria
Car ID es única en la entidad. Las líneas múltiples no pueden compartir el mismo valor de clave primaria.
Del mismo modo, el Color ID identifica de forma unívoca cada registro de la entidad Colores, al igual que
el Customer ID y el TX ID de las entidades Clientes y Transacciones, respectivamente.
b. Relaciones
Las líneas de la figura anterior que enlazan las diversas entidades se conocen como relaciones. La
notación de “pata de gallo” expresa la cardinalidad de las relaciones entre las entidades uno a uno, uno
a muchos, muchos a uno y muchos a muchos. Esta notación ilustra explícitamente la entidad con el lado
“many” de la relación con múltiples "patas", mientras que la entidad del lado “one” tiene una “pata”. Los
atributos en una relación one-to-one son idénticos, mientras que las relaciones de many-to-many indican
las tuplas múltiples en la entidad A que tienen los mismos valores de atributo que otras tuplas en la
19/306
SQL
entidad B. Tanto las relaciones de one-to-one como las de many-to-many no son muy comunes y a veces
señalan defectos en el modelo relacional. Las relaciones one-to-many y many-to-one ocurren
frecuentemente cuando se modelan entidades relacionales y relacionan atributos en dos entidades en
una relación master-detail. Desde el punto de vista de la relación entre las entidades Cars y Colors (el
orden es significativo), por ejemplo, muchos registros en la entidad Cars tendrán un Color. Muchos coches
podrían tener el mismo atributo de identificación de un solo color que indica que son del mismo color. La
entidad Colors es la entidad maestra o entidad de búsqueda, mientras que la entidad Cars es la entidad
de detalle en este caso. Desde el punto de vista de la relación entre Colors y Cars, un color puede ser
asociado con muchos coches. Así que es sólo una cuestión de perspectiva si una relación es de uno a
muchos o de muchos a uno; todo depende de cuál sea la dirección de la relación que se considere. Las
otras relaciones indicadas por este método muestran que un solo coche puede ser comprado y vendido
varias veces, de ahí la relación uno a muchos entre las entidades Cars y Transactions y, por último, que
un cliente puede realizar muchas transacciones (como comprar y vender muchos coches).
Nota: Las claves externas en una entidad se basan en claves únicas en una entidad relacionada, pero
esas claves únicas no tienen que ser la clave primaria; sólo tienen que ser únicas.
20/306
SQL
El modelo lógico de la figura anterior, normalmente evolucionaría hacia un modelo relacional con más
detalles de tipología de datos y claves primarias y ajenas más claras, como en la figura mostrada a
continuación.
21/306
SQL
Los datos de la muestra transferidos al modelo físico, construido a partir del modelo relacional anterior,
producirían cuatro conjuntos de datos, como en la figura siguiente.
22/306
SQL
Las dos primeras líneas de datos en el conjunto de datos Transactions se pueden interpretar como se
indica a continuación:
- Una transacción con TX_ID 100 describe la compra de un automóvil con Car_ID 1 por parte del
concesionario de Sid a un cliente con Customer_ID 2 por 10.000 dólares el 1 de junio de 2013. Se busca
el cliente con Customer_ID 2 y se observa que fue una venta de Coda, un vendedor privado con
Customer_SSN 12345. Si se busca el automóvil con Car_ID 1, se determina que se trataba de un
Mercedes del 2001- A160 con Color_ID 1.
- Una transacción con TX_ID 101 describe la venta de un automóvil con Car_ID 1 a Customer_ID 4, que
se observa que es un vendedor llamado Wags del concesionario Wags Auto con Customer_SSN 12347,
por 12.000 dólares el 1 de agosto de 2013.
d. Registros y tablas
El paradigma relacional modela los datos como tablas bidimensionales. Una tabla consta de varios
registros, cada uno de las cuales consta de un conjunto de columnas. Dentro de una tabla, todos los
23/306
SQL
registros tienen la misma estructura de columnas, aunque es posible que algunas columnas se
encuentren vacías. Un ejemplo de una tabla sería una lista de los empleados; cada empleado está
representado por un registro. Las columnas pueden ser: el número de empleado, el nombre y un código
para el departamento en el que trabaja el empleado. Cualquier empleado que no esté actualmente
asignado a un departamento tendrá esa columna en blanco. Otra tabla podría representar los
departamentos: un registro por departamento con columnas para el código del departamento y el nombre
del departamento.
Las tablas relacionales se ajustan a ciertas reglas que limitan y definen los datos. En el nivel de columna,
cada columna debe ser de un determinado tipo de datos, como numérico, fecha/hora o carácter. El tipo
de datos de carácter es el más general, en el sentido de que puede aceptar cualquier tipo de datos. A
nivel de registro, normalmente cada uno debe tener alguna característica identificativa: podría ser el
valor de una columna, como el número de empleado y número de departamento en los ejemplos
anteriores, que no pueden repetirse en otros registros. También puede haber reglas que definan los
vínculos entre las tablas, como la regla de que a cada empleado se le debe asignar un código de
departamento que puede coincidir con un registro de la tabla de departamentos.
Tabla DEPT
Tabla EMP
24/306
SQL
DEPTNO DNAME
10 ACCOUNTING
20 RESEARCH
30 SALES
40 OPERATIONS
7369 SMITH 20
7499 ALLEN 30
7521 WARD 30
7566 JONES 20
7654 MARTIN 30
7698 BLAKE 30
7782 CLARK 10
7788 SCOTT 20
Si se examinan las tablas DEPT y EMP, la estructura bidimensional es clara. Cada registro es de longitud
fija, cada columna es de longitud fija, y los registros se delimitan con una nueva línea. Los cambios en
25/306
SQL
los datos suelen ser muy eficientes con el modelo relacional. Se pueden añadir nuevos empleados, o
pueden ser movidos de un departamento a otro simplemente modificando el valor DEPTNO en su registro.
Se considera una estructura alternativa, en la que los datos se almacenan según el paradigma jerárquico.
El modelo jerárquico se desarrolló antes que el relacional por razones tecnológicas. Al principio, los
dispositivos de almacenamiento carecían de la capacidad de mantener los archivos separados que se
necesitaban para las tablas relacionales. Téngase en cuenta que este problema se evita en la base de
datos de Oracle mediante abstracción del almacenamiento físico (ficheros) del almacenamiento lógico
(tablas): no hay conexión directa entre tablas y archivos y menos un mapeo one-to-one. En efecto,
muchas tablas se pueden almacenar en muy pocos archivos.
Una estructura jerárquica almacena todos los datos relacionados en una unidad. Por ejemplo, el registro
de un departamento incluiría todos los empleados de ese departamento. El paradigma jerárquico puede
ser muy rápido y muy eficiente en cuanto al espacio. Un acceso a un archivo puede ser todo lo que se
necesita para recuperar todos los datos necesarios para satisfacer una consulta. Los empleados y
departamentos listados anteriormente podrían almacenarse jerárquicamente como se indica a
continuación:
10,ACCOUNTING,7782,CLARK
20,RESEARCH,7369,SMITH,7566,JONES,7788,SCOTT
30,SALES,7499,ALLEN,7521,WARD,7654,MARTIN,7698,BLAKE
40,OPERATIONS
En este ejemplo, los registros y columnas son de longitud variable. Las columnas se delimitan con una
coma, los registros con una nueva línea. La recuperación de datos es muy eficiente si la consulta puede
navegar por la jerarquía: si uno conoce el departamento de un empleado, el empleado puede ser
encontrado rápidamente. Si no lo hace, la recuperación puede ser lenta. Las modificaciones de los datos
pueden ser un problema si la modificación requiere movimiento. Por ejemplo, para mover el empleado
7566, JONES de RESEARCH a SALES supondría un esfuerzo considerable por parte de la base de datos,
ya que el traslado debe llevarse a cabo como una eliminación de un registro y una inserción en otra.
Téngase en cuenta que en este ejemplo, si bien es posible tener un departamento sin empleados (el
departamento OPERATIONS), es absolutamente imposible tener un empleado sin un departamento: no
hay ningún lugar donde ponerlo. Esto es excelente si hay una regla de negocios que establece que todos
los empleados deben estar en un departamento, pero no tan bueno si no es el caso.
El paradigma relacional es altamente eficiente en muchos aspectos para muchos tipos de datos, pero no
es apropiado para todas las aplicaciones. Como regla general, un análisis relacional debería ser el primer
enfoque adoptado al modelar un sistema. Sólo si se demuestra inapropiado, se recurre a estructuras no
relacionales. Aplicaciones en las que el modelo relacional ha demostrado ser altamente efectivo incluye
prácticamente todos los sistemas OLTP y DSS. El paradigma relacional puede ser exigente en sus
requerimientos de hardware y en la habilidad necesaria para desarrollar aplicaciones a su alrededor, pero
a la hora de encajar los datos, ha demostrado ser el modelo más versátil. Puede haber, por ejemplo,
26/306
SQL
problemas causados por la necesidad de mantener los índices que mantienen, a su vez, los vínculos entre
las tablas y los requisitos de espacio (mantener múltiples copias de los datos indexados en los propios
índices y en las tablas en las que residen las columnas). Sin embargo, el diseño relacional es en la
mayoría de los casos el modelo óptimo.
Varios editores de software han creado sistemas de gestión de bases de datos que se ajustan (con
diversos grados de precisión) al paradigma relacional; Oracle es sólo uno. IBM fue quizás la primera
empresa en dedicarle importantes recursos, pero su producto (que más tarde se convirtió en DB2) no
fue importado a plataformas que no fueran IBM durante muchos años. SQL Server de Microsoft es otra
base de datos relacional que ha sido limitada por las plataformas en las que se ejecuta. Las bases de
datos Oracle, por el contrario, siempre se han importado a todas las plataformas importantes desde la
primera versión. Esto puede ser lo que dio a Oracle la ventaja en el mercado de los Sistemas de Gestion
de Bases de Datos (SGDB).
Problema Solución
Una organización está diseñando una Todos. El equipo del proyecto debe
nueva aplicación. ¿Quién debe involucrar a analistas de negocio (que
participar? modelan los procesos de negocio),
analistas de sistemas (que modelan los
datos), diseñadores de sistemas (que
deciden cómo implementar los modelos),
desarrolladores, administradores de
bases de datos, administradores de
sistemas y (lo más importante) usuarios
finales.
27/306
SQL
Nota: en la terminología, puede surgir una confusión al discutir sobre bases de datos relacionales con
personas acostumbradas a trabajar con productos de Microsoft. SQL es un lenguaje y SQL Server es una
base de datos, pero en el mundo de Microsoft, el término SQL se utiliza a menudo para referirse a
cualquiera de los dos.
Las versiones anteriores de la base de datos Oracle utilizaban una implementación de SQL que presentaba
algunas desviaciones significativas del estándar. Esto no se debía a que Oracle estuviera siendo diferente:
normalmente se debía a que Oracle implementaba características que estaban por delante de la norma,
y cuando la norma se actualizó, se utilizó diferente sintaxis. Un ejemplo es OUTER JOIN (detallada en
este curso), que Oracle implementó mucho antes que el estándar de SQL. Cuando el estándar de SQL
introdujo un sistema externo, Oracle agregó soporte para la nueva sintaxis de JOIN, al tiempo que
mantenía el soporte para su propia sintaxis. Oracle Corporation garantiza el cumplimiento futuro
mediante la inserción de personal en los diversos comités de ISO y ANSI, impulsando el estándar de
SQL.
28/306
SQL
- RENAME
- TRUNCATE
- COMMENT
Los comandos Data Control Language (DCL):
- GRANT
- REVOKE
Los comandos Transaction Control Language (TCL):
- COMMIT
- ROLLBACK
- SAVEPOINT
El primer comando, SELECT, es el tema principal de los capítulos 2 a 9. Los comandos DML restantes se
tratan en el Capítulo 10, junto con los comandos TCL. El DDL se detalla en el Capítulo 11. DCL, que tiene
que ver con la seguridad, sólo se menciona brevemente: entra más en el dominio del administrador de
la base de datos que en el del desarrollador.
Cuando SQL falla al proporcionar una solución completa es porque es puramente un lenguaje de acceso
a datos. La mayoría de las aplicaciones necesitarán declaraciones procesales, como el control de flujo:
ramificación e iteración condicional. Por lo general, también necesitarán control de pantalla, las
instalaciones de la interfaz de usuario y las variables; SQL no tiene ninguno de estos. SQL es un lenguaje
orientado a la configuración capaz solamente de acceder a datos. Para el desarrollo de aplicaciones, por
lo tanto, se necesitará un lenguaje procedural que pueda invocar llamadas SQL. Es por lo tanto necesario
para SQL trabajar con un lenguaje procedural.
Se considera una aplicación que solicita un nombre a un usuario, recupera a todas las personas con ese
nombre de una tabla, le pide al usuario que elija uno de ellos, y luego borra la persona elegida. El
lenguaje procedural dibujará una pantalla y generará una solicitud de un nombre. El usuario introducirá
29/306
SQL
el nombre. El lenguaje de procedimiento construirá una sentencia SQL SELECT usando el nombre y
enviará la sentencia a través de una sesión de base de datos al servidor de base de datos para su
ejecución. El servidor devolverá un conjunto de registros (todas las personas con ese nombre) al lenguaje
procedural, que formateará el conjunto para que se muestre al usuario y le pedirá que elija uno (o más)
de ellos. El identificador de la persona (o personas) elegida(s) se utilizará para construir una sentencia
SQL DELETE para que el servidor la ejecute. Si el identificador es un identificador único (la clave
primaria), entonces el conjunto de registros a borrar será un conjunto de un solo registro; si el
identificador no es único, entonces el conjunto seleccionado para borrado será más grande. El código
procedural no sabrá nada sobre el tamaño probable de los conjuntos recuperados o borrados.
1.4.1. SQL*Plus
SQL*Plus es una herramienta cliente-servidor para conectarse a una base de datos y para lanzar
comandos SQL ad hoc. También se pueden usar para crear código PL/SQL y tiene herramientas para dar
formatos determinados a los resultados. Está disponible en todas las plataformas donde la base de datos
se traslade. En las siguientes secciones se darán detalles acerca del uso de SQL*Plus tanto en Windows
como en Linux. No hay grandes diferencias en el uso de SQL*Plus en otras plataformas.
En términos de arquitectura, SQL*Plus se trata de un proceso de usuario escrito en C que establece una
sesión a través de una instancia y una base de datos a través del protocolo de Oracle Net. Las plataformas
para el cliente y el servidor pueden ser diferentes. Por ejemplo, no hay ninguna razón para no usar
SQL*Plus en un ordenador con Windows y conectarlo a una base de datos siendo ejecutada en un servidor
Unix o viceversa, dado que Oracle Net está configurado para este tipo de conexiones.
Al estar escrito en Java, SQL Developer está disponible en todas las plataformas que puedan lanzar la
versión que corresponda del JRE. No hay diferencias significativas entre plataformas.
SQL Developer puede ser una herramienta muy útil, altamente configurable. Se puede experimentar con
el entorno, leer la Ayuda y construir su interfaz para que resulte lo más cómodo posible trabajar en ella.
30/306
SQL
Estos esquemas se pueden habilitar cuando se crea la base de datos; es una opción que muestra el
Asistente de Configuración de Base de Datos (DBCA). Si no existen, se pueden crear más tarde
ejecutando algunos scripts que existirán en la base de datos Oracle Home.
Los esquemas se utilizan para almacenar objetos. Estos pueden ser objetos de datos tales como tablas
o procedimientos almacenados en PL/SQL. Para conectarse a una base de datos y acceder a sus objetos
el usuario tiene primero que ejecutarse y arrancar la base de datos. Por defecto, los usuarios tienen
acceso a los objetos de su propio esquema y a ningún otro, pero muchas aplicaciones modifican este
comportamiento. Normalmente, un esquema puede utilizarse para almacenar datos a los que acceden
otros usuarios a los que se les ha dado permiso para usar los objetos, aunque no les pertenezcan. En la
práctica, muy pocos usuarios tendrán objetos en su propio esquema, o permiso para crearlos: tendrán
permisos de acceso sólo a objetos en otro esquema. Estos objetos serán utilizados por todos los usuarios
que ejecutan la aplicación cuyos datos almacena ese esquema. Por el contrario, los usuarios propietarios
de los esquemas de almacenamiento de datos nunca accederán: el único propósito de sus esquemas es
contener datos utilizados por otros.
Es imposible que un objeto de datos exista independientemente de un esquema. O, en otras palabras,
todas las tablas deben tener un propietario. El propietario es el usuario en cuyo esquema reside la tabla.
El identificador único para una tabla (o cualquier otro objeto de esquema) es el nombre de usuario,
seguido del nombre de objeto. De ello se deduce que no es posible que existan dos tablas con el mismo
nombre en el mismo esquema, pero sí es posible que dos tablas con el mismo nombre (aunque
posiblemente con estructuras o contenidos diferentes) existan en esquemas diferentes. Si un objeto no
existe en el propio esquema, para acceder a él se debe calificar su nombre con el nombre del esquema
en el que reside. Por ejemplo, [Link] es la tabla denominada EMPLOYEES en el esquema del
usuario HR. A menos que haya sinónimos disponibles, sólo un usuario conectado como HR puede acceder
a la tabla haciendo referencia a EMPLOYEES sin un calificador de nombre de esquema. Un sinónimo es
una construcción que hace que un objeto accesible a otros usuarios sin requerir su nombre de esquema
como prefijo.
31/306
SQL
Dos de las relaciones mostradas en la figura anterior pueden no ser inmediatamente comprensibles. En
primer lugar, existe una relación de muchos a uno entre EMPLOYEES y EMPLOYEES. Esto es lo que se
conoce como clave foránea autorreferenciada. Esto significa que muchos empleados pueden estar
conectados a un empleado, y se basa en el hecho de que muchos empleados pueden tener un gerente,
pero el gerente también es un empleado. La relación es implementada por la columna manager_id siendo
una clave foránea para employee_id, que es la clave principal de la tabla.
La segunda relación que puede requerir explicación es entre DEPARTMENTS y EMPLOYEES, que es
bidireccional. La relación de un departamento a muchos empleados simplemente establece que puede
haber muchos miembros del personal en cada departamento, basado en la columna dept_id de la tabla
EMPLOYEES, que es una clave foránea de la columna dept_id (primary key) de la tabla DEPARTMENTS.
La relación de un empleado con muchos departamentos muestra que un empleado podría ser el gerente
de varios departamentos y es implementado por la columna manager_id en la tabla DEPARTMENTS
siendo una clave foránea a la columna employee_id (primary key) en la tabla EMPLOYEES.
La siguiente tabla muestra las columnas de cada tabla en el esquema HR, utilizando la notación descrita
en la sección anterior “Normalización de datos” para indicar las claves primarias (#), las claves foráneas
(\), y si las columnas son opcionales (o) u obligatorias (*).
32/306
SQL
Tabla Columnas
REGIONS #* region_id
o region_name
COUNTRIES #* country_id
o country_name
\o region_id
LOCATIONS #* location_id
o street_address
o postal_code
* city
33/306
SQL
34/306
o state_province
SQL
\o country_id
DEPARTMENTS #* department_id
* department_name
\o manager_id
\o location_id
EMPLOYEES #* employee_id
o first_name
* last_name
o phone_number
* hire_date
\* job_id
o salary
o comission_pct
\o manager_id
\o department_id
35/306
SQL
JOBS #* job_id
* job_title
o min_salary
o max_salary
JOB_HISTORY #* employee_id
#* start_date
* end_date
\* job_id
\o department_id
El esquema OE es considerablemente más complejo que el esquema HR. Las estructuras de las tablas
son mucho más complicadas: incluyen columnas definidas como tablas anidadas, tipos de datos definidos
por el usuario y tipos de datos XML. Hay una serie de ejercicios opcionales al final de cada capítulo que
normalmente se basan en el esquema OE. Los objetos a los que se hace referencia se describen a medida
que se utilizan.
1.6. Resumen
Posicionar las tecnologías de servidor
36/306
SQL
• Oracle WebLogic Server ejecuta aplicaciones que conectan a los usuarios con la base de datos.
• Oracle Enterprise Manager es una herramienta para gestionar bases de datos, servidores de
aplicaciones y, si se desea, todo el entorno informático.
• Los lenguajes incorporados en la base de datos para el desarrollo de aplicaciones son SQL,
PL/SQL y Java.
• Los esquemas de demostración son proporcionados por Oracle para facilitar el aprendizaje, pero
deben ser creados antes de que se puedan utilizar.
Saber cómo recuperar datos en un formato establecido utilizando un idioma de consulta es el primer
paso para la comprensión de las posibilidades de las sentencias SELECT.
Las tres áreas principales que se estudian son las siguientes:
37/306
SQL
SQL*Plus tiene un amplio entorno de comandos en tiempo de ejecución que se puede explorar
utilizando la documentación en línea o el comando HELP INDEX. Estas listas incluyen los
comandos SQL*Plus disponibles, tales como el comando SHOW, que muestra el valor de una
variable SQL*Plus. Por ejemplo, SHOW USER muestra el nombre del usuario actualmente
conectado.
38/306
SQL
DESC[RIBE] <SCHEMA>.tablename
La palabra clave DESCRIBE puede ser acortada a DESC. Todas las tablas pertenecen a un esquema o a
un propietario. Si se está describiendo una tabla que hace referencia al esquema al que está conectado,
la parte "<SCHEMA>" del comando puede ser omitida. La imagen que aparece más abajo muestra el uso
del comando “SHOW user” para verificar que el usuario conectado actualmente es HR. Mientras se está
conectado a la base de datos como HR, la tabla EMPLOYEES se puede mostrar con el comando DESCRIBE
employee, y la tabla DEPARTMENTS se puede mostrar utilizando la notación abreviada DESC
[Link]. El prefijo “hr” puede omitirse ya que la tabla DEPARTMENTS pertenece al esquema HR.
El esquema HR (y cualquier otro esquema) tiene acceso a una tabla especial llamada DUAL, que
pertenece al esquema SYS. Esta tabla puede ser descrita con el comando DESCRIBE [Link].
La descripción de las tablas origina resultados interesantes y útiles. Se sabe qué columnas de una tabla
pueden seleccionarse ya que DESCRIBE muestra los nombres de todas las columnas de la tabla. También
es posible saber qué tipo de datos contienen estas columnas, puesto que DESCRIBE también muestra el
tipo de dato de la columna. Véanse los tipos de datos que se muestran en la imagen de arriba:
Para las columnas numéricas se utiliza a menudo el tipo de dato NUMBER(p,s), donde el primer parámetro
es la precisión (el número máximo de dígitos que va a tener el dato) y el segundo es la escala (el número
máximo de dígitos decimales que se puede almacenar a la derecha del separador decimal). En la figura
anterior, la columna SALARY de la tabla EMPLOYEES tiene un tipo de datos NUMBER(8,2). Esto significa
39/306
SQL
que los valores almacenados en esta columna pueden tener un máximo de 8 dígitos. De estos 8 dígitos,
2 pueden estar a la derecha del punto decimal y hasta 6 pueden estar a la izquierda. Si hay más de dos
dígitos a la derecha del punto decimal, el número se redondeará a 2 decimales siempre que haya un
máximo de 8 dígitos. Un valor SALARY de 999999.99 es aceptable, pero un valor SALARY de 9999999.9
no lo es, aunque ambos números contengan 8 dígitos.
Hay que tener en cuenta que si esta columna no contiene datos o su contenido es inferior a 20 caracteres,
no utilizará necesariamente el mismo espacio que utilizaría para almacenar un nombre de 20 caracteres.
El tipo de datos CHAR(size) especifica columnas de longitud fija, en las que el espacio del campo se
preasigna para contener un número fijo de caracteres independientemente de su contenido. CHAR es
mucho menos utilizado que VARCHAR2. A menos que la longitud de los datos sea predecible y constante,
el tipo de datos CHAR utiliza el almacenamiento de manera ineficiente, rellenando con espacios los
componentes no utilizados.
Los tipos de datos de columna DATE y TIMESTAMP almacenan información de la fecha y la hora. DATE
almacena día, mes, año, horas, minutos y segundos. TIMESTAMP(f) almacena la misma información que
DATE pero es también capaz de almacenar segundos fraccionarios.
Hay una gran variedad de tipos de datos, muchos tienen un propósito concreto como BLOBs
(Binary Large Objects), usado para almacenar datos binarios como música o datos de vídeo.
Pero la gran mayoría de las tablas, sin embargo, utilizan los tipos de datos de columna
primitiva NUMBER, VARCHAR2 y DATE. El tipo de datos TIMESTAMP se ha utilizado
ampliamente desde su introducción en Oracle 9i.
Cualquier columna de datos que esté restringida por la directiva NOT NULL cuando se crea la tabla debe
contener algunos datos. Es importante señalar que NULL tiene un significado especial para el servidor
Oracle. NULL se refiere a la ausencia de datos. Los espacios en blanco no cuentan como NULL ya que
están presentes en el registro y tienen cierta longitud, aunque no sean visibles.
40/306
SQL
quisiera una lista que contiene sólo las columnas DEPARTMENT_NAME y MANAGER_ID? Entonces, se
pediría sólo esas dos columnas de la tabla. Esta restricción de columnas se llama proyección.
La selección hace referencia a la restricción de las tuplas o registros seleccionados de una relación (tabla).
A menudo no se desea recuperar cada registro de una tabla. Las tablas pueden contener muchos registros
y, en lugar de preguntar por todos ellos, la selección proporciona un medio para restringir las líneas
devueltas. Quizás se ha pedido que se identifique sólo los empleados que pertenecen al departamento
30. Con la selección es posible limitar los resultados establecidos en aquellos registros que tienen un
valor DEPARTMENT_ID de 30.
La unión, como concepto relacional, se refiere a la interacción de las tablas entre sí en una consulta. La
tercera forma normal, como se vio en el Capítulo 1, presentaba la noción de separar los diferentes tipos
de datos en tablas autónomas para evitar la duplicidad y anomalías de mantenimiento y asociar datos
relacionados utilizando claves primarias y foráneas. Estas relaciones proporcionan el mecanismo para
unir las tablas entre sí. La unión se discute más extensamente en el Capítulo 7.
Suponiendo que es necesario recuperar las direcciones de correo electrónico de todos los empleados que
hay en el departamento de Ventas. La columna EMAIL pertenece a los EMPLOYEES mientras que la
columna DEPARTMENT_NAME pertenece a la tabla DEPARTMENTS. La proyección y selección de la tabla
DEPARTMENTS puede ser utilizada para obtener el valor DEPARTMENT_ID que corresponde al
departamento de Ventas. Los registros correspondientes de la tabla EMPLOYEES se pueden unir a la tabla
DEPARTMENTS basándose en el valor común DEPARTMENT_ID. La columna EMAIL se mostrará a partir
de este conjunto de resultados.
La sentencia SQL SELECT se rige matemáticamente por estos tres principios. Una combinación ilimitada
de proyecciones, selecciones y uniones proporciona al lenguaje extraer los datos relacionales que se
necesiten.
Estos son los temas que se tratarán en los siguientes cuatro apartados:
FROM table
41/306
SQL
Las palabras clave o palabras reservadas de la sintaxis de la propia sentencia SELECT son las que
aparecen en mayúsculas. Estas palabras reservadas son también denominadas como cláusulas.
Las palabras reservadas no se pueden usar como nombres de columnas o nombre de otros objetos de la
base de datos. SELECT, DISTINCT y FROM son tres palabras clave; es decir, tres cláusulas SQL. La
sentencia SELECT siempre está compuesta por dos o más cláusulas. Las dos cláusulas obligatorias son
la cláusula SELECT y la cláusula FROM. El símbolo de la tubería (|) se usa para denotar la expresión
lógica OR.
A continuación, se muestra el uso más sencillo de la instrucción SELECT:
SELECT *
FROM table;
El símbolo de asterisco (*) se utiliza para hacer referencia a todas las columnas.
SELECT * es una forma concisa de pedirle al servidor de Oracle que devuelva todas las columnas
disponibles. Se usa como un atajo, un símbolo para ahorrar tiempo en vez de teclear SELECT column1,
column2,…,columnX, para seleccionar todas las columnas. La cláusula FROM especifica qué tabla
consultar para obtener (proyectar) las columnas solicitadas en la cláusula SELECT.
Se puede utilizar el siguiente comando SQL para recuperar todas las columnas y todas las filas de la tabla
REGIONS en el esquema HR:
SELECT *
FROM regions;
Cuando este comando se ejecuta en SQL * Plus, devuelve todos los registros de datos y todas las
columnas que pertenecen a esta tabla. El uso del asterisco en una instrucción SELECT a veces se
denomina consulta "ciega" porque las columnas que se deben buscar no están especificadas.
La segunda forma de la sentencia básica SELECT tiene la misma cláusula FROM que la primera forma,
pero la cláusula SELECT es diferente:
FROM table;
Un alias es un nombre alternativo para hacer referencia a una columna o expresión. Los alias se usan
generalmente para mostrar resultados de una manera fácil de usar. También sirven como atajo para
hacer referencia a columnas o expresiones para reducir teclear. Los alias se tratarán en detalle más
adelante en este capítulo.
Al enumerar explícitamente solo las columnas que se desean obtener en la cláusula SELECT, en efecto,
se proyecta el subconjunto exacto de los resultados referentes a dichas columnas. La siguiente consulta
devolverá solo el subconjunto de columnas REGION_NAME de la tabla REGIONS, tal y como se muestra
en la segunda consulta de la imagen de abajo.
42/306
SQL
SELECT region_name
FROM regions;
También se puede ver en la imagen cómo la primera consulta muestra tanto las columnas REGION_ID
como REGION_NAME.
Supóngase que se quieren obtener todos los roles laborales que ha ejercido un empleado en la
organización a lo largo de la historia. Para esto puede emitir la consulta SELECT * FROM JOB_HISTORY.
Sin embargo, SELECT * además devuelve las columnas EMPLOYEE_ID, START_DATE y END_DATE.
43/306
SQL
El uso de la palabra clave DISTINCT permite eliminar registros duplicados del conjunto de resultados. En
numerosas situaciones se requiere un conjunto de registros únicos. Es importante tener en cuenta que
el criterio empleado por el servidor Oracle para determinar si un registro es único o distinto a otro
depende completamente de lo que se especifique después de la palabra clave DISTINCT en la cláusula
SELECT. Seleccionar distintos valores JOB_ID de la tabla JOB_HISTORY devolverá los ocho tipos de
trabajos distintos, como se puede ver a continuación.
Comparando esta salida con la anterior, donde se devuelven diez registros. Se ve que hay dos apariciones
de los valores AC_ACCOUNT y ST_CLERK JOB_ID. Estos son los dos registros duplicadas que se han
eliminado buscando valores distintos JOB_ID con DISTINCT.
DISTINCT permite por lo tanto eliminar valores duplicados en combinaciones de columnas. Véase ahora
un ejemplo.
Hay diez registros en la tabla JOB_HISTORY. Ocho registros contienen distintos valores JOB_ID. Seis
registros contienen distintos valores DEPARTMENT_ID. ¿Cuántos registros contienen distintas
combinaciones de valores JOB_ID y DEPARTMENT_ID? En el conjunto de resultados se devuelven nueve
registros que contienen distintas combinaciones JOB_ID y DEPARTMENT_ID. Este es, por supuesto, el
registro que contiene un valor JOB_ID de ST_CLERK y un valor DEPARTMENT_ID de 50. Se puede ver el
resultado de la consulta y la propia consulta en la siguiente imagen:
44/306
SQL
45/306
SQL
La capacidad de proyectar columnas específicas desde una tabla es muy útil. Junto con la
capacidad de eliminar valores duplicados o combinaciones de valores, esto permite ayudar
con los requisitos básicos de informes de los usuarios. En muchas bases de datos de
aplicaciones, las tablas a veces pueden almacenar datos duplicados. Los informes del usuario
final frecuentemente requieren que estos datos se presenten como un conjunto manejable de
registros únicos. Hay que tener cuidado, sin embargo, al usar consultas ciegas para
seleccionar datos de tablas grandes. Ejecutando un SELECT * FROM huge_table; La sentencia
puede causar problemas de rendimiento si la tabla contiene millones de registros de datos.
a. Mayúsculas o minúsculas
Los ejemplos utilizados hasta ahora se han escrito en mayúsculas y minúsculas, utilizando las mayúsculas
para las palabras reservadas y las minúsculas para el resto de la declaración con fin de hacer más claros
los ejemplos. Muchos desarrolladores prefieren escribir sus declaraciones SQL en minúsculas. También
existe una idea errónea de que las palabras reservadas de SQL deben especificarse en mayúsculas. Se
aconseja adherirse a un formato consistente y estandarizado. Las siguientes tres declaraciones son
sintácticamente equivalentes:
46/306
SQL
Hay un caso a tener en cuenta sobre la sensibilidad de mayúsculas y minúsculas. Al interactuar con
valores literales, el uso de mayúsculas o minúsculas sí importa. Se considera la columna JOB_ID de la
tabla JOB_HISTORY. Esta columna contiene registros de datos que se almacenan en la base de datos en
mayúsculas, por ejemplo, SA_REP y ST_CLERK. Al solicitar que el conjunto de resultados esté restringido
por el valor literal de los campos de una columna, el uso de mayúsculas o minúsculas es crítico para
obtener un resultado u otro. El servidor de Oracle trata la solicitud de todos los registros en la tabla
JOB_HISTORY que contienen un valor de St_Clerk en la columna JOB_ID diferente de la solicitud para
todos los registros que tienen un valor de ST_CLERK en la columna JOB_ID.
Los metadatos sobre diferentes objetos de la base de datos se almacenan de forma predeterminada en
mayúsculas en el diccionario de datos. Si se consulta una tabla diccionario de una base de datos para
devolver una lista de tablas del esquema HR, es probable que los nombres de tabla devueltos se
almacenen en mayúsculas. Esto no significa que no se pueda crear una tabla con un nombre en
minúscula; puede ser. Es más común y es el comportamiento predeterminado del servidor de Oracle
crear y almacenar tablas, columnas y otros metadatos de objetos de base de datos en mayúsculas en el
diccionario de la base de datos.
b. Finalizar sentencias
Los puntos y coma se usan generalmente para finalizar consultas SQL. SQL * Plus siempre requiere
terminar la sentencia, y generalmente se usa un punto y coma.
Una sola instrucción SQL o incluso grupos de consultas asociadas a menudo se guardan como script para
uso futuro.
Las sentencias individuales en las secuencias de comandos SQL suelen terminarse mediante un salto de
línea (o retorno de carro) y una barra diagonal (/) en la siguiente línea, en lugar de un punto y coma.
Se puede crear una instrucción SELECT, terminarla con un salto de línea, incluir una barra inclinada para
ejecutar la instrucción y guardarla en un script. El script se puede llamar desde SQL * Plus. Hay que
tener en cuenta que SQL Developer no requiere de finalizar explícitamente una consulta si esta es la
única instrucción que debe ejecutarse, pero no es incorrecto utilizar un finalizador de sentencia. Es una
buena práctica terminar siempre las consultas SQL con un punto y coma. A continuación, se incluyen
varios ejemplos de sentencias SQL * Plus:
47/306
SQL
En el primer ejemplo se expone una consulta SELECT terminada con un punto y coma y escrita en una
sola línea. Es totalmente aceptable que una instrucción SQL se escriba en una línea o abarque varias
líneas, siempre que no haya palabras cortadas.
Este segundo ejemplo muestra una instrucción que abarca tres líneas y que finaliza con una nueva línea,
la sentencia es ejecutada cuando aparece el carácter (/).
Este ejemplo destaca los beneficios de sangrar una consulta SQL para mejorar la legibilidad del código
(el servidor de Oracle también acepta si la declaración completa está escrita en una línea sin sangría).
Es una buena práctica separar diferentes cláusulas de la instrucción SELECT en diferentes líneas.
El intérprete de SQL es mucho más manejable durante el proceso de desarrollo si las expresiones
complejas se aíslan en líneas separadas, ya que los errores suelen mostrarse en el formato de: "ERROR
en la línea X:". Esto hace que el proceso de depuración sea mucho más simple.
Un solo signo de puntuación faltante, como un punto y coma, puede marcar la diferencia entre
una consulta correcta y una incorrecta.
Problema Solución
Se quiere construir y ejecutar consultas No. Oracle proporciona SQL * Plus y SQL
en tablas almacenadas en una base de Developer como herramientas gratuitas
para crear y ejecutar consultas. Existen
datos Oracle. ¿Es obligatorio el uso de
numerosas herramientas disponibles de
SQL*Plus o SQL Developer? Oracle (por ejemplo, Discoverer, APEX y
JDeveloper) y otros proveedores
externos que proporcionan una interfaz
para trabajar con las tablas de una base
de datos Oracle.
48/306
SQL
Al consultar la tabla JOBS para cada Se realiza una proyección ya que las
registro que contiene solo las columnas columnas en la tabla JOBS se han
restringido a las columnas JOB_ID y
JOB_ID y MAX_SALARY, ¿se está
MAX_SALARY.
realizando una proyección, selección o
unión?
Como en la aritmética regular, hay un orden predefinido de evaluación (prioridad del operador) cuando
existe más de un operador en una expresión. Los paréntesis tienen la mayor prioridad. Las operaciones
de división y multiplicación son las siguientes en la jerarquía y se evalúan antes de la suma y la resta,
que tienen la prioridad más baja. Los operadores con el mismo nivel de prioridad se evalúan de izquierda
a derecha.
Por lo tanto, los paréntesis pueden utilizarse para evaluar y otorgar prioridad a lo que haya dentro de
ellos, sea el operador que sea. Se recomienda utilizar paréntesis generosamente cuando se construyen
consultas complejas ya que conduce a un código legible que es menos propenso a errores.
49/306
SQL
a. Operadores aritméticos
Considérese el ejemplo de la tabla JOB_HISTORY, que almacena la fecha de inicio y la fecha de finalización
referentes al tiempo que ha permanecido un empleado en un cargo de trabajo anterior. Puede ser útil
para fines tributarios o de pensión, por ejemplo, calcular cuánto tiempo trabajó ese empleado en ese
cargo. Esta información se puede obtener usando una expresión aritmética. A continuación se ve un
ejemplo de esta consulta, en la cual hay algunos elementos interesantes tanto en la propia consulta SQL
como de los resultados obtenidos (el resultado es devuelto en horas).
Se han especificado siete operaciones en la cláusula SELECT. Las primeras cuatro son columnas regulares
de la tabla JOB_HISTORY, concretamente: EMPLOYEE_ID, JOB_ID, START_DATE y END_DATE. Los dos
últimos términos proporcionan la información de origen necesaria para calcular la cantidad de días y
horas que un empleado ocupó un puesto determinado.
Véase el número de empleado 176 en el noveno registro de salida. Este empleado comenzó como gerente
de ventas el 1 de enero de 2007 y finalizó el empleo el 31 de diciembre de 2007. Por lo tanto, este
empleado trabajó durante exactamente un año, que en 2007 consistió en 365 días o 2.920 horas.
El número de días para los cuales un empleado estuvo contratado se puede calcular utilizando el quinto
término en la cláusula SELECT, que es una expresión. Esta expresión demuestra que la aritmética
realizada en columnas que contienen información de fecha arroja valores numéricos que representan un
cierto número de días. El sexto término se asemeja mucho al quinto, pero calcula el número de horas
trabajadas al multiplicar por 8 (suponiendo un día laboral de 8 horas).
Para imponer la prioridad del operador de las operaciones de resta y suma en el sexto término, la
subexpresión end_date - start_date + 1 está encerrada entre paréntesis y luego multiplicada por 8 para
obtener la cantidad correcta de horas trabajadas. El séptimo término se evalúa primero multiplicando 1
por 8, que se agrega a end_date - start_date, que devuelve los resultados incorrectos.
50/306
SQL
Véase ahora otro ejemplo. Se ha diseñado una fórmula hipotética para predecir la probabilidad de una
lluvia de meteoritos en una región geográfica particular. Las dos consultas que aparecen en la imagen
siguiente son idénticas, excepto por la expresión Meteor Shower Probability.
Sin embargo, como lo demuestran los resultados en la siguiente tabla, cada expresión está haciendo un
cálculo diferente. Hay que tener cuenta que las dos expresiones difieren muy levemente. La segunda
consulta tiene un par de paréntesis al final, que engloban (10 - 5).
Véase como son evaluada para Asia (con REGION_ID 3) las expresiones de ambas consultas:
51/306
SQL
3. Los operadores con la prioridad más alta son El operador con la prioridad más alta es el par
los operadores de división y multiplicación. de paréntesis y estos deben evaluarse primero.
Por lo tanto, la primera subexpresión que se
Estos deben ser evaluados primero. Si más de evaluará es: (10 - 5): 3*100/5 + 20/5
un operador con el mismo nivel de prioridad
está presente en una expresión, luego estos se
evaluarán de izquierda a derecha. Por lo tanto,
la primera subexpresión que se evaluará es: 3 *
100: 300/5 + 20/10 - 5
5. La siguiente subexpresión a evaluar es: 20/10: La siguiente subexpresión que se evaluará es:
60 + 2 - 5 300/5: 60 + 20/5
6. Los operadores restantes son operadores de La siguiente subexpresión que se evaluará es:
suma y resta que comparten el mismo nivel de 20/5: 60 + 4 = 64
prioridad. Por lo tanto, estos se evaluarán de
izquierda a derecha. La siguiente subexpresión
a evaluar es:
60 + 2: 62 - 5 = 57
52/306
SQL
En el segundo ejemplo de la imagen anterior, se ilustra otra característica interesante de los alias de
columnas. Se ha prescindido de las comillas dobles y, en lugar del carácter espacio, se ha puesto un
guion bajo entre Days y Worked, de forma que Days_Worked es una sola palabra y ya no hay error. El
intérprete de Oracle procesa la sentencia, no encuentra ningún problema y la ejecuta. Aunque el alias se
53/306
SQL
especificó como Days_Worked, el encabezado de consulta se devolvió como DAYS_WORKED: todas las
letras se convirtieron automáticamente a mayúsculas. Por lo tanto, para que se preserven las mayúsculas
y minúsculas del alias, este deberá estar entre comillas dobles.
Los alias encontrados hasta el momento se han especificado dejando un espacio después de una columna
o expresión e insertando el nombre del alias. SQL ofrece una manera más formal de utilizar alias, y es
haciendo uso de la palabra clave AS, la cual se debe poner tras el nombre de la columna o expresión y
delante del nombre que se le quiera dar al propio alias.
La siguiente imagen ilustra las diferentes formas de poner alias a las columnas. Tanto las columnas
EMPLOYEE_ID como JOB_ID reciben un alias utilizando la palabra clave AS, mientras que la consulta
"Days Worked" recibe un alias utilizando un espacio. La palabra clave AS es por lo tanto opcional; sin
embargo, el uso de AS mejora la legibilidad de las consultas.
54/306
SQL
La figura anterior muestra que el operador de concatenación puede ser usado múltiples veces y casi en
cualquier lugar en una expresión de caracteres.
Aquí se concatena el carácter de cadenas "The" con el contenido de datos de la columna REGION_NAME.
Esta nueva cadena de caracteres se concatena con la cadena de caracteres "region is on Planet Earth",
y toda la expresión tiene el alias "Planetary Location". Se puede observar cómo se construye cada registro
del conjunto de resultados mediante la aplicación sistemática de la expresión a cada valor del registro
de la tabla.
Véase el primer registro de datos de la columna "Planetary Location", el cual devuelve "The Europe region
is on Planet Earth". Se ha creado una frase legible para los registros de datos mediante la concatenación
de cadenas de caracteres y espacios a ambos lados del valor de la columna REGION_NAME de cada
registro. A la columna REGION_ID se le ha puesto un alias para mostrar que tanto las columnas regulares
como las expresiones pueden recibir un alias. Además, los encabezados de columna se muestran por
defecto en mayúsculas, pero se pueden sustituir con un alias como "Region Id".
55/306
SQL
¿Qué hay del procesamiento de cadenas de caracteres que no tienen nada que ver con los datos de
columnas existentes? Para asegurar la consistencia relacional, Oracle ofrece una solución inteligente al
problema de usar la base de datos para evaluar expresiones que no tienen nada que ver con ninguna
tabla o columna.
Para que la base de datos evalúe una expresión, se debe enviar una sentencia SELECT sintácticamente
correcta. ¿Y si se quisiera saber la suma de dos números o dos cadenas de caracteres de tipo numérico?
Esta información sólo se puede obtener interactuando con la base de datos de manera relacional.
Oracle soluciona el problema de las interacciones relacionales con una base de datos que opera con
expresiones de cadena de caracteres a través de una tabla “especial” denominada DUAL.
La tabla DUAL está constituida por una única columna de tipo de dato carácter. Permite evaluar
expresiones constituidas por cadenas de caracteres y devolver el nuevo valor de la expresión para su
posterior procesamiento.
Se va a presentar un ejemplo sobre cómo calcular los segundos que hay en un año.
La figura anterior muestra una consulta aritmética ejecutada en la tabla DUAL. Probar expresiones
complejas durante el desarrollo, a través de la tabla DUAL, es un método eficaz para evaluar si estas
expresiones están funcionando correctamente. Las expresiones de cadenas de caracteres pueden ser
consultadas desde cualquier tabla, pero cabe recordar que será procesada para cada registro de la tabla.
56/306
SQL
La consulta anterior devolverá cuatro registros en el conjunto de resultados, ya que hay cuatro registros
de datos en la tabla REGIONS.
¿Qué hay de las cadenas de caracteres que contienen comillas simples? Por ejemplo, si se añade un
apostrofo, eso causaría un error ya que se considerará como final de la cadena de caracteres.
Véase, la siguiente consulta:
Al ejecutar esta consulta se genera un error de Oracle ORA-01756. Puede parecer un error extraño, pero
al examinarlo más de cerca, el intérprete de Oracle procesa con éxito la instrucción SELECT hasta la
posición 16, momento en el que espera una cláusula FROM. La posición 1 a la posición 16 es:
select 'Plural's
El servidor de Oracle procesa este segmento como si “s” fuese el alias de ‘Plural’.
En este punto, el intérprete espera una cláusula FROM, pero en su lugar encuentra la palabra "have". A
continuación, se genera el error.
Entonces, ¿cómo se tratan las palabras que contienen comillas simples? Hay esencialmente dos
mecanismos disponibles. El más popular de ellos es añadir una comilla simple adicional junto a cada
comilla simple natural en la cadena de caracteres.
La imagen siguiente muestra que usando comillas simples, para arreglar el problema anterior, puede
volverse un tanto confuso en el caso que se dé muchas veces en una misma consulta.
57/306
SQL
Para solucionarlo, Oracle propone otra alternativa: el operador alternativo q, de quote en inglés.
El operador q permite elegir entre un conjunto de caracteres para sustituir y hacer el papel de las comillas
simples.
Las opciones son cualquier carácter de un byte o multibyte o en su defecto (paréntesis), {llaves},
[corchetes], o < signos de menor que y mayor que >. Usando el operador q, el delimitador de caracteres
puede ser cambiado de una sola comilla a cualquier otro carácter, como se muestra en la figura siguiente.
58/306
SQL
q'delimiter carácter literal que puede incluir las comillas simples delimiter'
Donde delimiter puede ser cualquier carácter o paréntesis. Los ejemplos primero y segundo de la imagen
anterior muestran el uso de corchetes y signos de menor que y mayor que como delimitadores de
caracteres, mientras que el tercer ejemplo demuestra cómo se ha utilizado una "X" mayúscula como
símbolo delimitador de caracteres especiales.
59/306
SQL
no se tiene en cuenta el tratamiento especial que requieren los valores nulos, cabe la posibilidad que
produzca un error o, peor aún, una respuesta inexacta.
Los valores nulos pueden ser un concepto difícil de entender. No es un valor real y tangible que pueda
relacionarse con el mundo físico. NULL es un marcador de posición en memoria en una columna no
obligatoria (NOT NULL column) hasta que algunos datos reales se almacenan en su lugar.
Esta sección pretende interactuar con campos o valores nulos (NULL) en consultas SELECT para poder
observar los resultados de valores nulos en diferentes expresiones.
NULLABLE es un término que, por lo tanto, se utiliza para describir una columna que puede contener
valores nulos. Una de las columnas NULLABLE es la columna COMMISSION_PCT.
Esta figura muestra los primeros cinco registros de datos de la tabla EMPLOYEES. Esto es suficiente para
ver que todos estos registros de empleado tienen valores nulos en sus columnas COMMISSION_PCT.
60/306
SQL
SQL Developer facilita la visualización de valores nulos en columnas, como se muestra en la segunda
figura. Aquí, la palabra (null) se muestra en el resultado de la consulta cuando se encuentra un valor
nulo, como en la columna COMMISSION_PCT. SQL Developer soporta la personalización de esta
descripción predeterminada de datos nulos.
61/306
SQL
La columna con el alias "Null Arithmetic" es una expresión compuesta por COMISSION_PCT + SALARY +
10. En lugar de devolver un valor numérico, esto devuelve un valor nulo. Hay una razón importante por
la que sucede esto:
Oracle ofrece un mecanismo para interactuar aritméticamente con valores NULL usando las funciones
generales discutidas en el Capítulo 5. Como la expresión de la columna con el alias "Division by Null"
ilustra, incluso la división por un valor nulo resulta en nulo, a diferencia de la división por cero, que da
como resultado un error. Por último, obsérvese el impacto del valor nulo cuando se utiliza con el operador
de concatenación de caracteres. NULL está concatenado entre las columnas FIRST_NAME y LAST_NAME,
pero no tiene ningún impacto.
Los operadores de concatenación de caracteres ignoran los valores nulos, mientras que las operaciones
aritméticas que involucran valores nulos siempre resultan nulas.
62/306
SQL
¿Pero qué hay de los valores NULL? ¿Puede la columna DEPARTMENT_ID en la tabla DEPARTMENTS
contener valores nulos? La respuesta es no. Oracle insiste en que cualquier columna que es una clave
primaria está implícitamente restringida a ser obligatoria (NOT NULL). ¿Pero qué hay de las restricciones
implícitas en las claves foráneas? Este es un problema para Oracle, ya que, para permanecer flexible, no
puede pedir que las columnas relacionadas a través de restricciones de integridad referenciales deban
ser obligatorias. Además, no todas las situaciones exigen esta funcionalidad.
La columna DEPARTMENT_ID de la tabla EMPLOYEES puede contener valores nulos. Por lo tanto, existe
el riesgo de que existan registros con valores DEPARTMENT_ID nulos presentes en esta tabla. De hecho,
existen tales registros en la tabla EMPLOYEES. El modelo de datos de HR permite que los empleados,
correctamente o no, no pertenezcan a ningún departamento. Cuando se realizan uniones relacionales
entre tablas, es totalmente posible que se pierda o excluyan ciertos registros que contienen nulos en la
columna de unión. En el capítulo 7 se verán las formas de hacer frente a este desafío mediante el uso
de uniones externas.
Problema Solución
63/306
SQL
2.3. Resumen
Listar las Posibilidades de la Sentencia SQL SELECT
• Las tres operaciones fundamentales de las sentencias SELECT son proyección, selección y unión.
• Proyección hace referencia a la restricción de columnas seleccionadas de una tabla. Usando
proyección, se recuperan sólo las columnas de interés.
• Selección hace referencia a la extracción de registros de una tabla. La selección incluye la
restricción adicional de los registros extraídos basados en varios criterios o condiciones. Esto
permite recuperar sólo los registros que son de interés y no todos los registros de la tabla.
• Unión implica enlazar dos o más tablas basadas en campos comunes. La unión permite que los
datos se almacenen en tercera forma normal en tablas discretas, en lugar de en una gran tabla.
• Una combinación ilimitada de proyecciones, selecciones y uniones proporciona el lenguaje para
extraer los datos relacionales requeridos.
• La definición estructural de una tabla puede obtenerse usando el comando DESCRIBE.
• Las columnas de las tablas almacenan diferentes tipos de datos, los más comunes son NUMBER,
VARCHAR2, DATE, y TIMESTAMP.
• El tipo de datos NUMBER(p, s) almacena datos numéricos, tanto enteros como decimales, con o
sin signo. Precisión (p), indica el número máximo de dígitos que va a tener el dato. Escala (s),
indica el número de dígitos que puede haber a la derecha del punto decimal.
• El comando DESCRIBE lista los nombres, tipos de datos y si una columna puede ser o no NULL.
• Las columnas obligatorias también se denominan columnas NOT NULL.
64/306
SQL
• La sentencia SELECT también se denomina consulta SELECT y está comprendida por al menos
dos cláusulas, a saber, la cláusula SELECT y la cláusula FROM.
• La cláusula SELECT determina la proyección de las columnas. En otras palabras, la cláusula
SELECT especifica qué columnas se incluyen en los resultados devueltos.
• El operador asterisco (*) se utiliza como símbolo comodín para indicar todas las columnas. Así,
la sentencia SELECT * FROM accounts devuelve todas las columnas disponibles en la tabla
ACCOUNTS.
• La cláusula FROM especifica la tabla o tablas fuente a partir de las cuales los datos son
seleccionados.
• La palabra clave DISTINCT se añade a las sentencias SELECT, justo después de la palabra clave
SELECT. Devuelve valores únicos, ya que, en una tabla, una columna puede contener valores
duplicados y algunas veces sólo se necesita un listado de los valores diferentes.
• Las sentencias SQL deben terminar con punto y coma. Como alternativa, se puede añadir una
nueva línea después de una sentencia y se puede utilizar una barra oblicua hacia delante (/) para
que se ejecute la expresión.
• Las sentencias SQL pueden escribirse y ejecutarse en minúsculas, mayúsculas o mixto. Se debe
tener cuidado al interactuar con las cadenas de caracteres ya que distinguen entre mayúsculas
y minúsculas.
• Los operadores aritméticos y el operador de concatenación de cadenas que actúan sobre datos
de columna y las cadenas de caracteres forman la base de las expresiones SQL.
• Se puede utilizar un alias para las expresiones y columnas regulares utilizando la palabra clave
AS o dejando un espacio entre la columna o expresión y el alias.
• Si un alias contiene varias palabras o en caso de que la combinación entre mayúsculas y
minúsculas sea relevante en el alias, debe ir entre comillas dobles.
• Para poder incluir dentro de una cadena de caracteres comillas dobles se tiene que encapsular
dentro de comillas simples.
• La tabla DUAL es una tabla de una sola columna y un solo registro que se utiliza a menudo para
evaluar expresiones que no tienen que ver con columnas o tablas específicas.
• Las columnas que no tienen una restricción NOT NULL tienen la opción para almacenar valores
nulos y a veces se denominan columnas nulas (nullable columns).
• Los valores NULL no son lo mismo que un espacio en blanco o cero. Los valores NULL hacen
referencia una ausencia de datos. El valor nulo (NULL) se define como un valor que no está
disponible, no asignado, desconocido o inaplicable.
• Hay que tener cuidado cuando se trabaja con valores nulos ya que las operaciones aritméticas
con un valor nulo siempre producen un resultado nulo.
65/306
SQL
La cláusula WHERE especifica una o más condiciones que el servidor Oracle evalúa para restringir los
registros devueltos por la petición. Otra mejora del lenguaje se introduce con la cláusula ORDER BY que
proporciona capacidades de clasificación de datos.
La sustitución por ampersand (&) proporciona una forma de reutilizar la misma sentencia para ejecutar
diferentes consultas mediante la sustitución de elementos de consulta en tiempo de ejecución. Este
capítulo concluye con una exploración de esta técnica de encuadernación en tiempo de ejecución en
sentencias SQL.
Uno de los principios fundamentales de la teoría relacional es la selección. La selección se actualiza
utilizando la cláusula WHERE de la secuencia SELECT. Las condiciones que restringen el conjunto de datos
devuelto adoptan muchas formas y funcionan tanto en columnas como en expresiones. Sólo los registros
en la tabla que se adecúen a estas condiciones serán devueltos. Las condiciones restringen los registros
que utilizan operadores de comparación junto con columnas y valores literales. Los operadores booleanos
proporcionan un mecanismo para especificar múltiples condiciones para restringir los registros devueltos.
Se discuten los operadores booleanos, condicionales, de concatenación y aritméticos para establecer su
orden de precedencia cuando se encuentran en una sentencia SELECT.
• La cláusula WHERE
• Los operadores de comparación
• Operadores booleanos Reglas de precedencia
La cláusula WHERE siempre sigue a la cláusula FROM. Los corchetes indican que la cláusula WHERE es
opcional. Se pueden aplicar simultáneamente una o más condiciones para restringir el conjunto de
resultados. Una condición se especifica comparando dos términos utilizando un operador condicional.
Estos términos pueden ser valores de columna, literales o expresiones. El operador de igualdad es el más
utilizado para restringir los conjuntos de resultados. A continuación se muestran dos ejemplos de las
cláusulas WHERE:
66/306
SQL
SELECT country_name
FROM countries
WHERE region_id=3;
El segundo ejemplo devuelve dos columnas, LAST_NAME y FIRST_NAME de la tabla EMPLOYEES. Los
registros devueltos se limitan a las que contienen el valor SA_REP en sus columnas JOB_ID.
67/306
SQL
Una columna numérica puede ser comparada con otra columna numérica en el mismo registro para
construir una condición en la cláusula WHERE, como muestra la siguiente consulta:
En el ejemplo de la figura que se muestra más abajo se puede apreciar como la cláusula WHERE es
demasiado restrictiva y no se selecciona ningún registro. Esto se debe a que el rango de SALARY es de
2100 a 24000, y el rango de valores de DEPARTMENT_ID es de 10 a 270. Dado que no hay solapamiento
en el rango de DEPARTMENT_ID y SALARY, no hay registros que satisfagan esta condición y, por lo tanto,
la consulta no devuelve ningún resultado. El ejemplo también ilustra cómo una condición de cláusula
WHERE compara una columna numérica con otra. El segundo ejemplo de la figura muestra la extensión
de la cláusula WHERE para comparar una columna numérica SALARY con la expresión numérica:
DEPARTMENT_ID*100. Para cada registro, el valor de la columna SALARY es comparado con el producto
del valor DEPARTMENT_ID y 100. La cláusula WHERE también permite expresiones a ambos lados del
operador de comparación. Se puede emitir la siguiente expresión para obtener resultados idénticos:
Como en álgebra regular, la expresión (SALARY = DEPARTMENT_ID * 100) es equivalente a (SALARY /10
= DEPARTMENT_ID * 10). La característica notable de este ejemplo es que los términos a ambos lados
del operador de comparación son expresiones.
68/306
SQL
SELECT last_name
FROM employees
WHERE job_id='SA_REP';
Si se intenta especificar la cadena de caracteres sin las comillas, se producirá un error de Oracle.
Recuerde que los datos de cadena de caracteres se distinguen entre mayúsculas y minúsculas, por lo
que las siguientes cláusulas WHERE no son equivalentes.
Cláusula 1 genera un error “ORA-00904: “SA_REP”: invalid identifier” ya que la cadena de caracteres
SA_REP no está envuelto en comillas simples. Cláusula 2 y 3 son sintácticamente correctas pero no
equivalentes. Además, ninguna de estas cláusulas produce datos ya que no hay registros en la tabla
EMPLOYEES que tengan valores de columna JOB_ID que sean Sa_Rep o sa_rep,sino SA_REP como se
muestra en la siguiente figura:
69/306
SQL
Las condiciones basadas en caracteres no se limitan a comparar valores de columna con cadenas de
texto exactas. También se pueden especificar utilizando otras columnas tipo texto y expresiones. Las
columnas LAST_NAME y FIRST_NAME se especifican como columnas escritas con datos VARCHAR2(25).
Se considera la consulta:
Tanto la columna LAST_NAME como la columna FIRST_NAME aparecen a ambos lados del operador de
igualdad en la cláusula WHERE. No hay cadenas de caracteres exactas presentes en la consulta; por lo
tanto, no se necesitan comillas para delimitarlos. Esta condición estipula que sólo se devolverán los
registros que contengan el mismo valor de datos (una coincidencia exacta entre mayúsculas y
minúsculas) en las columnas LAST_NAME y FIRST_NAME. Esta condición es demasiado restrictiva y,
como muestra la figura siguiente, no se devuelven registros.
70/306
SQL
Las expresiones basadas en caracteres forman una o ambas partes de una condición separadas por un
operador condicional. Estas expresiones pueden formarse concatenando cadenas de caracteres o
caracteres simples con una o más columnas de caracteres. Las siguientes cuatro cláusulas muestran
algunas de las opciones para las condiciones basadas en caracteres:
La cláusula 1 concatena el carácter "A" con las columnas LAST_NAME y FIRST_NAME. Esta expresión se
compara con la cadena de caracteres "A King" y se devuelve cualquier registro que cumpla esta condición.
La cláusula 2 demuestra que las expresiones de caracteres pueden colocarse a ambos lados del operador
condicional. La cláusula 3 demuestra que las expresiones de cadenas de caracteres también pueden
colocarse a la izquierda del operador condicional. Es lógicamente equivalente a la cláusula 4, que ha
cambiado los operando de la cláusula 3. Tanto la cláusula 3 como la cláusula 4 tienen como resultado
que se devuelva el mismo registro de datos, como se muestra en la figura siguiente.
71/306
SQL
72/306
SQL
El primer enunciado pone a prueba la igualdad entre dos columnas de tipo DATE. Los registros que
contengan los mismos valores en sus columnas START_DATE y END_DATE serán devueltos. Hay que
tener en cuenta, sin embargo, que los valores tipo DATE sólo son iguales entre sí si hay una coincidencia
exacta entre todos sus componentes, incluyendo día, mes, año, horas, minutos y segundos. En la cláusula
WHERE de la segunda sentencia, la columna START_DATE se compara con el carácter literal '01-JAN-
2001'. Se ha especificado todo el componente de cuatro dígitos del año (YYYY). Esto es aceptable para
el servidor Oracle, y se devolverán todos los registros de la tabla JOB_HISTORY con valores de columna
START_DATE iguales al 1 de enero de 2001.
73/306
SQL
Esta consulta devuelve los registros de la tabla JOB_HISTORY que contiene un valor de START_DATE
igual a 1 día antes del 25-MAR-2006. Por lo tanto, sólo se recuperarán los registros con un valor de
24MAR-2006 en la columna START_DATE.
74/306
SQL
que contiene la columna es nulo. Estos operadores pueden ser combinados en la cláusula WHERE y serán
analizados a continuación.
a. Igualdad y desigualdad
Limitar los registros devueltos por una consulta conlleva especificar una cláusula WHERE adecuada. Si la
cláusula es demasiado restrictiva, entonces la consulta devolverá uno (o incluso ningún) registro. Por el
contrario, si la condición es demasiado amplia, entonces serán devueltos más registros que los
solicitados.
Analizando los diferentes operadores válidos, éstos deben estar provistos del lenguaje requerido para
devolver exactamente los registros que interesan. Comprobar por igualdad en una condición debe ser
tanto natural como intuitivo. Tal condición se forma utilizando el operador “es igual que” (=). Se
devolverá un registro si la condición de igualdad es verdadera para este registro. Se considera la siguiente
consulta:
Se comprueba si la columna JOB_ID en cada registro de la tabla EMPLOYEES coincide literalmente con
los caracteres SA_REP. Deben coincidir todos los caracteres, siendo sensible a mayúsculas y minúsculas.
Cuando se encuentra una coincidencia, los valores para las columnas seleccionadas LAST_NAME y
SALARY se devuelven para este registro como se muestra en la siguiente Figura.
75/306
SQL
Nótese que, aunque la cláusula condicional se basa en la columna JOB_ID, no es necesario que esta
columna sea seleccionada para la consulta.
Las condiciones basadas en desigualdad mejoran la especificación de la cláusula WHERE. En las
comparaciones por rango y por patrón de coincidencia es posible utilizar operadores de igualdad y
desigualdad, pero es preferible utilizar los operadores BETWEEN y LIKE para este tipo de comparaciones.
Los operadores de desigualdad son descritos en la siguiente tabla.
OPERADORES DESCRIPCIÓN
!= Distinto que
Los operadores de desigualdad permiten que se satisfagan las consultas basadas en rangos. Se debe
proporcionar un conjunto de resultados cuando el valor de una columna es mayor que otro. Por ejemplo,
se puede realizar la siguiente consulta para obtener una lista de valores de LAST_NAME y SALARY para
empleados que ganan más de 5000$:
Análogamente, para obtener una lista de empleados que ganan menos de 3000$, se puede realizar la
siguiente consulta:
Los operadores de desigualdad compuestos (es decir, que tienen más de un símbolo) son utilizados es
las siguientes cuatro cláusulas:
76/306
SQL
La cláusula 1 devuelve los registros que contienen un valor de SALARY menor o igual que 3000. La
cláusula 2 obtiene datos donde el valor de SALARY es mayor o igual que 5000, mientras que las cláusulas
3 y 4 manifiestan las dos formas de los operadores “distinto que”. La cláusula 3 devuelve los registros
con los valores de la columna SALARY que no son iguales a los valores de DEPARTAMENT_ID. El operador
alternativo de “distinto que” en la cláusula 4 muestra las columnas, cadenas de caracteres y expresiones
que pueden ser comparadas usando operadores de desigualdad. Esta cláusula devuelve los registros que
contienen un valor de SALARY que es distinto a la suma de 4000 y del valor de DEPARTAMENT_ID para
este registro.
La desigualdad numérica es intuitiva. La comparación de caracteres y fechas, sin embargo, son más
complejas. Comprobar la desigualdad de caracteres es interesante ya que se comparan las cadenas
situadas a ambos lados del operador de desigualdad en orden lexicográfico. Basado en el conjunto de
caracteres de la base de datos y en NLS (National Language Support –Soporte en idioma nacional-),
cada cadena de caracteres se evalúa utilizando un método de comparación binario o lingüístico. En los
conjuntos de caracteres en inglés, las comparaciones semánticas actúan como se describen en este
capítulo. Con el método predeterminado de comparación binaria, los caracteres tienen asignados un valor
numérico con espacios en blanco, teniendo un valor menor que otros caracteres. Estos valores numéricos
forman la base para la evaluación de la comparación por desigualdad. Se considera la siguiente sentencia:
SELECT last_name
FROM employees
WHERE last_name < 'King';
77/306
SQL
Esta consulta recupera el apellido y la fecha de contratación de cada registro de empleado que contiene
un valor de HIRE_DATE anterior a ’01-JAN-2003’. Se devuelven los registros con HIRE_DATE de
empleados a fecha de 31-DEC-2002 o anterior, mientras que los registros con valores de HIRE_DATE de
empleados posteriores a 1 de enero de 2003 no serán devueltos, como se muestran en la siguiente
Figura:
Si se quiere buscar los apellidos y los salarios de los empleados que ganan un salario en el rango de
3400$ y 4000$, una posible solución utilizando el operador BETWEEN será la siguiente:
Este operador permite que la condición WHERE sea leída de manera natural. Se devolverán los apellidos
y salarios de todos los empleados que ganan entre 3400$ y 4000$. Los operadores booleanos como AND,
78/306
SQL
OR y NOT serán analizados más adelante en este capítulo, aunque serán introducidos aquí para mejorar
la descripción del operador BETWEEN. El operador AND es utilizado para especificar múltiples condiciones
WHERE, las cuales deben cumplirse para que un registro sea devuelto. Al utilizar el operador AND, el
operador BETWEEN es equivalente a utilizar dos condiciones con los operadores “mayor o igual que” y
“menor o igual que”, respectivamente. La sentencia SQL anterior es equivalente a utilizar la siguiente
sentencia:
SELECT last_name
FROM employees
WHERE salary >= 3400 AND salary <= 4000;
Para el valor de SALARY de un registro, se comprueba primero si éste es mayor o igual que 3400 y,
seguidamente, si es menor o igual que 4000. Si ambas condiciones se cumplen el valor de LAST_NAME
del registro forma parte del conjunto de resultados. Por el contrario, si solo una o ninguna de las
condiciones se satisfacen, el registro no será seleccionado.
79/306
SQL
Por lo tanto, las condiciones especificadas con el operador BETWEEN se pueden denotar de forma
equivalente utilizando dos condiciones de desigualdad, pero es más corto y sencillo especificar el rango
utilizando el operador BETWEEN. La implicación de esta equivalencia es que el mecanismo utilizado para
evaluar operandos numéricos, caracteres y fechas por operadores de desigualdad es lo mismo que por
el operador BETWEEN. La siguiente consulta comprueba si el valor de la columna HIRE_DATE es igual o
posterior a 24-JUL-2004 pero igual o anterior a 07-JUN-2007:
No está restringido a utilizar valores cadenas de caracteres en los operandos del operador BETWEEN, ya
que pueden ser valores de columnas y expresiones tales como la siguiente:
Para que un registro sea devuelto por esta consulta, la cadena de caracteres tipo fecha 24-JUL-1994 debe
estar entre los registros de los valores de la columna HIRE_DATE más 30 días y la cadena de caracteres
tipo fecha 07-JUN-2007.
El valor de SALARY en cada registro es comparado por igualdad a las cadenas de caracteres especificados
en el conjunto. Si los valores de SALARY son iguales a 3000, 4000 o 6000, los valores de LAST_NAME y
SALARY para esos registros serán devueltos. El operador booleano OR, que se analizará después en este
capítulo, es usado para especificar múltiples condiciones en la cláusula WHERE, donde al menos una de
ellas debe cumplirse para que el registro sea devuelto. El operador IN es, por lo tanto, equivalente a una
serie de condiciones OR. La sentencia SQL anterior puede ser reescrita utilizando múltiples condiciones,
por ejemplo:
80/306
SQL
OR salary = 6000;
Esta sentencia devolverá los valores de LAST_NAME y SALARY de empleados si al menos una de las
condiciones de la cláusula WHERE es verdadera; esto tiene el mismo significado que la sentencia anterior
en la que se utilizaba el operador IN, como se muestra en la Figura siguiente:
Los componentes del conjunto de pruebas utilizando el operador IN se realizan de manera más rápida
que con múltiples condiciones OR, especialmente a medida que aumenta el número de elementos en el
conjunto. Las dos sentencias siguientes muestran el uso del operador IN con datos tipo DATE y
CHARACTER.
SELECT last_name
FROM employees
WHERE last_name IN ('King','Garbharran','Ramklass');
SELECT last_name
FROM employees
WHERE hire_date IN ('01-JAN-1998','01-DEC-1999');
81/306
SQL
La siguiente consulta puede utilizarse para proporcionar una lista de empleados cuyo primer nombre
empieza por la letra “A”:
SELECT first_name
FROM employees
WHERE first_name LIKE 'A%';
El carácter con el que se compara la columna FIRST_NAME está encerrado entre comillas simples como
un carácter. Además, tiene un símbolo de porcentaje, el cual tiene un significado especial en el contexto
del operador LIKE. El símbolo del porcentaje sustituye a cero o más caracteres añadidos a la letra “A”.
Los registros de empleados con valores de FIRST_NAME que empiezan por la letra “A” son devueltos.
Los caracteres ‘comodín’ pueden aparecer al principio, en el medio o al final de la cadena de caracteres.
Incluso pueden aparecer solos, como en:
En este caso, cada registro que contenga un valor de FIRST_NAME que no sea nulo será devuelto. Los
símbolos ‘comodín’ no son obligatorios cuando se utiliza el operador LIKE.
En tal caso, LIKE se comporta como un operador de igualdad comprobando que hay coincidencias exactas
de caracteres; así las dos siguientes cláusulas WHERE son equivalentes:
Dependiendo del conjunto de datos, éste podría recuperar, por ejemplo, empleados llamados King, Kong
o Kung. Una forma alternativa para realizar la concordancia de patrones es utilizar una serie interminable
de condiciones OR, pero lograr los resultados anteriores sin usar el operador LIKE es extremadamente
complejo. Por ejemplo, se podría lograr con la siguiente serie de condiciones OR:
82/306
SQL
Este ejemplo está incompleto, ya que no es factible listar todos los caracteres posibles por los que podría
ser sustituido. Este ejemplo muestra el gran esfuerzo que se requiere para sustituir un solo carácter sin
usar el operador LIKE y el símbolo comodín de guion bajo. Para un número desconocido (cero o más) de
sustituciones de caracteres, las posibilidades son exponencialmente mayores que para la sustitución de
un solo carácter. Prácticamente no es posible realizar la concordancia de patrones de caracteres sin el
uso del operador LIKE y los símbolos ‘comodín’.
Como muestra la siguiente Figura, los dos símbolos ‘comodín’ pueden ser usados independientemente,
juntos o incluso varias veces en una sola condición WHERE. La primera consulta recupera aquellos
registros en los que COUNTRY_NAME comienza con la letra "I" seguida de cero o más caracteres, seguida
de una "a" minúscula que a su vez es seguida de cero o más caracteres.
La segunda consulta recupera aquellos países cuyos nombres contienen la letra "i" como su quinto
carácter. La longitud de los valores COUNTRY_NAME y la letra con la que comienzan no son importantes.
Los cuatro símbolos ‘comodín’ de guion bajo que preceden a la "i" minúscula en la cláusula WHERE
representan exactamente cuatro caracteres (que pueden ser cualquier carácter). La quinta letra debe
ser una "i" y el símbolo de porcentaje especifica que el COUNTRY_NAME puede tener cero o más
caracteres del sexto carácter en adelante.
83/306
SQL
¿Qué pasa cuando se está buscando una cadena de caracteres que contiene un carácter porcentaje o
guion bajo? Oracle proporciona una forma de desactivar temporalmente su significado especial y
considerarlos como caracteres regulares utilizando el identificador ESCAPE. La tabla JOBS contiene
valores de JOBS_ID que están especificados con el carácter guion bajo, como SA_MAN, AD_VP, MK_REP
y SA_REP. Supóngase, además, que existe un registro en la tabla JOBS con un valor de JOBS_ID de
SA%MAN (nótese que no hay carácter guion bajo en este JOB_ID). ¿Cómo se pueden recuperar entonces,
de la tabla JOBS si se están buscando valores de JOB_ID que empiezan por los caracteres SA_?
Considérese la siguiente sentencia SQL:
SELECT *
FROM jobs
WHERE job_id LIKE 'SA_%';
Esta consulta devolverá los registros SA_REP, SA_MAN, y SA%MAN. El requisito en este ejemplo no se
cumple, ya que un registro adicional, SA%MAN, que no cumple el criterio de que comienza por los
caracteres SA_, también es devuelto, como se muestra en la siguiente Figura.
Un carácter guion bajo puede ser “escapado” (o tratarse como un símbolo normal no especial) utilizando
el identificador ESCAPE junto con el carácter ESCAPE (\). El segundo ejemplo de la figura anterior
muestra una sentencia de SQL que devuelve registros de la tabla JOBS con valores de JOB_ID iguales a
SA_MAN y SA_REP y que cumplen con el requisito original:
SELECT *
FROM jobs
WHERE job_id LIKE 'SA\_%' ESCAPE '\';
El identificador ESCAPE indica al servidor de Oracle que trate cualquier carácter encontrado después de
la
84/306
SQL
barra invertida como un carácter normal no especial sin significado de comodín. En la cláusula WHERE
anterior, cualquier valor de JOB_ID que empiece con los tres caracteres “SA_” será devuelto.
Tradicionalmente, el carácter ESCAPE es el símbolo de la barra invertida (\), pero no tiene por qué serlo.
La siguiente sentencia es equivalente a la anterior, pero en su lugar utiliza el símbolo de dólar como
carácter ESCAPE.
SELECT job_id
FROM jobs
WHERE job_id LIKE 'SA$_%' ESCAPE '$';
El símbolo del porcentaje puede ser “escapado” de forma similar cuando debe tratarse como un dato de
carácter. Supóngase que hay un requisito para recuperar el registro con el hipotético valor de JOB_ID:
SA%MAN introducido anteriormente. Si se consulta la tabla JOBS para valores de JOB_ID tales como
SA%MAN, utilizando el siguiente código se devolverían los registros SA_MAN y SA%MAN.
SELECT job_id
FROM jobs
WHERE job_id LIKE 'SA%MAN';
El servidor de Oracle interpreta el símbolo de porcentaje en la cláusula WHERE como un símbolo comodín
cuando se utiliza con el operador LIKE. Para obtener el registro con el valor de JOB_ID de SA%MAN
utilizando el operador LIKE, el símbolo de porcentaje debe ser “escapado” utilizando la siguiente
sentencia:
SELECT job_id
FROM jobs
WHERE job_id LIKE 'SA\%MAN' ESCAPE '\';
La barra invertida se define como el carácter ESCAPE que instruye al servidor de Oracle a ignorar las
propiedades comodín del símbolo que aparece inmediatamente después de la barra invertida. De esta
manera, ambos símbolos ‘comodín’ pueden utilizarse como caracteres especializados o normales en
diferentes segmentos de la misma cadena de caracteres.
85/306
SQL
Se considera un ejemplo donde existe una tabla con los datos guardados de los empleados. Esta tabla
tiene un campo llamado FIRST_NAME (primer nombre) y COMMISSION_PCT. Si se quisiera extraer
aquellos empleados cuyo FIRST_NAME empiece por la letra “J” y que ganan una COMMISSION_PCT
superior al 10%, se debería hacer una consulta donde se restrinjan estos datos. De esta forma “J%” se
correspondería a la primera condición. En cuanto a la segunda, se deberán testear los datos para
comprobar cuáles son superiores a 10 por ciento. Estas dos condiciones que van a trabajar
conjuntamente se asocian mediante el operador Booleano AND y se aplican consecutivamente en la
cláusula WHERE.
En general, se usarán los operadores Booleanos siempre que se quiera obtener un resultado basado en
la
86/306
SQL
a. El operador AND
El operador AND une condiciones en una condición más larga, que una línea de una tabla deberá cumplir
para ser incluida en el resultado. Los operadores Booleanos se definen utilizando tablas verdadero-falso.
En la tabla siguiente se define la tabla verdadero-falso para el operador AND, resumiendo así su
funcionalidad.
Si dos condiciones especificadas en una cláusula WHERE se unen mediante un operador AND, el registro
al que pertenecen será testeada para comprobar que ambas se cumplan antes de recuperar los datos e
incluirlos en el conjunto de resultados. Si finalmente ninguna de las condiciones o sólo una de ellas se
cumplen, el registro será excluido del resultado, dado que este es FALSE(falso). Si una de las condiciones
es NULL (campo vacío) causando que una de las condiciones se evalúe a NULL, el registro también se
excluirá.
87/306
SQL
En resumen, el registro sólo se incluirá en el conjunto de resultados si todas las condiciones son evaluadas
como TRUE (verdadero). Si hubiera más de dos condiciones, sólo los casos en los que todas las
condiciones se cumplieran sería incluidos como resultados válidos.
En el ejemplo que se usó anteriormente, todos aquellos empleados con FIRST_NAME empezando por “J”
y además tienen un valor para COMMISSION_PCT superior a 10 por ciento, serán recuperados de la base
de datos mediante la siguiente consulta:
commission_pct, hire_date
FROM employees
WHERE first_name LIKE 'J%'
AND commission_pct > 0.1;
Nótese que la cláusula WHERE tiene ahora dos condiciones, pero sólo hay una palabra clave WHERE. El
operador AND separa ambas condiciones. Para especificar más condiciones que imperativamente se
deben cumplir, simplemente se añadirán detrás de la segunda condición separándolas cada vez con un
operador AND; De esta manera se pueden especificar tantas condiciones como se desee. Se debe tener
en cuenta que cuantas más condiciones AND se incluyan en una misma consulta, más restrictiva será.
En la Figura siguiente se muestra la consulta anterior con dos nuevas restricciones adicionales. El valor
HIRE_DATE debe ser mayor que 01-JUN-1996 y LAST_NAME debe contener la letra “o”.
88/306
SQL
La primera consulta devolverá 4 registros. Nótese que las condiciones AND adicionales de la segunda
consulta solo son satisfechas por dos registros.
b. El Operador OR
El operador OR separa condiciones múltiples donde al menos una de ellas debe ser satisfecha por el
registro seleccionado para que este se incluya en el conjunto de respuestas. La siguiente es la tabla de
verdadero-falso para el operador OR, que resume su funcionalidad.
89/306
SQL
Si dos condiciones especificadas en una cláusula WHERE se unen con un operador OR, los registros se
evalúan para que una o todas las condiciones se cumplan. Si uno de los requisitos se cumple, es condición
suficiente para que el registro se incluya en el conjunto de resultados. En cambio, si ninguno de estos
requisitos se cumple el resultado será FALSE (falso) y por tanto quedará excluido. En resumen, un
registro será incluido en el conjunto de resultados siempre que al menos uno de los requisitos asociados
al operador OR sea evaluado como TRUE (verdadero).
En el siguiente ejemplo se ve como se escribe la consulta para recuperar a todos aquellos empleados
cuyo FIRST_NAME empiece por “B” o que su COMMISION_PCT sea mayor que 35 por ciento:
commission_pct, hire_date
FROM employees
WHERE first_name LIKE 'B%'
OR commission_pct > 0.35;
Nótese que las dos condiciones están separadas por la palabra clave OR. Todos aquellos empleados que
tengan valores de FIRST_NAME empezando por la mayúscula “B” se recuperaran sin importar el valor de
COMMISSION_PCT, aún si estos son NULL. Todos aquellos registros cuyo valor para COMMISSION_PCT
sea mayor que 35% serán también recuperados sin importar el valor que tengan para FIRST_NAME.
90/306
SQL
Se pueden especificar tantas condiciones OR como se deseen, siempre que se separen por dicho operador.
Contrariamente a cómo funciona el operador AND, cuantas más condiciones OR se incluyan, menos
restrictiva se vuelve la consulta. En la Figura anterior se observa la consulta que se ha explicado
anteriormente con dos condiciones OR adicionales. El valor HIRE_DATE debe ser mayor que 01-MAR2008
o el LAST_NAME debe empezar por la letra “B”. Efectivamente, la primera consulta devuelve menos
registros que la segunda. Esto de se debe a que, dado que sólo una de las condiciones debe ser
verdadera, cuantas más se añaden, más registros de la tabla serán capaces de cumplir alguna de dichas
condiciones.
c. El Operador NOT
El operador NOT niega a los operadores condicionales. Un registro seleccionado deberá ajustarse al
contrario lógico de las condiciones que se establezcan para poder ser incluido en el conjunto de
resultados. La tabla siguiente es la tabla verdadero-falso para el operador NOT donde se puede ver su
funcionalidad.
91/306
SQL
Condition X Condition Y
FALSE TRUE
TRUE FALSE
NULL NULL
En la siguiente tablase ve cómo se pueden negar los operadores condicionale por el operador NOT.
Positive Negative
WHERE salary BETWEEN 1 and 3000 WHERE salary NOT BETWEEN 1 AND 3000
Como se muestra en los ejemplos de la tabla anterior, el operador NOT puede ser muy útil. Es importante
entender que el operador NOT niega al operador lógico en una condición, sea cual sea su naturaleza.
Problema Solución
92/306
SQL
Para recuperar a todos aquellos empleados cuyo valor para FIRST_NAME no empiece por la letra “B” o
aquellos que no se ajustan a la condición para COMMISSION_PCT siendo esta mayor que 35%, se
escribiría una consulta tal que:
Nótese que las dos condiciones siguen estando separadas por el operador OR. El operador NOT ser añade
justo detrás.
93/306
SQL
1 () Paréntesis o llaves
4 || Concatenación
8 !=,<> No igual a
11 OR Condición lógica OR
94/306
SQL
95/306
SQL
Cambiar el orden de las condiciones en la cláusula WHERE significa cambiar su significado, dado que se
modificará su orden de prioridad. Considérese el siguiente código:
SELECT last_name,salary,department_id,job_id,commission_pct
FROM employees
WHERE last_name LIKE '%a%'
AND salary > department_id * 100
AND commission_pct IS NOT NULL
OR job_id = 'MK_MAN';
Hay dos condiciones compuestas en esta consulta, la primera condición recupera los registros con un
carácter “a” en el campo LAST_NAME y con un valor para SALARY 100 veces mayor que el valor para
DEPARTMENT_ID y donde el valor de COMMISSION_PCT no puede ser NULL.
La segunda condición busca aquellos registros cuyo valor para JOB_ID es MK_MAN. Un registro se
recuperará cuando cualquiera de las condiciones se cumpla, puesto que están separadas por el operador
OR.
96/306
SQL
Tal y como se ve en la figura a continuación, esta consulta recupera 6 registros. También se observa la
división de la consulta en otras dos. La primera condición separada devuelve 5 registros, mientras que
la segunda sólo recupera 1.
97/306
SQL
ORDER BY col(s)|expr;
En el supuesto que se requiera un informe que deba contener el LAST_NAME, SALARY y
COMMISSION_PCT de los empleados, ordenados alfabéticamente para la primera columna, para todos
los representantes de ventas y gestores de marketing. Este informe se podría extraer mediante la
siguiente sentencia SELECT:
Los datos seleccionados pueden ser ordenados en cualquiera de las columnas de las tablas de la cláusula
FROM, incluyendo aquellas que no aparecen en la lista del SELECT. Los resultados de la sentencia anterior
se pueden ordenar por COMMISSION_PCT como se muestra en la siguiente figura:
98/306
SQL
En el segundo ejemplo de la figura anterior, se muestra que al añadir la palabra clave DESC a la cláusula
ORDER BY, los registros se devuelven ordenados de manera descendente basándose nuevamente en la
columna COMMISSION_PCT. En el tercer ejemplo se muestra que al añadir las palabras clave NULLS
LAST, todos aquellos registros que en la columna que se usa para la ordenación tengan un valor nulo
serán enviados al final después de los valores no nulos. De similar forma, si se añaden las palabras clave
NULLS FIRST, estos registros nulos se mostrarán los primeros, antes que los registros no nulos para la
columna utilizada como base de ordenación.
En el siguiente ejemplo se ordena un conjunto de datos basados en una expresión que calcula el valor
de un empleado para una compañía basándose en sus valores para las columnas HIRE_DATE y SALARY.
Dicha fórmula toma el valor HIRE_DATE y le resta un número específico de días para devolver una fecha
anterior. Este número de días restado se calcula a partir del valor del campo SALARY dividido por 10. La
expresión se denomina EMP_VALUE como se muestra en el siguiente código:
99/306
SQL
FROM employees
WHERE job_id IN ('SA_REP','MK_MAN')
ORDER BY emp_value;
La expresión EMP_VALUE se inicializa con el valor HIRE_DATE y se desfasa hacia el pasado basándose
en el campo SALARY. La fecha más temprana de EMP_VALUE aparecerá primero en el registro de
resultados dado que la cláusula ORDER BY especifica que el resultado debe ser organizado por la
expresión. Nótese que los resultados podrían ser ordenados por la expresión explícitamente y el alias se
podría omitir: ORDER BY HIRE_DATE-(SALARY/10), pero utilizar un alias para dicha expresión hace que
la consulta sea mucho más sencilla de leer.
Hay varias opciones seleccionadas por defecto implícitas cuando se usa ORDER BY. La más importante
es que si no se especifica mediante DESC, la ordenación se asume como ascendente. Si hay valores
nulos en la columna base, se ordenará como NULL LAST por defecto para ordenaciones ascendentes y
NULL FIRST para descendentes. Si no hay una cláusula ORDER BY, la misma consulta ejecutada diversas
veces devuelve el mismo conjunto de resultados en diferente orden, por lo que no se pueden asumir
patrones para la ordenación por defecto en este caso.
c. Ordenación compuesta
Los resultados de una consulta se pueden ordenar mediante más de una columna. Dos o más columnas
se pueden especificar (tanto literalmente como por posición) como base para la ordenación si se separan
por comas en la cláusula ORDER BY. Considérese como requisito la ordenación del conjunto de resultados
mediante JOB_ID, LAST_NAME, SALAY y HIRE_DATE de la tabla EMPLOYEES. Otras especificaciones para
la ordenación son que para JOB_ID se debe ordenar de manera alfabéticamente descendente,
alfabéticamente ascendente para LAST_NAME y finalmente numéricamente descendente para SALARY.
La siguiente consulta SELECT cumple dichos requisitos:
100/306
SQL
101/306
SQL
Variables de sustitución
Comandos VERIFY y
DEFINE
Utilizando la sustitución, se insertan valores en los elementos en cursiva, seleccionando las palabras
clave opcionales que se utilizarán en las consultas. Cuando se necesita la columna LAST_NAME de la
tabla EMPLOYEES, la consulta se construye utilizando la forma general de la sentencia SELECT y
sustituyendo el nombre de la columna: APELLIDOS_NOMBRE en lugar de la columna palabra en la
cláusula SELECT y el nombre de la tabla; EMPLEADOS en lugar de la tabla palabra en la cláusula FROM.
102/306
SQL
En la figura siguiente cuando se ejecuta la consulta anterior, el servidor Oracle le pide que ingrese un
valor para la variable llamada LASTNAME; introduzca el apellido de un empleado si lo conoce, por ejemplo
"King"; si no sabe el apellido, pero sabe el número de identificación del empleado, puede escribir
cualquier valor y pulsar la tecla ‘Intro’ para enviar el valor; Oracle le pedirá que introduzca un valor para
la variable EMPNO.
Después de escribir un valor, por ejemplo 0 y pulsar ‘Intro’, no quedan variables de sustitución para que
Oracle las resuelva, y se ejecuta la siguiente sentencia:
A las variables se les puede asignar cualquier nombre alfanumérico que sea un nombre de identificador
válido. La variable que se pide debe ser de un tipo de datos apropiado para ese contexto; de lo contrario,
se devuelve un error de identificador no válido ORA-00904: invalid identifier error. Si la variable está
destinada a sustituir un carácter o un valor de fecha, la variable debe incluirse entre comillas simples.
Una técnica útil es encerrar la variable Ampersand de sustitución entre comillas simples cuando se trata
de valores de carácter y fecha. De esta manera, se requiere que el usuario envíe un valor literal sin
preocuparse de incluirlo entre comillas. La siguiente sentencia reescribe la anterior, pero incluye la
variable LASTNAME entre comillas:
103/306
SQL
Las dos condiciones son idénticas, pero se aplican a columnas diferentes. Cuando este se ejecuta, primero
se le pedirá que introduzca un valor de sustitución para la variable SEARCH utilizada en la comparación
con la columna LAST_NAME. A continuación, se le pedirá que introduzca un valor de sustitución para la
variable SEARCH utilizada en la comparación con la columna FIRST_NAME. Esto plantea dos problemas.
Primero, es ineficiente introducir el mismo valor dos veces, pero segundo y más importante, los errores
tipográficos pueden confundir la consulta ya que Oracle no verifica que se introduzca el mismo valor
literal cada vez que se utilizan variables de sustitución con el mismo nombre. En este ejemplo, la
suposición lógica es que el contenido de las variables sustituidas debe ser el mismo, pero el hecho de
que las variables tengan el mismo nombre no tiene ningún significado para el servidor Oracle y este no
hace tal suposición.
El primer ejemplo en la figura que viene a continuación se muestra los resultados de ejecutar la consulta
anterior y enviar dos valores distintos para la variable de sustitución SEARCH. En este ejemplo en
particular, los resultados son incorrectos ya que el requisito era recuperar los pares FIRST_NAME y
LAST_NAME que contenían la misma cadena de caracteres. En situaciones en las que una variable de
sustitución es referenciada varias veces en la misma consulta y su intención es que la variable tenga el
mismo valor en cada ocurrencia en la sentencia, es preferible hacer uso la sustitución con doble
Ampersand. Esto implica prefijar la primera ocurrencia de la variable de sustitución que ocurre varias
veces en una consulta, con dos símbolos de Ampersand en lugar de uno. Cuando el servidor Oracle
encuentra una variable de sustitución de doble Ampersand, se define un valor de sesión para esa variable
y no se le pide que introduzca un valor para sustituir esta variable en referencias posteriores.
El segundo ejemplo de la figura demuestra cómo la variable SEARCH es precedida por dos Ampersand
en la condición con la columna FIRST_NAME y a partir de entonces es precedido por un Ampersand en
la condición con la columna LAST_NAME. Cuando se ejecuta, se le pide que introduzca un valor para
sustituir la variable SEARCH sólo una vez para la condición con la columna FIRST_NAME. Este valor se
resuelve automáticamente a partir del valor de la sesión de la variable en referencias posteriores a la
misma, como en la condición con la columna LAST_NAME. Para vaciar la variable SEARCH, se debe utilizar
el comando UNDEFINE que se describe más adelante en este capítulo.
104/306
SQL
105/306
SQL
En la siguiente figura se pide que proporcione un valor para la variable Ampersand y Ampersand doble
llamada COL. Por ejemplo, podría introducir una columna llamada SALARY y envíe sus comentarios. La
sentencia que ejecuta la sustitución realiza la sustitución y recupera las columnas FIRST_NAME, JOB_ID
y SALARY de la tabla EMPLOYEES ordenados por SALARY. A diferencia de las cadenas de caracteres y las
fechas, las referencias de nombre de columna no requieren comillas simples tanto cuando se especifican
explícitamente como cuando se sustituyen mediante la sustitución por Ampersand.
SELECT &rest_of_statement;
Cuando se ejecuta, se le pide que envíe un valor para la variable REST_OF_STATEMENT que podría ser
cualquier consulta legítima, como DEPARTMENT_NAME FROM DEPARMENTS. Si envía este texto como
entrada para la variable, la consulta que se ejecuta se resolverá en la siguiente sentencia:
SELECT department_name
FROM departments;
Considere la forma general de la sentencia SQL reescrita usando la sustitución Ampersand como se
muestra a continuación:
106/306
SQL
SELECT &SELECT_CLAUSE
FROM &FROM_CLAUSE
WHERE &WHERE_CLAUSE
ORDER BY &ORDER_BY_CLAUSE;
La utilidad de esta declaración es discutible, pero ilustra el concepto de sustitución de manera efectiva.
En la figura que sigue, la declaración anterior permite que cualquier consulta vista hasta ahora sea
enviada en tiempo de ejecución. La primera ejecución consulta la tabla REGIONS, mientras que la
segunda consulta la tabla CONTRIES. Todos los candidatos para la sustitución por Ampersand son
sentencias que se ejecutan varias veces y difieren ligeramente entre sí.
107/306
SQL
Este efecto no siempre se desea y, de hecho, puede llegar a suponer un límite para la capacidad de
sustituir variables. Sin embargo, ORACLE permite resolver el conflicto borrando estas variables de sesión
a petición del desarrollador.
El comando VERIFY es específico de SQL*Plus y controla si los elementos sustituidos se repiten o no en
la pantalla del usuario antes de ejecutar una sentencia SQL que utiliza la sustitución de variables. Este
tipo de comandos se presentan en las siguientes secciones.
UNDEFINE variable;
Considere un ejemplo genérico que selecciona una columna estática y una columna variable de la tabla
EMPLOYEES y ordena el resultado basándose en la columna variable. La columna estática podría ser la
llamada como LAST_NAME.
La primera vez que esta sentencia se ejecuta, se pide que se introduzca el valor para la variable llamada
COLNAME y SALARY como valores de entrada. Este valor se sustituye y la sentencia se ejecuta. Si esta
sentencia se vuelve a ejecutar dentro de la misma sesión, no se requerirá que la introducción de ningún
valor para COLNAME, dado que ya está definido como SALARY en el contexto de la sesión y solo puede
ser eliminado mediante el comando UNDEFINE COLNAME, como se muestra en la siguiente figura:
108/306
SQL
Una vez que la variable se ha eliminado, la siguiente ejecución de la sentencia volverá a requerir al
usuario que introduzca un nuevo valor para COLNAME y FIRST_NAME será sustituido, cambiando la
consulta.
El comando DEFINE sirve para, por un lado, recuperar la lista de todas las variables definidas en ese
momento en la sesión SQL y por otro lado puede ser usado para definir explícitamente valores para las
variables referenciadas como variables de sustitución en una o más sentencias mientras la sesión siga
activa. La sintaxis de ambas variantes del comando DEFINE son como sigue:
DEFINE;
109/306
SQL
DEFINE variable=value
Tal y como se ve en la Figura siguiente, una variable llamada EMPNAME se define explícitamente para
tener el valor ‘King’. El comando independiente DEFINE de SQL*Plus, recupera las variables de sesión,
algunas con una barra baja delante, y otras que ya son conocidas, como EMPNAME y las variables de
sustitución doble Ampersand, que se definieron anteriormente de manera implícita.
Dos consultas diferentes, simples, se ejecutan y en ambas, la variable sustituida explícitamente definida
EMPNAME es referenciada en ambas.
La capacidad de la herramienta cliente en SQL para mantener las variables que persisten durante la
sesión se puede desactivar y activar mediante el comando SET. Si se escribe SET DEFINE OFF, la
herramienta cliente (SQL*Plus, por ejemplo) no guardará ninguna variable de sesión.
Gracias a esta acción, el símbolo que define el Ampersand (&) se puede usar como un carácter más si es
necesario. El comando SET DEFINE ON|OFF determina si la sustitución Ampersand está activa o no para
la sesión.
El siguiente ejemplo se usa el símbolo Ampersand como un valor literal. Cuando se ejecuta la sentencia,
se pide que se introduzca un valor para la variable de unión SID.
110/306
SQL
Al desactivar esta funcionalidad, la consulta se ejecutará sin que lance peticiones para recibir datos de
entrada:
Una vez la declaración se ejecuta, el comando SET DEFINE ON se podrá usar para recuperar la
funcionalidad. Hay que tener en cuenta que, si dicha característica de la sesión está desactivada y por el
contesto, se necesitase utilizar la sustitución Ampersand, la consulta no se podría realizar con éxito y
Oracle devolvería un error.
Problema Solución
111/306
SQL
112/306
SQL
3.5. Resumen
• La cláusula WHERE amplía la sentencia SELECT con un lenguaje que permite la selección.
• La cláusula WHERE está formada por una o más condiciones. Estas condiciones especifican unas
reglas de selección de los datos.
• Para cada registro revisado en una condición, existen términos a izquierda y derecha de un
operador de comparación. Estos términos pueden ser valores de columna, cadenas de caracteres,
o expresiones.
• Los operadores de comparación pueden comparar dos términos de muchas maneras, los más
comunes son los comparadores de igualdad; pero los comparadores de rango, de conjunto o de
patrón también están disponibles
• Los comparadores de rango se formulan utilizando el operador BETWEEN, que comprueba si un
término está entre dos límites dados.
• Con el operador IN se puede comprobar si un término pertenece a un conjunto. La condición
basada en una comparación de conjunto evalúa a TRUE si el término de la izquierda se encuentra
en el conjunto entre paréntesis del lado derecho del operador IN.
• El Operador LIKE permite comparar cadenas de caracteres con otras cadenas, valores de
columna, o expresiones. El símbolo porcentaje (%) se comporta como un símbolo ‘comodín’ que
113/306
SQL
puede ser igual a cero o muchos caracteres. El símbolo guion bajo (_) se comporta como un
símbolo ‘comodín’ que solo coincide única y exactamente con otro carácter .
• Los operadores booleanos son AND, OR y NOT. Los operadores AND y OR permiten múltiples
condiciones, estas son denominadas como Cláusulas WHERE múltiples. El operador NOT niega
cualquier operador de comparación que se encuentre en una condición.
• Los Resultados se ordenan mediante la cláusula ORDER BY. Los registros recuperados pueden
ser ordenados según uno o más atributos de columna; y estos se pueden especificar mediante
el nombre de la misma o con su posición numérica en la cláusula SELECT.
• El resultado ordenado se puede obtener en orden ascendente o descendente utilizando los
modificadores DESC o ASC al final de la cláusula ORDER BY.
Sustitución ampersand
En términos generales, las funciones de SQL están divididas en dos grandes grupos. Aquellas que calculan
y devuelven un valor para cada registro de un conjunto de datos y aquellas que devuelven un único valor
agregado para todas las filas.
114/306
SQL
Hay tres componentes básicos en la definición de una función. El primero es la lista de parámetros de
entrada. Estos especifican cero o más argumentos que serán introducidos a la función para ser
procesados. Estos parámetros pueden ser de distinto tipo, obligatorios u opcionales. El segundo
componente es el tipo de dato del valor resultante. En el momento de la ejecución, solo un valor de un
tipo predefinido es devuelto por la función. Por último, el tercer componente encapsula los detalles del
proceso ejecutado por la función y contiene el código de programa que de forma opcional manipula los
parámetros introducidos, ejecuta cálculos y operaciones y genera un valor de salida.
A menudo se describe una función como una “caja negra” que recibe unos datos de entrada, los ejecuta
y transforma, y devuelve un resultado como se detalla a continuación:
F(x,y,z,…) = resultado
Las funciones se pueden anidar con otras funciones como por ejemplo F1( x, y, F2( a, b), z), donde F2,
que tiene “a” y “b” como parámetros de entrada, forma parte de los parámetros de entrada de la función
F1. Las funciones pueden operar con todos los tipos de datos disponibles, los más utilizados son los de
tipo carácter, fecha y numérico. Estos operandos serán columnas o expresiones.
Como ejemplo, se considera una función que calcula la edad de una persona. La función EDAD tendrá
como parámetro de entrada la fecha de nacimiento de la persona. El resultado devuelto es un número
que representa la edad de esta. El cálculo caja negra implica obtener la diferencia de edad en años entre
la fecha actual y la fecha introducida como parámetro de entrada.
Las funciones de manipulación de caracteres incluyen las funciones LENGTH, CONCAT, SUBSTR, INSTR,
LPAD, RPAD, TRIM, y REPLACE.
La función LENGTH (string) utiliza una cadena de texto como parámetro de entrada y devuelve un valor
numérico del número de caracteres que la forman:
115/306
SQL
La función CONCAT (string1, string2) toma dos cadenas de texto y las concatena del mismo modo que
el operador ||:
La función SUBSTR (string, start position, number of characters) toma tres parámetros de entrada: Una
cadena de texto, la posición de inicio y el número de caracteres a extraer, y devuelve una cadena de
texto formada por los caracteres extraídos, a partir de la posición fijada, de la cadena de texto
introducida.
La función INSTR (source string, search item, [start position], [nth occurrence of search item]) devuelve
un número que indica la posición en la cadena de caracteres (source string), empezando desde una
posición inicial dada (start position), en la que aparece por enésima vez (nth ocurrence of search ítem)
el elemento buscado (search ítem).
INSTR ('[Link] 1, 2) = 18
Las funciones LPAD (string, length after padding, padding string) y RPAD (string, length after padding,
padding string) añaden un carácter a la derecha o a la izquierda de la cadena de texto, en la posición
especificada.
La función TRIM (trailing|leading|both trimstring from s) recorta literalmente los caracteres iniciales o
finales (o ambos) de una cadena determinada:
La función REPLACE (string, search item, replacement term) localiza un elemento y lo sustituye por otro
elemento de reemplazo, devolviendo una cadena de texto con los caracteres sustituidos:
REPLACE ('#PASSWORD#','WORD','PORT') = #PASSPORT#
116/306
SQL
Tres funciones numéricas comunes, detalladas en este capítulo, son ROUND, TRUNC y MOD.
La función TRUNC (number, decimal precision) trunca un numero decimal al número de decimales
especificado:
MOD (42,10) = 2
MONTHS_BETWEEN ('01-FEB-2008','01-JAN-2008') = 1
ADD_MONTHS ('01-JAN-2008',1) = 01-FEB-2008
La función LAST_DAY (date) devuelve el último día del mes de la fecha especificada. Mientras que
NEXT_DAY (date, day of the week) devuelve la siguiente fecha con el día de la semana especificado.
117/306
SQL
La función SYSDATE no requiere parámetros y devuelve una fecha que representa la fecha y hora actuales
del servidor. Las funciones ROUND (date, date precision format) y TRUNC (date, date precision format)
redondea y trunca una fecha al formato de la fecha dada respectivamente.
SYSDATE = 17-DEC-2007
ROUND (sysdate,'month') = 01-JAN-2008
TRUNC (sysdate,'month') = 01-DEC-2007
Las funciones de registro único se utilizan en casi todas las consultas emitidas por los
analistas, desarrolladores y administradores. Al buscar datos de caracteres, la función TRIM
se utiliza con frecuencia para eliminar espacios adicionales que se producen en campos de
tipo carácter. Las funciones de conversión se utilizan para estandarizar los datos de una
columna. Esto facilita una búsqueda más precisa y eficiente de los registros que se capturan
ya que, a menudo, son inconsistentes.
Como muestra la figura más adelante, se han seleccionado dos columnas de la tabla REGIONS junto con
una expresión utilizando la función LENGTH con la columna REGION_NAME.
La longitud de la columna REGION_NAME se calcula para cada registro, lo que demuestra que la función
se ha ejecutado cuatro veces separadas, devolviendo un resultado por registro.
Las funciones de registro único manipulan los datos de un registro para extraerlos y formatearlos con
fines de visualización. Los valores de entrada a una función de registro único pueden ser constantes o
literales especificados por el usuario, una columna de datos, variables o expresiones proporcionadas, de
forma opcional, por otras funciones de registro único anidadas. El anidamiento de las funciones de
registro único es una técnica comúnmente utilizada. Las funciones pueden devolver un valor con un tipo
de datos diferente de sus parámetros de entrada. Como muestra la siguiente figura, la función LENGTH
acepta un parámetro de entrada de tipo carácter y devuelve una salida de tipo numérico.
118/306
SQL
Para obtener el último carácter de una cadena, la función SUBSTR se utiliza con la columna
REGION_NAME como cadena de origen. La longitud de REGION_NAME se utiliza como posición inicial
(para obtener la posición del último carácter) produciendo la siguiente cláusula ORDER BY:
119/306
SQL
Como muestra la figura anterior, sólo se devuelven tres de las cuatro regiones, y la lista se ordena en
orden alfabético según el último carácter de la columna REGION_NAME para cada registro.
Se ejecutan funciones de registro único para cada registro del conjunto de datos seleccionado.
Las funciones siempre devuelven sólo un valor de un tipo de datos predeterminado. Pueden
aceptar cero o más parámetros de diferentes tipos de datos. Las funciones de registro único
como LENGTH, SUBSTR, e INSTR se usan frecuentemente anidadas. Cabe recordar que los
parámetros de entrada que pueden convertirse implícitamente a los tipos de datos requeridos
por las funciones.
4.2. Utilizar las funciones tipo carácter, numérico y fecha en sentencias SELECT
Esta sección lleva a cabo una investigación detallada de las funciones de un solo registro que se han
presentado anteriormente. Se adoptará un enfoque estructurado que incluye descripciones de funciones,
reglas sintácticas, descripciones de parámetros y ejemplos de uso. Se examinarán las funciones de
conversión de mayúsculas/minúsculas, seguidas de las funciones de manipulación de caracteres.
Seguidamente, se examinarán las funciones numéricas. La sección concluye con una evaluación de las
funciones de fecha.
120/306
SQL
a. La función LOWER
La función LOWER convierte una cadena de caracteres en su equivalente en minúsculas. No añade
caracteres extra o acorta la longitud inicial de la cadena de texto. Los caracteres en mayúscula se
convierten a su equivalente en minúscula. Los números, puntuaciones o caracteres especiales no se
tienen en cuenta en la transformación. La función LOWER solo puede tomar un parámetro de entrada:
LOWER(s)
Las siguientes consultas ilustran el uso de esta función:
Las Consultas 1 y 2 devuelven cadenas de texto “100” y “200” respectivamente. El parámetro introducido
a la Consulta 3 es una expresión formada por caracteres y la cadena devuelta por la función es “the sum
100 + 100 = 200”.
FROM dual;
Asumiendo que la fecha actual del servidor es: 17-DEC-2007. Las Consultas 4 y 5 devolverán “17-
dec2007” y “19-dec-2007” respectivamente. Las expresiones de fechas se evalúan y se convierten
implícitamente en tipo carácter antes de que se ejecute la función LOWER.
La siguiente imagen muestra la función LOWER utilizada en la cláusula WHERE para localizar los registros
con las minúsculas “u” y “r” consecutivas en el campo LAST_NAME.
121/306
SQL
Una consulta alternativa para obtener el mismo resultado sin usar la función LOWER en la cláusula WHERE
sería:
La consulta es correcta pero incómoda para trabajar con ella, y el número de cláusulas OR requeridas se
incrementa exponencialmente con la longitud de la cadena de texto.
b. La función UPPER
La función UPPER es el opuesto lógico de la función LOWER y convierte una cadena de caracteres en su
equivalente en mayúsculas. No añade caracteres adicionales o acorta la longitud de la cadena de texto
inicial. Todos los caracteres en minúsculas se convierten a sus equivalentes en mayúsculas. Los números,
puntuaciones o caracteres especiales no se tienen en cuenta en la transformación. La función UPPER solo
puede tomar un parámetro de entrada:
UPPER(s),
Las siguientes consultas ilustran el uso de esta función:
122/306
SQL
La función UPPER se utiliza en la siguiente imagen para extraer los registros de la tabla COUNTRIES
donde los valores de COUNTRY_NAME contienen las letras ‘U’, ‘S’ y ‘A’ en este orden. Las letras indicadas
no tienen por qué ser adyacentes.
Una consulta alternativa para obtener el mismo resultado sin utilizar las funciones UPPER o LOWER podría
ser la siguiente, utilizando ocho condiciones:
c. La función INITCAP
La función INITCAP convierte la primera letra de cada palabra de una cadena de texto en mayúscula. Se
utiliza a menudo para la presentación de datos. Normalmente, una palabra es una cadena de caracteres
adyacentes separada de otras por un espacio o un guion bajo, pero otros caracteres como el porcentaje,
exclamaciones o símbolos de dólar también son aceptados como caracteres de separación. Los símbolos
de puntuación o caracteres especiales son válidos para la separación de palabras. La función INITCAP
solo puede tomar un parámetro de entrada:
INITCAP(s),
Las siguientes consultas ilustran el uso de esta función:
123/306
SQL
La Consulta 1 devuelve el cociente 3 como cadena de texto. La Consulta 2 devuelve la fecha actual del
servidor con el mes transformado de mayúsculas a únicamente el primer carácter en mayúscula y el
resto en minúscula. Asumiendo que la fecha actual del servidor es 17-DEC-2007, la Consulta 2 devuelve
“17-Dec-2007”. La Consulta 3 devuelve “Init Cap Or Init_Cap Or Init%Cap”.
Las consultas de la siguiente imagen seleccionan los valores LAST_NAME y JOB_ID de la tabla EMPLOYEES
para aquellos empleados con LAST_NAME que empiece con la letra “H”. La primera consulta aplica la
función INITCAP para toda la cláusula SELECT. La segunda consulta muestra como la función INITCAP se
aplica por separado a cada cadena de texto. Ambas consultas devuelven resultados idénticos.
124/306
SQL
a. La función CONCAT
La función CONCAT une dos caracteres, columnas o expresiones de caracteres a una expresión de
caracteres más grande. Los literales numéricos y de fecha son implícitamente convertidos como
caracteres cuando aparecen como parámetros de la función CONCAT. Expresiones numéricas o de fecha
son evaluadas antes de ser convertidas en cadenas de texto preparadas para ser concatenadas.
La Consulta 1 devuelve la cadena "3.14 aproximates pi". La expresión numérica devuelve el número
3.14. Este número cambia automáticamente a la cadena de caracteres "3.14", que se concatena con el
literal de tipo carácter del segundo parámetro. El segundo parámetro de la función CONCAT en la Consulta
2 es SYSDATE, el cual devuelve la fecha actual del sistema. Este valor se convierte implícitamente a una
cadena a la cual se le concatena el literal del primer parámetro. Si la fecha del sistema fuese 17-DIC-
2007, la Consulta 2 devolverá la cadena "Hoy es: 17-DIC-2007".
Considérese la posibilidad de usar la función CONCAT para unir tres términos para devolver una única
cadena de caracteres. Dado que CONCAT sólo acepta dos parámetros, sólo es posible unir dos términos
con una instancia con esta función. La solución es anidar la función CONCAT dentro de otra función
CONCAT, como se muestra aquí:
La primera función CONCAT tiene dos parámetros: el primero es la cadena "Outer1", mientras que la
segunda es una función CONCAT anidada. La segunda función CONCAT toma dos parámetros: el primero
es la cadena "Inner1" mientras que el segundo es la cadena "Inner2". Esta consulta resulta en la siguiente
cadena: "Outer1 Inner1 Inner2". El anidado de funciones se describe más detalladamente en el capítulo
5.
La función CONCAT se utiliza en la imagen mostrada a continuación para extraer los registros de la tabla
EMPLOYEES donde DEPARTMENT_ID=100. El objetivo es producir una salida literal de una sola cadena a
partir de la función CONCAT del formato ‘FIRST_NAME LAST_NAME earns SALARY’.
125/306
SQL
Esta simple tarea resulta en un complejo conjunto de cuatro niveles anidados de llamadas a la función.
Como demuestra el segundo ejemplo de la figura anterior, el operador de concatenación realiza la tarea
equivalente de una manera más sencilla.
b. La función LENGTH
La función LENGTH devuelve el número de caracteres que constituyen una cadena de caracteres. Esto
incluye caracteres, columnas o expresiones de caracteres. Valores de tipo fecha y numéricos se
convierten automáticamente al tipo carácter cuando aparecen como parámetros de la función LENGTH.
Las expresiones numéricas o de fecha se evalúan antes de ser convertidas a cadenas listas para medir
su longitud. Los espacios en blanco, tabulaciones y caracteres especiales son contados por la función
LENGTH. La función LENGTH sólo acepta un parámetro. Su sintaxis es:
LENGTH (s)
Donde s representa cualquier cadena de valores, valor de columna de tipo carácter o expresión resultante
en un valor de tipo carácter.
Las consultas siguientes ilustran el uso de esta función:
Consulta 1: SELECT LENGTH (1+2.14||'approximates pi') FROM dual;
La Consulta 1 devuelve el número 19. La expresión numérica se evalúa para devolver el número 3.14.
Este número se trata automáticamente como una cadena de caracteres "3.14" la cual es luego
126/306
SQL
concatenada al carácter literal " approximates pi". La cadena de caracteres resultante contiene 20
caracteres. La Consulta 2 evalúa primero la función SYSDATE, que devuelve la fecha actual del sistema.
Este valor se convierte automáticamente en una cadena de caracteres cuya longitud se evalúa a
continuación. Suponiendo que la fecha del sistema devuelta sea "17-DEC-07", la consulta 2 devuelve el
valor 9.
La función LENGTH se usa en la siguiente imagen para extraer los registros cuyo COUNTRY_NAME tenga
longitud superior a 10 caracteres de la tabla COUNTRIES.
Las funciones LPAD y RPAD, también conocidas como funciones ‘left pad’ y ‘right pad’, devuelven una
cadena con un número específico de caracteres a la izquierda o a la derecha de la cadena
respectivamente. Las cadenas de caracteres utilizadas incluyen literales, valores de columna, o
expresiones de caracteres. Los literales numéricos y de fecha están implícitamente convertidos a
caracteres cuando aparecen como parámetros de las funciones LPAD y RPAD. Expresiones de tipo fecha
o numérico son evaluadas antes de ser convertidas a cadenas. También se puede utilizar espacios en
blanco, tabulaciones y caracteres especiales como parámetros para dichas funciones.
Las funciones LPAD y RPAD toman tres parámetros. Sus sintaxis son:
127/306
SQL
donde string representa la cadena de origen, length es un valor entero que representa la longitud final
de la cadena devuelta, y padstring especifica la cadena de caracteres a utilizar como relleno. Si se utiliza
LPAD (o RPAD), el padstring se añade a la izquierda (o derecha) de la cadena de origen hasta que alcance
la longitud deseada. Hay que tener en cuenta que, si la longitud es menor o igual a la longitud de la
cadena de la fuente, entonces no hay relleno y se devuelve una sub-cadena de la cadena de origen con
un número de caracteres igual a la longitud. Si se omite el padstring, la cadena de caracteres utilizada
para el relleno es, por defecto, un espacio en blanco. Las consultas siguientes ilustran la utilización de
esta función:
FROM dual;
FROM dual;
FROM dual;
FROM dual;
La función LPAD en la Consulta 3 tiene una longitud de cadena deseada de 14 caracteres. Suponiendo
que SYSDATE devuelve un valor de fecha de nueve caracteres: “17-DEC-07”. Esta fecha se convierte en
una cadena de caracteres, y se "rellena" sistemáticamente para alcanzar la longitud objetivo,
devolviendo: "$#$#$17-DIC-07". Téngase en cuenta que, aunque el "relleno" consta de dos caracteres
($#), la cadena no se aplicó uniformemente ya que hay tres símbolos de dólar y dos símbolos de
almohadilla. Esto se debe a que LPAD y RPAD rellenarán la cadena de origen tanto como sea posible con
la cadena de "relleno" hasta la longitud que se desea alcanzar. La función RPAD en la Consulta 4 tiene
una longitud objetivo de 4 caracteres, pero la función la función SYSDATE devuelve un valor de nueve
caracteres. Por lo tanto, no se produce "relleno" y, suponiendo que la fecha actual del sistema es "17DEC-
07", solo se devuelven los cuatro primeros caracteres: “17-D”.
Los resultados de las siguientes consultas son idénticos en las dos imágenes siguientes, pero se han
vuelto más legibles utilizando (en la segunda imagen) las funciones LPAD y RPAD, que formatean los
resultados de una manera más ordenada y presentable.
128/306
SQL
129/306
SQL
d. La función TRIM
La función TRIM elimina caracteres del principio o del final de las cadenas, columnas o expresiones de
caracteres para obtener un elemento de tipo carácter potencialmente más corto.
Los valores de tipo fecha o numérico se convierten automáticamente en caracteres cuando aparecen
como parámetros en la función TRIM. Las expresiones numéricas o de fecha se evalúan primero, antes
de ser convertidas a cadenas de caracteres, para poder ser recortadas.
La función TRIM toma un parámetro compuesto por un parámetro opcional y un parámetro obligatorio.
Su sintaxis es:
La cadena a recortar (str) es obligatoria. Los siguientes puntos enumeran las reglas que rigen el uso de
esta función:
• TRIM(trailing trimstring from str) elimina todas las coincidencias (si existen) con trimstring del
final de la cadena str.
• TRIM(leading trimstring from str) remueve todas las coincidencias (si existen) con trimstring del
inicio de la cadena str.
130/306
SQL
• TRIM(both trimstring de str) elimina todas las coincidencias (si existen) con trimstring del inicio
y final de la cadena str.
Las consultas siguientes ilustran la utilización de esta función:
Consulta 1: SELECT TRIM (TRAILING 'e' FROM 1+2.14||' is pie') FROM dual;
La Consulta 1 evalúa la expresión numérica para devolver el número 3.14. Este es entonces convertido
como cadena de caracteres "3.14" la cual es a su vez concatenada con el literal de tipo carácter para
construir la cadena "3.14 is pie". A continuación, la función TRIM elimina cualquier coincidencia con el
carácter "e" del final de la cadena para devolver "3.14 es pi".
La Consulta 2 elimina todas las coincidencias con el carácter "*" del principio y el final de la cadena de
texto y devuelve la cadena "Hidden". Aunque se especifique un solo carácter de recorte, se recortarán
múltiples caracteres siempre y cuando estos sean consecutivos.
La Consulta 3 tiene dos aspectos interesantes. La cadena origen no está entre comillas y se convierte
implícitamente en una de tipo carácter.
La función SYSDATE devuelve la fecha actual del sistema (supóngase 17-DEC-07). Dado que no se
especifica ninguna palabra clave (trailing, leading o both) para el recorte, se aplica el valor por defecto
both. Por lo tanto, todas las coincidencias con el carácter ‘1’ al principio o al final de la cadena de fecha
se cortan, devolviéndose "7-DEC-07".
La función TRIM utilizada en la imagen siguiente no parece hacer nada, pero un análisis más profundo
revela un uso práctico y común para ello.
131/306
SQL
Como se discutió anteriormente, los datos se introducen con frecuencia en las tablas de la base de datos
de la aplicación a través de una variedad de fuentes.
Puede ocurrir que los espacios se introduzcan accidentalmente y se guarden sin querer en campos de
caracteres.
La cadena de recorte de la cláusula WHERE simula el campo LAST_NAME rellenado con espacios. Esto
podría dificultar la búsqueda de empleados con los valores LAST_NAME = Smith. Recortar el espacio
añadido a LAST_NAME permite una búsqueda precisa y elimina el riesgo de espacios no intencionados
que pueden estar presentes en los datos de tipo carácter. Recordar que cuando no se especifican
parámetros distintos de la cadena str en la función TRIM, entonces su comportamiento por defecto es el
siguiente:
Los valores numéricos y de fecha están implícitos como caracteres cuando aparecen como parámetros
de la función INSTR. Las expresiones de fecha o numéricas se evalúan primero antes de convertirse en
cadenas de caracteres para poder ser buscadas.
La función INSTR toma cuatro parámetros, compuestos por dos obligatorios y dos opcionales. La sintaxis
es:
132/306
SQL
El valor por defecto para el parámetro search start position es 1 o el inicio del parámetro source string.
El valor por defecto para el parámetro nth ocurrence es 1 o la primera aparición.
Las siguientes consultas ilustran la función INSTR con expresiones numéricas y de fecha:
La Consulta 1 evalúa la expresión numérica para devolver el número 3.14. Este se convierte
implícitamente como la cadena de caracteres "3.14". Se busca el carácter "." y aparece por primera vez
en la posición 2.
La Consulta 2 evalúa el SYSDATE y convierte la fecha devuelta en una cadena de caracteres (supuesto
que la fecha del sistema es 17-DEC-07). La primera aparición de los caracteres DEC se da a partir de la
posición 4.
Considérense, ahora, las siguientes consultas con datos de tipo carácter que ilustran el valor por defecto
y los parámetros tercero y cuarto de la función INSTR:
La Consulta 3 busca la primera aparición del carácter "#" en la cadena de origen comenzando en la
posición 1 y devolviendo la posición 2 como resultado.
La Consulta 4 tiene el número 5 como tercer parámetro, que indica que la búsqueda del carácter debe
comenzar en la posición 5 en la cadena de origen. La aparición posterior del símbolo de control se
encuentra en la posición 6, devuelta por la consulta.
La Consulta 5 tiene los números 3 y 4 como su tercer y cuarto parámetro, respectivamente. Esto indica
que la búsqueda del carácter debe comenzar en la posición 3 de la cadena de origen. La consulta 5
devuelve el número 10, que es la posición de la cuarta aparición del símbolo de almohadilla cuando la
búsqueda comienza en posición 3.
La función INSTR utilizada en la siguiente figura devuelve los registros de la tabla DEPARTMENTS donde
se encuentra la cadena "on" comenzando en la segunda posición de la columna DEPARTMENT_NAME.
133/306
SQL
El número por defecto de caracteres a extraer es igual al número de caracteres desde la posición inicial
hasta el final de la cadena de origen. Las siguientes consultas ilustran la función SUBSTR con expresiones
numéricas y de fecha:
134/306
SQL
La Consulta 1 evalúa la expresión numérica para devolver el número 9997. Este se convierte
automáticamente en la cadena de caracteres "9997". La búsqueda comienza en la posición 3 y los dos
caracteres desde esa posición en adelante son extraídos, dando como resultado la sub-cadena "97".
La Consulta 2 evalúa la función SYSDATE y convierte la fecha devuelta en una cadena de caracteres
(supuesto que la fecha del sistema es 17-DEC-07). La búsqueda de la sub-cadena comienza en la posición
4 y, a partir de esta posición, se extraen los 3 caracteres, dando lugar a la sub-secuencia "DEC".
Considérense las siguientes consultas con datos de tipo carácter que ilustran el comportamiento por
defecto del parámetro opcional de la función SUBSTR:
135/306
SQL
g. La función REPLACE
La función REPLACE reemplaza todas las coincidencias de una cadena dada, que se encuentren en otra
cadena origen, con un elemento de reemplazo, devolviendo la cadena de origen modificada. Si la longitud
del elemento de reemplazo es diferente de la del elemento de búsqueda, la longitud de la cadena origen
y la cadena resultado serán diferentes. Si no se encuentra la cadena de búsqueda, se devuelve la cadena
sin cambios. Los valores y expresiones numéricas y de fecha son evaluados antes de ser convertidos
implícitamente como caracteres cuando aparecen como parámetros de la función REPLACE.
La función REPLACE toma tres parámetros, siendo los dos primeros obligatorios. Su sintaxis es:
Si se omite el parámetro replacement term, cada aparición del parámetro search item es borrado de
source string. En otras palabras, se sustituye por una cadena vacía. Las siguientes consultas ilustran la
función REPLACE con números y expresiones de fecha:
La Consulta 1 evalúa la expresión numérica para devolver el número 9997, el cual es convertido como la
cadena de caracteres "9997". La cadena o elemento de búsqueda es el carácter "9" que aparece tres
veces en la cadena origen. Cada carácter de búsqueda se sustituye por la cadena de sustitución "85",
dando como resultado la cadena "8585857".
La Consulta 2 evalúa la función SYSDATE y convierte la fecha devuelta en una cadena de caracteres
(supuesto que la fecha del sistema es 17-DEC-07). La cadena de búsqueda "DEC" aparece una vez en la
136/306
SQL
cadena de origen y se sustituye por los caracteres "NOV", obteniéndose el resultado "17-NOV-07".
Téngase en cuenta que esto es una cadena de caracteres y no un valor de fecha.
Considérese las siguientes consultas que ilustran el comportamiento por defecto del parámetro opcional
de la función REPLACE:
La función REPLACE utilizada en la imagen siguiente devuelve los registros de la tabla EMPLOYEES donde
JOB_ID = SA_MAN, pero modifica la columna SALARY sustituyendo cada 0 por 000 y solapando la nueva
expresión como "Dream Salary".
Problema Solución
137/306
SQL
Se desea buscar una cadena de caracteres Sí, la solución más sencilla es, en primer lugar,
almacenada en la base de datos. El formato en utilizar TRIM, eliminando los espacios en
la que se encuentra almacenada es blanco de la columna (leading y trailing) y
desconocido y posee espacios en blanco luego convertir los datos de columna utilizando
delante y detrás de la cadena. ¿Puede dicha una función de conversión como LOWER,
consulta realizarse? UPPER, o INITCAP para simplificar el número
de comparaciones requeridas en la cláusula
WHERE.
Se pide extraer los últimos tres caracteres de Sí. La función SUBSTR(source string, start
la columna LAST_NAME en la tabla position, number of characters) tiene tres
EMPLOYEES. ¿Se puede realizar una consulta parámetros. Si la posición de inicio se
de este tipo sin el uso de la función LENGTH? establece a -3, y el número de caracteres se
establece en 3 o se omite, los últimos tres
caracteres de los datos de la columna
LAST_NAME serán devueltos. Se puede utilizar
la siguiente consulta:
Se quiere extraer una cadena de diez Sí, la función LPAD se puede utilizar de la
caracteres basada en la columna SALARY en la siguiente manera:
tabla EMPLOYEES. Si el valor del salario es
menor de diez caracteres, se deben añadir SELECT LPAD (SALARY,10,0)
ceros a la izquierda del valor para obtener una FROM EMPLOYEES;
cadena de diez caracteres. ¿Es esto posible?
138/306
SQL
El parámetro source number representa cualquier literal, columna o expresión numérica. El parámetro
decimal precision (opcional) especifica el grado de redondeo. Si no se introduce el parámetro decimal
precision, por defecto, el grado de redondeo es cero, lo que significa que se redondea al número entero
más cercano.
Se consideran los grados decimales listados en la siguiente tabla para el número 1234.5678. Los valores
negativos para el parámetro de precisión se encuentran a la izquierda de la coma mientras que los
positivos a la derecha.
-3 1 Millares (nx1000)
-2 2 Centenas
(nx100)
-1 3 Decenas (nx10)
0 4 Unidades (nx1)
1 5 Décimas (n/10)
2 6 Centésimas
(n/100)
3 7 Milésimas(n/1000)
Si el parámetro de precisión decimal es cero, el número se redondea al número entero más cercano. Si
es 2, entonces el parámetro source number se redondea a la centésima más cercana y así sucesivamente.
Las siguientes consultas ilustran la utilización de esta función:
La Consulta 1 tiene una precisión decimal (n) de 1, lo que implica que el número introducido se redondea
a la décima más cercana. Al ser el dígito (n+1) menor que 5 no se produce redondeo y el número
devuelto es 1601.9. El parámetro decimal precision en la Consulta 2 es 2, así que el valor introducido se
139/306
SQL
redondeará a la centésima. El valor de las milésimas es 6 por lo que se realizará el redondeo y el valor
devuelto será 1601.92. En la Consulta 3, el parámetro es -3. Al ser negativo, la cifra significativa a
redondear es 6, se encuentra tres posiciones a la izquierda de la coma y se redondea al millar,
devolviendo 2000. En la Consulta 4 no se ha introducido parámetro decimal precision por lo que el
número se redondeará al número entero más cercano, devolviendo el valor 1602.
El ejemplo mostrado a continuación selecciona los empleados que trabajan como jefes de ventas y calcula
un "bono de antigüedad" basándose en el número de días trabajados redondeado al número entero más
cercano. La función ROUND se utiliza para redondear la parte fraccional de la diferencia entre la fecha
del servidor y el valor de HIRE_DATE para cada empleado.
El parámetro source number representar cualquier literal, valor de columna o expresión numé[Link]
parámetro decimal precision (opcional) especifica el grado de truncamiento. Si no se introduce el
parámetro decimal precision, el grado de truncamiento por defecto es cero, lo que significa que se trunca
al número entero más cercano. Si el parámetro decimal precision es 1, entonces el número se trunca en
las décimas. Si es 2, se trunca en la centésima, y así sucesivamente. Las siguientes consultas ilustran el
uso de esta función:
140/306
SQL
La Consulta 1 tiene un valor del parámetro decimal precision de 1, lo que implica que el número
introducido se truncará a la décimas de unidad y el valor devuelto es 1601.9. En la Consulta 2, el
parámetro (n) es 2 por lo que el valor introducido será truncado a las centésimas, devolviendo 1601.91.
Es importante saber diferenciar el resultado entre ROUND y TRUNC para el mismo valor con el mismo
del parámetro decimal precision, ya que en la función ROUND, al ser el digito (n+1=3) 6 y es mayor que
5, el valor devuelto habría sido 1601.92.
En la Consulta 3 se introduce un valor de -3 al parámetro (n), lo que indica que el truncamiento se
realizará tres posiciones a la izquierda de la coma, al millar más cercano. Por lo tanto, el número se
trunca al millar y devuelve 1000. Por último, la Consulta 4 no contiene el parámetro decimal precision,
por lo que el truncamiento se realizará al número entero más próximo. El valor devuelto es 1601.
En la siguiente figura se muestra el ajuste salarial con el premio otorgado al departamento de finanzas.
El departamento de finanzas ha decidido otorgar un premio departamental con el cual la empresa
recompensará a su personal de finanzas ajustando sus salarios. La función TRUNC se utiliza para truncar
el aumento de sueldo propuesto a un número entero.
c. La función MOD
La función MOD devuelve el resto de una operación de división. Se proporcionan dos números, el
dividendo (número que se divide) y el divisor (número por el que se divide) y se realiza una operación
de división. Si el divisor es factor del dividendo, MOD devuelve cero ya que no hay resto. Si el divisor es
cero, no se devuelve error, en su lugar la función MOD devuelve el dividendo. Si el divisor es mayor que
el dividendo, entonces la función MOD devuelve el dividendo como resultado. Esto se debe a que divide
cero veces el dividendo, dejando el resto igual al dividendo.
141/306
SQL
Los parámetros dividend y divisor representan un literal, un valor de columna o una expresión numérica,
que pueden ser negativos o positivos. Las siguientes consultas ilustran el uso de esta función:
La Consulta 1 divide 6 entre 2 por lo que el resto devuelto es 0. La Consulta 2 divide 5 entre 3 devolviendo
2 como resto. La Consulta 3 intenta dividir 7 entre 35. Al tratarse de un divisor mayor que el dividendo
la función MOD devuelve 7. La Consulta 4 divide 5.2 entre 3 devolviendo 2.2 como resto.
Cualquier número par dividido por 2 no tendrá resto, pero los impares divididos por 2 siempre
devolverán 1. Por lo tanto, la función MOD se usa a menudo para distinguir entre números
pares e impares.
La columna EMPLOYEE_ID de la tabla EMPLOYEES almacena una secuencia única de números para cada
registro empezando por el 100. Los primeros 12 empleados deben ser asignados a uno de los cuatro
equipos de manera cíclica para una tarea en particular. En la imagen anterior se muestra la sentencia
para realizar la asignación.
Los registros de los 12 empleados se aíslan con un operador BETWEEN en la cláusula WHERE. La función
MOD se aplica a la división de la columna EMPLOYEE_ID entre 4. la función MOD asigna los números del
0 al 3 a cada fila de una manera cíclica.
Los valores propuestos asumidos por los parámetros opcionales de las funciones no son
siempre intuitivos, pero a menudo se prueban. Por ejemplo, llamando a la función SUBSTR
con sólo los resultados de los dos primeros parámetros en la función que extrae una
142/306
SQL
subcadena de una posición de inicio hasta el final de la cadena de texto. El parámetro opcional
tanto para el numérico como para la fecha TRUNC y ROUND es el grado de precisión. Por
ejemplo, llamando a la función numérica TRUNC sin especificar el grado de truncamiento
resulta que el número sea truncado al número entero más cercano. Es útil estar familiarizado
con el valor por defecto asignado a los parámetros opcionales para estas funciones.
143/306
SQL
Aunque el siglo no se muestra por defecto, se almacena en la base de datos cuando se inserta o actualiza
el valor de fecha y está disponible para su recuperación.
El formato en el que se muestra una fecha se denomina máscara de formato. Hay varios códigos o
máscaras de formato de fecha disponibles, como se muestra en la siguiente tabla.
El lenguaje para formatear elementos de fecha utilizando máscaras de formato de fecha se discutirá en
el Capítulo 5. La máscara de formato DD-MON-RR es la máscara de visualización y entrada de datos por
defecto. La máscara de formato de fecha RR difiere de la máscara de formato YY porque se utiliza para
especificar diferentes siglos basándose en el año actual y en el especificado. El componente siglo
asignado a un valor de fecha al insertarse o actualizarse cuando los dos dígitos del año se envían,
depende de la configuración NLS_DATE_FORMAT en esa sesión. Si el NLS_DATE_FORMAT se fija en el
formato por defecto DD-MON-RR, el componente de siglo se asigna automáticamente en base a las
siguientes reglas:
• Si los dos últimos dígitos del año en curso y del año especificado se encuentran entre 0 y 49, se
devuelve el siglo actual (supuesto que el año en curso es 2014). La fecha asignada para el 24JUL-
04 es el 24-JUL-2004.
• Si los dos últimos dígitos del año en curso se encuentran entre 0 y 49 y los dígitos del año
especificado entre 50 y 99, se devuelve el siglo anterior (supuesto que el año en curso es 2014).
La fecha asignada para el 24-JUL-94 es el 24-JUL-1994.
• Si los dos últimos dígitos del año en curso y del año especificado se encuentran entre 50 y 99,
se devuelve el siglo actual por defecto. Si el año en curso es 2055, la fecha asignada para el
24JUL-94 es el 24-JUL-2094.
• Si los dos últimos dígitos del año en curso se encuentran entre 50 y 99 y el año especificado está
entre 0 y 49, se devuelve el siguiente siglo. Si el año actual es 1975, la fecha asignada para el
24-JUL-17 es el 24-JUL-2017.
144/306
SQL
CC Siglo
MI Minutos
SS Segundos
b. La función SYSDATE
La función SYSDATE no toma ningún parámetro y devuelve la fecha y hora actual del sistema según el
servidor de la base de datos. Por defecto, la función SYSDATE devuelve los componentes DD-MON-RR de
la fecha actual del sistema. Es importante recordar que SYSDATE no devuelve la fecha y hora
especificadas por su reloj del sistema local. Si el servidor de base de datos está ubicado en una zona
horaria diferente a la de un cliente que consulta la base de datos, la fecha y la hora que se devuelve
difieren de las del sistema operativo en la máquina del cliente. La consulta para recuperar la fecha del
servidor es la siguiente:
145/306
SQL
SELECT SYSDATE
FROM dual;
Aritmética de fechas
Las siguientes ecuaciones ilustran un principio importante con respecto a la aritmética de fechas:
Una fecha se puede restar de otra fecha. La diferencia entre dos fechas se representa como el número
de días entre ellos. Cualquier número (incluidas las fracciones) puede sumarse o restarse de una fecha.
En este contexto, el número representa un número de días. La suma o diferencia entre un número y una
fecha siempre devuelve una fecha.
Para ilustrar la función SYSDATE en lo que se refiere a aritmética de fechas, el entorno SQL Developer
se ha modificado temporalmente para mostrar la información de la hora y la fecha.
Para modificar el entorno SQL Developer para mostrar información horaria y de fecha, por
defecto, navegar a Herramientas | Preferencias | Base de datos | NLS | Formato de fecha.
Cambiar la máscara de visualización por defecto (DD-MON-RR) a (DD-MON-RR HH24:MI:SS).
La siguiente figura muestra como la función TO_DATE es utilizada para convertir el valor fecha 02-
JUN2008 con hora 12.10pm en un elemento de tipo fecha.
La primera consulta de la figura se desglosa como: Dos días antes del 2-JUN-2008 es 31-MAY-2008, que
es la fecha devuelta por la expresión 1. Sumando 0.5 días (12 horas) al 2-JUN-08 12:10, como muestra
la expresión 2, resulta en la fecha 3-JUN-08 00:10. La expresión 3 suma seis horas a la fecha dada,
devolviendo 2-JUN-08 18.10.
146/306
SQL
La función MONTHS_BETWEEN
La función MONTHS_BETWEEN devuelve un valor numérico que representa el número de meses entre
dos valores fecha. Las fechas en formato DD-MON-RR o DD-MON-YYYYY se lanzan automáticamente
como elementos fecha cuando se introducen como parámetros de la función MONTHS_BETWEEN. La
función MONTHS_BETWEEN toma dos parámetros obligatorios:
La función calcula la diferencia, en meses, entre date1 y date2. Si date1 ocurre antes de date2, se
devuelve un número negativo. La diferencia entre los dos parámetros de fecha puede consistir en un
número entero y un componente fraccionario. El número entero representa el número de meses entre
las dos fechas. El componente fraccionario representa los días y el tiempo restante después del número
entero al calcular la diferencia entre años y meses, basándose en un mes de 31 días. Si los componentes
que se comparan comparten el mismo (o el último) día de su respectivo mes, se devuelve un número
entero.
147/306
SQL
Un error común es asumir que el tipo de datos de retorno de las funciones de un solo registro
es el mismo que al que pertenece la función. Este sólo se aplica a las funciones numéricas.
Las
148/306
SQL
funciones de carácter y fecha pueden devolver otro tipo de datos. Por ejemplo, la función de
carácter INSTR y la función MONTHS_BETWEEN, ambas devuelven un valor numérico. Es
importante familiarizarse con la aritmética de fechas, ya que es común asumir erróneamente
que la diferencia entre dos fechas es una fecha, cuando en realidad es un número.
La función ADD_MONTHS
La función ADD_MONTHS devuelve un objeto fecha calculado añadiendo un número de meses
especificado a un valor fecha dado. Las fechas en formato DD-MON-RR o DD-MON-YYYY se lanzan
automáticamente como elementos fecha cuando se introducen como parámetros de la función
ADD_MONTHS. La función ADD_MONTHS toma dos parámetros obligatorios. Su sintaxis es:
La función calcula la fecha prevista después de añadir el number of months especificado a start date. El
número de meses puede ser negativo, lo cual devolvería una fecha anterior a la fecha inicial dada. El
número de meses puede ser fraccional, pero se ignorará el componente fraccional y se utiliza el
componente entero.
Las tres consultas de la siguiente imagen ilustran el comportamiento de la función ADD_MONTHS.
149/306
SQL
La función NEXT_DAY
La función NEXT_DAY devuelve la próxima fecha que coincide con el día de la semana especificado. Son
aceptados los valores que implícitamente se pueden tomar como elementos de fecha cuando aparecen
como parámetros de la función NEXT_DAY. La función NEXT_DAY toma dos parámetros obligatorios. Su
sintaxis es:
La segunda consulta especifica el carácter literal WEDNE, que se interpreta como WEDNESDAY. El próximo
miércoles después del 01-JAN-2009 es 07-JAN-2009.
La tercera consulta utiliza el entero para especificar el quinto día de la semana. Asumiendo el valor por
defecto donde el domingo está representado por el número 1, el quinto día es el jueves. El próximo
jueves después del 01-JAN-2009 es el 08-JAN-2009.
150/306
SQL
Problema Solución
Se desea recuperar la duración de Sí, la función SYSDATE se puede utilizar para obtener la fecha
empleo en días para cada empleado. actual del sistema.
¿Es posible realizar un cálculo de este
tipo? La siguiente consulta calcula la duración restando la columna
HIRE_DATE a la fecha devuelta por la función SYSDATE:
SELECT SYSDATE-HIRE_DATE FROM
EMPLOYEES;
Se quiere identificar la fecha en la cual Sí, se llama a la función NEXT_DAY con el parámetro start
se pagará la prima de fin de año. date fijado para el último día de diciembre y el parámetro
Las bonificaciones se pagan day of the week fijado en viernes, por lo tanto, se devolverá
normalmente el último viernes de el primer viernes de enero. Restándo siete días a esta fecha
diciembre. se obtiene el último viernes de diciembre. Conidérese la
siguiente consulta para el año 2009:
¿Se puede calcular la fecha de la
prima utilizando la función SELECT NEXT_DAY ('31-DEC-2009', 'Friday') -7
NEXT_DAY? FROM DUAL;
151/306
SQL
Los empleados que trabajan en el Sí. Utilizando la función REPLACE. Si se reemplaza cada 4
departamento de IT se han mudado a por un 6 se cambiarán dígitos que no deben ser cambiados,
nuevas oficinas y, aunque los últimos por lo que la cadena a reemplazar debe ser especificada de
cuatro dígitos de sus números de manera única.
teléfono son iguales, el conjunto de La siguiente consulta proporciona la lista:
los tres dígitos 423 se ha cambiado a
SELECT FIRST_NAME,
623. Un número de teléfono típico de
LAST_NAME,PHONE_NUMBER, REPLACE
un miembro del personal de IT es
(PHONE_NUMBER, '.423.', '.623.')
590.423.4567. Se quiere
FROM EMPLOYEES WHERE
proporcionar una lista de los nombres
DEPARTMENT_ID=60
de los empleados con sus viejos y
nuevos números de teléfono.
¿Puede hacerse esa lista?
La función LAST_DAY
La función LAST_DAY devuelve la fecha del último día del mes que se ha especificado. Los valores que
pueden ser convertidos implícitamente como fechas son aceptables cuando aparecen como parámetros
de la función LAST_DAY. La función LAST_DAY tiene un parámetro obligatorio. Su sintaxis es:
152/306
SQL
La función ROUND
La función ROUND realiza una operación de redondeo de un valor basado en un formato de precisión de
fecha especificado. El valor devuelto se redondea por exceso o por defecto al formato de precisión de
fecha más cercano. La función de fecha ROUND tiene un parámetro obligatorio y otro opcional. Su sintaxis
es:
Redondear por siglo equivale a sumar 1 al siglo actual. Redondear por mes, redondeará la fecha hasta el
mes siguiente, si el componente del día es mayor que 16, o, de lo contrario, redondeará hasta el comienzo
del mes en curso. Si el mes está entre 1 y 6, el redondeo por año devuelve el año en curso; en caso
contrario, devuelve la fecha al principio del año siguiente. La siguiente figura muestra cuatro elementos
en la lista SELECT, cada uno redondeando una fecha con un grado de precisión diferente.
153/306
SQL
El primer elemento redondea la fecha al día más cercano. Mientras la hora sea las 13:00, que es después
de las 12:00, la fecha se redondea a medianoche del día siguiente, 03-JUN-2009 00:00.
El segundo redondea la fecha al mismo día de la semana que el primer día del mes y devuelve 01-
JUN2009.
El tercero redondea la fecha al principio del mes siguiente, ya que el componente de día es 16 y devuelve
01-JUL-2009.
Para el cuarto elemento, se redondea a la fecha al principio del año siguiente, ya que el componente de
mes es 7 y se devuelve el 01-JAN-2010.
La función TRUNC
La función TRUNC realiza una operación de truncamiento en un valor de fecha basado en un formato de
precisión de fecha definido. La función de fecha TRUNC tiene un parámetro obligatorio y un parámetro
opcional. Su sintaxis es:
El parámetro source date representa cualquier valor que se pueda convertir implícitamente en una fecha.
El parámetro date precision format (opcional) define el grado de truncamiento. Si está ausente, el grado
de truncamiento por defecto es día. Esto significa que cualquier componente horario de la fecha de origen
se ajusta a medianoche o 00:00:00 (00 horas 00 minutos y 00 segundos).
Truncar a nivel de mes fija la fecha hasta el primer día del mes. Truncar a nivel de año devuelve la fecha
a principios del año en curso. La siguiente figura muestra cuatro elementos en la lista SELECT, cada uno
de los cuales trunca una fecha con un grado diferente de precisión.
El primer elemento fija el componente de tiempo de 13:00 a 00:00 y devuelve el día actual.
154/306
SQL
El segundo trunca la fecha al mismo día de la semana que el primer día del mes y devolviendo el 01JUN-
2009.
El tercero trunca la fecha al inicio del mes en curso y devuelve 01-JUN-2009.
El cuarto trunca la fecha a principios del año en curso y devuelve el 01-JAN-2009.
4.3. Resumen
Varios tipos de funciones disponibles en SQL
• Las funciones aceptan cero o más parámetros de entrada, pero siempre devuelven un resultado
de un tipo de datos predeterminado.
• Las funciones de registro único se ejecutan una vez por cada registro seleccionado, mientras que
las funciones de registros múltiples se ejecutan una vez para todo el conjunto de registros
consultados.
• Las funciones de caracteres son la conversión de mayúsculas-minúsculas o la manipulación de
caracteres. Pueden utilizarse en las cláusulas SELECT, WHERE y ORDER BY en una sentencia
SELECT.
• La función INITCAP acepta una cadena de caracteres y devuelve cada palabra en formato título.
• La función que calcula el número de caracteres de una cadena, incluyendo espacios y caracteres
especiales, es la función LENGTH.
155/306
SQL
Se definirá en este capítulo el concepto de funciones de anidamiento, así como una serie de funciones
generales cuyo objetivo es simplificar la interacción con valores nulos, incluyendo las funciones NVL,
NVL2, NULLIF y COALESCE.
Se verá también la lógica condicional o la capacidad para mostrar distintos resultados según el valor de
los datos gracias a las funciones condicionales CASE y DECODE. Estas funciones proporcionan la lógica
ifthen-else(si… -> entonces …; en cualquier otro caso…) en el contexto de una consulta SQL.
Las funciones de conversión SQL son funciones de una sola línea que se han designado para alterar la
naturaleza del tipo de datos de los valores de una columna, expresión o variable. TO_CHAR, TO_NUMBER
y TO_DATE son las tres funciones de conversión más utilizadas y se presentaran posteriormente con más
detalle. La función TO_CHAR convierte información numérica y de fecha a caracteres, mientras que
TO_NUMBER y TO_DATE convierte datos de tipo carácter en números y fechas respectivamente. El
concepto de conversión implícita y explícita de datos se presenta en la siguiente sección.
convierten a tipos de datos Oracle. Esta estrategia permite que aquellas aplicaciones que fueron escritas
para otros sistemas de bases de datos puedan ser migradas a Oracle fácilmente.
La definición de una tabla se obtiene utilizando el comando DESCRIBE. Cada columna está asociada a un
tipo de dato que limita la naturaleza de los datos que puede almacenar. Una columna NUMBER no va a
poder almacenar datos de tipo carácter.
Una columna de tipo DATE no puede almacenar números o caracteres aleatorios. Sin embargo, los
caracteres equivalentes a números y fechas se pueden almacenar en campos de tipo VARCHAR2.
Si una función que acepta una entrada de datos tipo carácter recibe un número, Oracle procede
automáticamente a convertirlo en su carácter equivalente. Si la función acepta números o fechas y
encuentra un carácter, hay condiciones específicas que permiten que la conversión automática tenga
lugar. Los tipos de dato DATE y NUMBER son mucho más estrictos que los tipos VARCHAR2 y CHAR.
Aunque las conversiones de datos implícitas siempre están disponibles, es importante trabajar con
conversiones explicitas utilizando funciones que se aplican a un único registro (single-row conversion
functions). De hecho, la conversión de datos tipo carácter a datos de tipo NUMBER y DATE dependen de
máscaras de formato, que se presentarán más adelante en esta sección.
Cuando datos numéricos son proporcionados como entrada para funciones que esperan datos
de tipo carácter, la conversión de tipo de datos implícita asegura que estos datos numéricos
sean tratados como caracteres. De la misma manera, cadenas de caracteres que están
compuestas por dígitos numéricos se convierten implícitamente a valores numéricos cuando
ocurre una discordancia de tipos de datos. Sin embargo, hay ocasiones en las que esta
transformación implícita no se ejecuta como se esperaría, tal y como ocurre en la siguiente
cláusula WHERE:
Considere datos de una tabla T basados en una columna de tipo carácter C, que contiene la
cadena de caracteres ‘100’. La condición WHERE C=’100’ funciona como se esperaría, pero la
condición WHERE C=100 provocará el error “ORA-1722: invalid number”.
Ambas utilizan la función LENGTH, que toma una cadena de caracteres como parámetro. El número
1234567890 en la Consulta 1 se convierte implícitamente a cadena de caracteres, “1234567890”, antes
de ser evaluado por LENGTH, devolviendo el número 10. La Consulta 2 evalúa la función SYSDATE
inicialmente devuelve 07-APR-38. Esta fecha se convierte implícitamente a la cadena de caracteres:
“07APR-38” y posteriormente la función LENGTH devuelve el número 9.
157/306
SQL
No es común para los datos de tipo carácter que sean convertidos directamente a tipos numéricos dado
que la única condición bajo la que esto ocurre es que los datos de tipo carácter representen un formato
válido de número. La cadena de caracteres “11” se transformará implícitamente a número, pero
“11.123.456” no, tal y como demuestran las siguientes consultas:
Las consultas 3 y 4 convierten las cadenas “11” y “11.123” a los números 11 y 11.123 respectivamente,
antes de que la función MOD los evalúe y recupere los resultados 1 y 1.123. La consulta 5 devuelve el
error “ORA-1722: invalid number” cuando Oracle intenta realizar la transformación implícita carácter a
número falla, puesto que la cadena de caracteres “11.123.456” no es un número válido. La consulta 6
falla también con el error “ORA-1722: invalid number” dado que el símbolo del dólar no se puede
transformar implícitamente a número. La conversión implícita carácter a fecha es posible cuando la
cadena de caracteres presenta el siguiente patrón:
D y DD representan días del mes de uno o dos dígitos. MON es la abreviación de los meses en tres
dígitos, mientras que MONTH representa el nombre completo. R y RR representan años de uno o dos
dígitos. YYYY representa el año escrito con cuatro dígitos. Los elementos separador1 y separador2
equivalen a casi cualquier signo de puntuación, espacios y guiones. En la siguiente tabla se muestran
varios ejemplos de conversiones implícitas carácter a fecha, formando una lista de varias llamadas de
funciones y de resultados que SQL Developer devuelve.
months_between(‘13*jan*8’,’13/feb/2008’) DD*MON*R, -1
DD/MON/YYYY
158/306
SQL
Las funciones de conversión explicita son esenciales para manipular información de fechas,
números y caracteres.
La tabla siguiente muestra la sintaxis de las funciones de conversión explícita que se aplican a un único
registro (single-row explicit data type conversion functions).
Los parámetros opcionales de soporte de idioma nacional (nls_parameters) son útiles para especificar el
idioma y el formato en el que se devuelven los nombres de los elementos de fecha y numéricos. Estos
parámetros suelen estar ausentes, y se utilizan los valores por defecto para elementos como los nombres
159/306
SQL
de día o mes y las abreviaturas. En la figura siguiente se pueden ver algunos parámetros
NLS_SESSION_PARAMETERS que contienen parámetros NLS para la sesión.
El valor por defecto NLS_CURRENCY es el símbolo del dólar, pero se puede modificar a nivel de sesión de
usuario. Por ejemplo, para cambiar la moneda a la cadena USD de tres caracteres, se puede emitir el
siguiente comando:
ALTER SESSION SET nls_currency='USD';
El parámetro number1 es obligatorio y debe ser un valor que sea o pueda ser convertido implícitamente
en un número. El parámetro opcional format se puede utilizar para especificar información respecto al
formato numérico, como la anchura, el símbolo de moneda, la posición de un punto decimal y los
separadores de grupo (o miles). Se deben incluir entre comillas simples.
160/306
SQL
La Consulta 1 evalúa el número 00001, elimina los ceros a la izquierda, convierte el número 1 en el
carácter "1" y devuelve la cadena "1 is a special number". La Consulta 2 aplica la máscara de formato
numérico "0999999" al número 00001, convirtiéndolo en la cadena de caracteres "0000001". Después
de la concatenación con los literales de los caracteres, la cadena devuelta es "0000001 is a special
number". El cero y los seis nueves en la máscara de formato indican a la función TO_CHAR que deben
visualizarse ceros a la izquierda y que el ancho de visualización debe ajustarse a siete caracteres. Por lo
tanto, la cadena devuelta por la función TO_CHAR contiene siete caracteres.
Hay otras opciones de formato para los números que son convertidos en caracteres, algunos de los cuales
se enumeran en la tabla siguiente:
161/306
SQL
En la imagen siguiente se puede observar cómo la consulta recupera las columnas JOB_TITLE y
MAX_SALARY de la tabla JOBS para los registros con la palabra “PRESIDENT” en el JOB_TITLE
independientemente de las mayúsculas y minúsculas de los caracteres utilizados para almacenar el título
puesto. MAX_ SALARY también ha sido formateado para tener un símbolo de moneda de dólar, una coma
como separador de miles y un punto como separador de decimales. Cuando una máscara de formato es
más pequeña que el número que se está convirtiendo, como se ilustra en el cuarto elemento de la lista
SELECT, se devuelve una cadena de símbolos (#). Cuando una máscara de formato contiene menos
componentes fraccionarios que el número, primero se redondea al número de decimales en la máscara
de formato antes de ser convertida.
162/306
SQL
La conversión de números a caracteres es una forma fiable de garantizar que las funciones y
la sintaxis SQL general, que espera la introducción de caracteres, no devuelvan errores cuando
se encuentran números. La conversión de números en cadenas de caracteres es común cuando
los datos numéricos deben formatearse con fines informativos. Las máscaras de formato que
soportan moneda, separadores de miles y separadores de punto decimal se utilizan con
frecuencia al presentar datos financieros.
163/306
SQL
Solo el parámetro date1 es obligatorio y debe adoptar la forma de un valor que pueda convertirse
implícitamente en una fecha. El parámetro format es opcional, distingue entre mayúsculas y minúsculas
y debe incluirse entre comillas simples. La máscara de formato especifica qué elementos de fecha se
extraen y si el elemento debe describirse con un nombre largo o abreviado. Los nombres de los días y
meses se rellenan automáticamente con espacios. Estos pueden ser eliminados usando un modificador
de la máscara de formato llamado fill mode operator (fm). Al prefijar el modelo de formato con las letras
fm, se instruye a Oracle para que recorte todos los espacios de los nombres de días y meses. Hay muchas
opciones de formato para las fechas que son convertidas a caracteres, algunas de las cuales se enumeran
en la siguiente tabla.
164/306
SQL
D Día de la semana 2
Si la fecha actual del sistema es 03/JAN/09 y el formato de visualización por defecto es DD/MON/RR, la
Consulta 1 devuelve la cadena "03/JAN/09 is today’s date".
Hay dos componentes a resaltar de la Consulta 2. En primer lugar, sólo se convierte a tipo carácter el
componente ‘Month’ de la fecha actual del sistema. En segundo lugar, como la máscara de formato
distingue entre mayúsculas y minúsculas y el componente 'Month' aparece como título, la cadena
devuelta es " January is a special time". No hay necesidad de añadir un espacio delante de la cadena "is
a special time", ya que la función TO_CHAR rellena automáticamente el nombre del mes con espacios (si
es necesario) para obtener una cadena de nueve caracteres de longitud. Dado que january tiene ocho
caracteres, se añade un espacio, pero si el mes fuera septiembre, no se añadirían espacios
automáticamente. Si la máscara de formato en la Consulta 2 fuera 'MONTH', la cadena devuelta sería
"January is a special time".
El modificador fm se aplica a la Consulta 3, y la cadena resultante es " Januaryis a special time". Nótese
que no hay espacio entre January y la cadena de texto “is a special time” como resultado del modificador
‘fm’. En la tabla anterior, se asume que los elementos están operando en la fecha 02-JUN-1975, siendo
el 2009 el año en curso.
Los elementos con formato de fecha correspondientes a semanas, trimestres, siglos y otras máscaras de
formato menos comunes se enumeran en la tabla que se mostrará a continuación. La columna de
resultados se obtiene de la evaluación de la función TO_CHAR utilizando la fecha 24-SEP-1000 BC, con
la misma máscara de formato que la de la primera columna de la tabla. El componente de tiempo de los
datos de tipo fecha y hora se extraen utilizando los modelos de formato de la tabla siguiente. Son el
resultado de evaluar la función TO_CHAR usando la fecha incluyendo su componente de tiempo 27-
JUN2010 21:35:13, con la máscara de formato de la primera columna de la tabla.
165/306
SQL
CC Centenario 10
166/306
SQL
MI Minuto (0-59) 35
SS Segundo (0-59) 13
En la tabla que se encuentra a continuación se resumen otros elementos que también pueden ser
utilizados en los modelos de fecha y hora. Los signos de puntuación se utilizan para separar los elementos
de formato. Existen tres tipos de sufijos para formatear los componentes de los elementos de fecha y
hora. Además, las cadenas de caracteres pueden incluirse en un modelo de formato de fecha si están
declarados entre comillas. Los resultados de la siguiente tabla se obtienen al aplicar la función TO_CHAR
utilizando la fecha 12/SEP/08 14:31 con las máscaras de formato de la columna “Descripción y máscara
de formato”.
La tabla JOB_HISTORY realiza un seguimiento de las funciones llevadas a cabo por los empleados en la
empresa. La consulta realizada en la siguiente imagen recupera una sentencia descriptiva sobre la fecha
de renuncia de cada empleado basada en sus campos END_DATE, EMPLOYEE_ID y JOB_ID. Una
expresión de carácter se concatena a una llamada a la función TO_CHAR con un modelo de formato de
'fmDay "the "ddth "of" Month YYYYY'. El modificador fm se utiliza para recortar los espacios en blanco
que siguen los nombres de los días y meses más cortos. Los dos caracteres literales entre comillas dobles
son las palabras "the" y "of". El modelo en formato th se aplica al elemento de fecha ‘dd’ para crear un
167/306
SQL
día ordinal como el día 17º o 31º. El formato del modelo ‘Month’ muestra el nombre completo del mes
de la columna END_DATE como título. Por último, la máscara de formato YYYY recupera el componente
de cuatro dígitos del año.
168/306
SQL
La función TO_DATE tiene un modificador fx, que es similar al modificador fm, usado en la función
TO_CHAR, y especifica una correspondencia exacta entre string1 y la máscara de formato. Cuando fx se
especifica, los caracteres que no concuerdan exactamente devuelven un error. Considérense las
siguientes 5 consultas:
La Consulta 1 evalúa la cadena 25-DEC-2010 y tiene suficiente información para convertirla en un ítem
DATE, utilizando la máscara DD-MON-YY, implícitamente. El guion utilizado para separar podría ser
sustituido por cualquier otro símbolo de puntuación. Dado que no se proporcionan elementos de tiempo,
se configurará para la media noche o 00:00:00.
La Consulta 2 no puede convertir de manera implícita la cadena dado que no hay suficiente información
y se devuelve un error de tipo: “ORA-01840: input value is not long enough for date format”.
En la Consulta 3 sí se proporciona una máscara de tipo DD-MON, por lo que se consigue que concuerden
los ítems para la transformación. El año será introducido implícitamente por la función SYSDATE y el
horario se configura a media noche.
La Consulta 4 procede a hacer una conversión completa con todos los elementos de fecha y hora y Oracle
no necesita dar ningún valor por defecto.
169/306
SQL
La función TO_DATE se usa en la cláusula WHERE de la anterior imagen para limitar los registros
devueltos para aquellos empleados que se contrataron después del 12 de enero de 2008. La máscara de
formato concuerda 01 con MM, 12 con DD y 2008 con YYYY.
Solamente el string1 es obligatorio. Si no hay máscara de formato (format) se debe introducir un valor
que se pueda convertir implícitamente en números. El parámetro opcional format se especifica entre
comillas. Las máscaras de formato son idénticas a las que se listaron en las tablas para TO_CHAR.
Considérense las siguientes consultas:
La Consulta 1 no puede proceder a hacer una conversión implícita debido a los símbolos del dólar, la
coma y el punto. Se recupera un error de tipo: “ORA-1722: invalid number”.
La Consulta 2 combina el símbolo del dólar, la coma y el punto de la cadena de caracteres con la máscara
de formato, y aunque la amplitud numérica es mayor que la de la cadena, se devuelve el número
1000.55.
Como se muestra en la siguiente imagen, se utiliza la función SUBSTR para extraer los últimos 8
caracteres de la columna PHONE_NUMBER. Posteriormente, se utiliza la función TO_NUMBER para
convertir dichos caracteres en un número (incluyendo el punto decimal), y, finalmente, se multiplica este
número por 10000 para aquellos empleados con valor de DEPARTMENT_ID = 30.
170/306
SQL
Problema Solución
Se necesita extraer el día y el mes de Sí. Con la función TO_CHAR se puede colocar un ítem de
una columna fecha y compararla con los tipo DATE mediante una máscara: “DD-MON” de manera
componentes correspondientes de la que se aíslen los componentes día y mes. Este valor se
fecha de sistema actual. ¿Esta compara con la actual fecha del sistema mediante la
comparación se puede hacer? siguiente expresión: TO_CHAR(SYSDATE, 'DD-MON')
Se pide un informe sobre las ganancias Sí. La cantidad numérica se debe convertir a una cadena
y pérdidas que muestre los resultados de caracteres utilizando la función TO_CHAR con una
de la siguiente manera: máscara de formato que la englobe entre paréntesis si es
Si la cantidad es negativa, debe estar negativa y la preceda por un signo del dólar. La siguiente
colocada entre paréntesis. La cantidad función ofrece dicho formato: TO_CHAR(AMOUNT,
debe tener el símbolo del dólar delante. '$999999PR')
¿Se pueden obtener estos resultados en
dicho formato?
171/306
SQL
Al sustituir parámetros de la función anterior por funciones, se puede obtener una expresión como la
siguiente:
Las funciones anidadas son las primeras en ser evaluadas, ya que sus salidas son utilizadas como
parámetros de entradas en otras funciones. Además, se evalúan desde el nivel más profundo al más
externo. La expresión previa es analizada de la siguiente forma:
Hay tres funciones dentro de la cláusula SELECT, que de nivel más bajo a nivel más alto son: TO_DATE,
TO_CHAR y LENGTH. El proceso que se sigue para evaluar esta función es:
Problema Solución
En las funciones anidadas, ¿se evalúan primero las No. Las funciones anidadas se resuelven
funciones más externas? evaluando de la función más interna hasta
la más externa.
¿Deben todas las funciones dentro de una expresión No. Los tipos de datos pueden diferir de
anidada devolver el mismo tipo de datos? una a la otra. La única característica
imprescindible es que el tipo de datos de
salida de un nivel inferior sea igual al de
los datos de entrada del nivel justo por
encima.
172/306
SQL
¿Existe alguna manera de mostrar la información sobre Si, una solución elegante y simple podría
SALARY de la tabla EMPLOYEES en la forma $13,000 sin ser utilizar la función TO_CHAR con la
usar la siguiente expresión? máscara de formato “$99G999”:
SELECT '$'|| SELECT TO_CHAR(SALARY,
SUBSTR(SALARY,1,MOD(LENGTH(SALARY),3))||', '$99G999') FROM EMPLOYEES;
'|| SUBSTR(SALARY,
MOD(LENGTH(SALARY),3)+1)
a. La función NVL
La función NVL evalúa si una columna o expresión de cualquier tipo de dato es NULL o no. Si es NULL,
se devuelve un valor alternativo; en caso contrario, se devuelve el término inicial.
La función NVL tiene dos parámetros obligatorios. Su sintaxis es:
Donde original representa el término que se está probando e ifnull representa el resultado devuelto si el
término original evaluado es NULL. Los tipos de datos de los parámetros original e ifnull deben ser
siempre compatibles. Deberán ser del mismo tipo, o bien ser posible convertir ifnull implícitamente al
tipo del parámetro original. La función NVL devuelve un valor con el mismo tipo de dato que el parámetro
original. Considérese la siguiente consulta:
Dado que la función NVL tiene dos parámetros obligatorios, la Consulta 1 devolverá el error “ORA-00909:
invalid number of arguments”.
La Consulta 2 devolverá 1234 después de que la palabra clave NULL sea probada y se encuentre que es
el valor nulo.
La Consulta 3 devolverá una función anidada SUBSTR que intenta extraer el cuarto carácter de una
cadena de 3 caracteres. La función interna devuelve NULL, dejando NVL(null,'No substring exists') que,
al ser ejecutada, que devuelve la cadena ‘No substring exists’.
173/306
SQL
La imagen anterior muestra dos consultas casi idénticas. Ambas consultas seleccionan registros en los
que LAST_NAME empieza por la letra ‘E’. Las columnas LAST_NAME, SALARY y COMMISSION_PCT son
también seleccionadas. La diferencia está en la expresión calculada llamada MONTHLY_COMMISSION.
Debido a la función NVL en la primera consulta se devuelven resultados numéricos. La segunda consulta
devuelve algunos valores nulos y un elemento numérico, aunque se añadan 1000 a cada registro.
Es tentador construir una expresión compleja compuesta por muchas llamadas a funciones
anidadas, pero este enfoque evoluciona con la práctica y la experiencia. Es recomendable
analizar una solución para una consulta y separar los componentes en llamadas a funciones.
La tabla DUAL es útil para pruebas lógicas ad hoc y depuración de llamadas a funciones
separadas. No se debe tener miedo de ejecutar consultas tantas veces como se desee para
perfeccionar los componentes antes de enlazarlos en componentes cada vez más grandes. Se
debe probar y depurar éstos hasta que la expresión final quede establecida.
174/306
SQL
b. La función NVL2
La función NVL2 proporciona una mejora a la función NVL, ambas tienen un propósito muy similar. Se
evalúa si la columna o expresión de cualquier tipo de datos es NULL. Si el primer término es no nulo,
entonces se devuelve el segundo parámetro; en caso contrario, se devuelve el tercer parámetro.
Recordar que la función NVL es diferente ya que devuelve el término original si no es nulo.
La función NVL2 tiene tres parámetros obligatorios. Su sintaxis es:
Donde original representa el término que se empieza a probar. Ifnotnull es el parámetro devuelto si
original es no nulo, e ifnull es el parámetro que se devuelve si original es nulo. El tipo de datos de los
parámetros ifnotnull y de ifnull deben ser compatibles y no pueden ser de tipo LONG. Ambos deben ser
del mismo tipo o a ser posible, convertir el parámetro ifnull al mismo tipo que el parámetro ifnotnull. El
tipo de dato devuelto por la función NVL2 es el mismo que el del parámetro ifnotnull. Considérese las
siguientes consultas:
El término ifnotnull en la Consulta 1 es un número mientras que el parámetro ifnull es ‘a string’. Ya que
los tipos de datos son incompatibles entre ellos, se devolverá el error “ORA-01722: invalid number”.
175/306
SQL
La imagen anterior muestra cómo es utilizada la función NVL2 para proporcionar texto descriptivo que
clasifica a los empleados con valores de LAST_NAME que empiezan por “F” en “Commision Earner” o no,
basados en la columna COMMISSION_PCT (que puede ser nula).
c. La función NULLIF
La función NULLIF comprueba dos términos por igualdad. Si estos son iguales, la función devolverá un
NULL; en caso contrario, devolverá el primero de los dos términos probados.
La función NULLIF tiene dos parámetros obligatorios de cualquier tipo de dato. La sintaxis es:
NULLIF(ifunequal, comparison_term)
Donde los parámetros ifunequal y comparison_term son comparados. Si estos son idénticos, entonces
se devuelve NULL. En caso de ser diferentes, el parámetro ifunequal será devuelto. Considérense las
siguientes consultas:
176/306
SQL
La ecuación aritmética de la Consulta 2 se evalúa implícitamente y la función NULLIF encuentra que 1234
es equivalente a 1233+1 (1234), por tanto, también devolverá NULL.
Los caracteres de las cadenas de caracteres de la Consulta 3 no son convertidos implícitamente a tipo
DATE y son comparados por la función NULLIF como dos cadenas de caracteres. Ya que ambas cadenas
tienen diferente longitud, se devolverá el parámetro ifunequal 24-JUL-2009.
La anterior imagen muestra cómo NULLIF es anidada como un parámetro a la función NVL2. La función
NULLIF en sí misma contiene las funciones de caracteres SUBSTR y UPPER incorporadas como una
expresión, utilizándose como el parámetro ifunequal. La columna EMAIL se compara con una expresión
formada por la concatenación del primer carácter de FIRST_NAME con el equivalente en mayúsculas de
la columna LAST_NAME para empleados con nombres con cuatro caracteres. Cuando estos términos son
iguales, NULLIF devuelve un valor NULL; en caso contrario, devuelve el parámetro evaluado ifunequal.
Este se utiliza como un parámetro para la función NVL2. La función NVL2 proporciona texto descriptivo
clasificando registros como coincidentes con el patrón o no.
177/306
SQL
d. La función COALESCE
La función COALESCE devuelve el primer valor no nulo de una lista de parámetros. Si todos los
parámetros son nulos, entonces devuelve NULL. La función COALESCE tiene dos parámetros obligatorios
y un número de parámetros opcionales. La sintaxis es:
COALESCE(expr1, expr2,…,exprn)
Donde se devuelve la expr1 si es no nula; en caso contrario, se devuelve el parámetro expr2, y así
sucesivamente. COALESCE es una forma general de la función NVL, como se muestra en las siguientes
ecuaciones:
COALESCE(expr1, expr2)=NVL(expr1,expr2)
COALESCE(expr1,expr2,expr3)=NVL(expr1,NVL(expr2,expr3))
El tipo de dato que devuelve la función COALESCE es un valor no nulo del mismo tipo que el primer
parámetro no nulo que se encuentre. Para evitar el error “ORA-00932: inconsistent data types”, todos
los parámetros no nulos deben tener tipos de datos compatibles con el primer parámetro no nulo.
Considérense las siguientes consultas:
La Consulta 1 devuelve el cuarto parámetro: una cadena de texto, ya que es el primer parámetro no
nulo encontrado.
La Consulta 2 devuelve un valor nulo porque todos los parámetros pasados son NULL.
La Consulta 3 evalúa el primer parámetro, que es una función anidada SUBSTR, y lo encuentra nulo. El
segundo parámetro es no nulo, así que la cadena ‘Not bc’ es devuelta.
178/306
SQL
a. La función DECODE
La función DECODE implementa la lógica ‘if-then-else’ al comprobar sus dos primeros términos para ver
si son iguales y recupera un tercero si efectivamente lo son, siendo opcional recuperar un cuarto valor
en caso de que esta condición no se cumpla. Es decir, esta función necesita obligatoriamente al menos
tres parámetros de entrada. La sintaxis es como sigue:
DECODE(expr1,comp1,iftrue1,[comp2,iftrue2...[compN,iftrueN]],[iffalse])
Expr1 se compara a comp1. Si fueran iguales, se recupera iftrue1. Si no lo fueran, el valor recuperado
dependerá de si comp2 y iftrue2 existen. Si están presentes, expr1 se comparará con comp2. Si ambos
son iguales se recupera iftrue2. Si no lo son, lo que pase dependerá de si compN e iftrueN existen como
pareja y el ciclo sigue hasta que no queda ninguna comparación por hacer. Finalmente, si ninguna de las
179/306
SQL
comparaciones son verdaderas, se recupera iffalse. Si este valor no estuviera definido, se recuperaría un
valor NULL.
Todos los parámetros de DECODE pueden ser expresiones, con lo cual, esta función se convierte en una
función anidada. Dado que los datos deben coincidir por parejas, si hubiera alguna discordancia en tipo
de datos, implícitamente se procede a realizar las adaptaciones necesarias.
Considérese como ejemplo las siguientes consultas:
La Consulta 1 compara el número 1234 con el primer término 123 de la comparación. Dado que no son
iguales, el primer resultado no se puede devolver. Además, como no hay una cláusula definida para
iffalse, se recupera un valor NULL.
La Consulta 2 es idéntica, pero sí tiene un valor definido para iffalse: “No match”.
La Consulta 3 busca a través de los valores de la comparación para encontrar una concordancia. En el
componente 3, parámetro 6, sí se encuentra una coincidencia puesto que contiene la cadena “search”.
Por tanto, se recuperará el parámetro 7 “true3”. Dado que se ha encontrado una comparación verdadera,
la búsqueda finaliza. Por tanto, aunque el parámetro 4 también daría una búsqueda positiva, esta
expresión nunca será evaluada.
En la siguiente imagen podemos ver cómo se puede construir la expresión que permita clasificar
COUNTRY_ID de la tabla LOCATIONS según “Northern Hemisphere” o “Southern Hemisphere”, utilizando
la función DECODE.
180/306
SQL
b. La expresión CASE
Prácticamente todos los lenguajes de programación de 3ª y 4ª generación incluyen un comando CASE,
que facilita la lógica ‘if-then-else’. Existen dos variantes de la expresión CASE. La expresión simple CASE
contiene una lista con los elementos de búsqueda y procede a comprobar si son iguales. La expresión de
búsqueda CASE construye una lista separada de condiciones para cada expresión de comparación.
Para poder entender estos conceptos con claridad, obsérvese la sintaxis de la expresión simple CASE:
CASE search_expr WHEN comparison_expr1 THEN iftrue1 [WHEN comparison_expr2 THEN iftrue2
…
WHEN comparison_exprN THEN iftrueN ELSE iffalse]
END
Como se puede observar, esta expresión está encapsulada en un bloque CASE … END y consta de, al
menos una sentencia WHEN … THEN, donde comparison_expr1 se compara con search_expr. Si son
iguales, se devuelve iftrue1. Si no, a no ser que se defina un parámetro iffalse, se recupera un valor
NULL. Si existe más de una cláusula WHEN … THEN, la búsqueda sigue hasta encontrar un caso
verdadero.
Los parámetros de búsqueda, comparación y resultado pueden ser columnas, expresiones o variables,
pero todos deben ser del mismo tipo de datos. Obsérvese la siguiente consulta:
181/306
SQL
SELECT
CASE substr(1234,1,3)
WHEN '134' THEN '1234 is a match'
WHEN '1235' THEN '1235 is a match'
WHEN concat('1','23') THEN concat('1','23')||' is a match'
ELSE 'no match'
END
FROM dual;
Véase un ejemplo. Las columnas LAST_NAME y HIRE_DATE para empleados con DEPARTMENT_ID no
iguales a 50, 80, 90, 100 o 110 se recuperan junto con dos expresiones numéricas y una expresión
CASE, tal y como se ve en la imagen que se muestra más abajo. La expresión numérica llamada MONTHS
devuelve un valor truncado obtenido de calcular los meses de servicio entre el 1 de enero 2013 y la fecha
de contratación del empleado utilizando la función MONTHS_BETWEEN.
Se han definido cinco categorías de lealtad a la empresa, basadas en cada dos años de servicio, al truncar
el cociente obtenido al dividir el total de meses de servicio entre 24. Con esto, se forma la expresión
para la búsqueda CASE. Ninguna de las expresiones coincide con la expresión de la primera sentencia
WHEN … THEN, pero como vemos en la imagen, el resto de WHEN … THEN recupera 13 registros y 3 más
se recuperan gracias a la sentencia ELSE. El conjunto de datos se clasifica por meses.
182/306
SQL
CASE
WHEN condition1 THEN iftrue1 [WHEN condition2 THEN iftrue2
…
WHEN conditionN THEN iftrueN ELSE iffalse]
END
La expresión buscada en CASE está encapsulada en un bloque CASE … END y consiste de al menos una
sentencia WHEN … THEN. En la forma más simple con una sola sentencia, la condition1 se evalúa, si es
verdadera, se recupera iftrue1, si no, se recupera un valor NULL a menos que haya componente definido
en ELSE. Cuando hay más de una sentencia WHEN … THEN, se continúa con la búsqueda hasta encontrar
un caso que sea VERDADERO. De no encontrar ninguno, se recuperará o bien NULL o bien el valor definido
en la cláusula ELSE. Para recuperar los mismos datos que en la imagen anterior mediante esta nueva
sintaxis, se podría utilizar la siguiente consulta:
183/306
SQL
ORDER BY months;
5.4. Resumen
Describir varios tipos de funciones de conversión válidas en SQL
• Cuando los valores no coinciden con los parámetros definidos de las funciones, Oracle intenta
convertirlos en los tipos de datos requeridos. Esto se conoce como conversión implícita.
• La conversión explícita se produce cuando se llama una función como TO_CHAR para modificar
el tipo de datos de un valor.
• La función TO_CHAR realiza una conversión de fecha a carácter y de número a carácter.
• Los parámetros de tipo carácter son transformados explícitamente a valores de fecha utilizando
la función de conversión TO_DATE.
• Los parámetros de tipo carácter son transformados a valores de números utilizando la función
de conversión TO_NUMBER.
184/306
SQL
Las funciones GROUP se examinan en dos etapas. Primero, se discute su propósito y su sintaxis. En
segundo lugar, se realiza un análisis detallado de las funciones AVG, SUM, MIN, MAX y COUNT. El concepto
de agrupar o segregar datos basados en uno o más valores de columna se evalúa antes de introducir la
cláusula GROUP BY. La cláusula WHERE restringe los registros de un conjunto de datos antes de la
agrupación, mientras que la cláusula HAVING los restringe después de la agrupación. Este capítulo
concluye con un debate sobre la cláusula HAVING.
En esta sección, se definen las funciones group SQL y se discuten las diferentes variantes. Se explica la
sintaxis de las funciones GROUP seleccionadas, se discuten sus tipos de datos y se explora el efecto de
la instrucción DISTINCT sobre ellas. Esta discusión se divide en dos áreas principales:
185/306
SQL
La función group se ejecuta una vez para cada registro y devuelve un único resultado por grupo. Estos
grupos pueden ser tablas enteras o partes de tablas asociadas usando un valor o atributo común. Si
todos los registros de las tablas se presentan como un grupo en la función GROUP , se devuelve un
resultado. Una o más funciones de agregación pueden aparecer en la lista SELECT de la siguiente manera:
Considérese la tabla EMPLOYEES. Hay 107 registros en esta tabla. Los grupos se pueden crear basándose
en los valores comunes que comparten los registros. Por ejemplo, los registros que comparten el mismo
valor de DEPARTMENT_ID pueden agruparse. A continuación, las funciones GROUP se ejecutan por
separado para cada grupo único. Como muestra la siguiente imagen, hay 12 valores distintos de
DEPARTMENT_ID en la tabla EMPLOYEES, incluyendo un valor nulo. Los registros se distribuyen en 12
grupos basados en valores comunes de DEPARTMENT_ID. La función COUNT se ejecuta 12 veces, una
por cada grupo. Se observa que los distintos grupos no contienen el mismo número de registros.
186/306
SQL
Las funciones GROUP agregan varios valores de varios registros en un único resultado. Se
utilizan ampliamente con fines de presentación de informes y también se conocen como
funciones resumidas o agregadas. Los datos agregados útiles como suma, promedios y
recuentos a menudo forman la base de cálculos estadísticos más sofisticados. Es útil tener un
buen entendimiento de los datos almacenados en las tablas de aplicación para maximizar la
calidad de los informes.
COUNT({*|[DISTINCT|ALL] expr}) ;
El tipo de datos expr puede ser NUMBER, DATE, CHAR, o VARCHAR2. Esta sintaxis puede descomponerse
de la siguiente forma:
187/306
SQL
1. COUNT(*)
2. COUNT(DISTINCT expr)
3. COUNT(ALL expr)
4. COUNT(expr)
Cuando se invoca COUNT(*), se cuentan todos los registros del grupo, incluidos los que tienen valores
nulos o duplicados. Cuando se ejecuta COUNT(DISTINCT expr), sólo se cuentan las veces que aparece
expr en cada grupo. La palabra clave ALL es parte de la sintaxis por defecto, por lo que COUNT(ALL expr)
y COUNT(expr) son equivalentes: cuentan el número de veces que expr aparece en cada grupo. Si expr
es nulo, se ignora a menos que se maneje usando una función general como NVL, NVL2, o COALESCE.
La función AVG calcula el valor promedio de una columna numérica o expresión en un grupo. Su sintaxis
es la siguiente:
AVG([DISTINCT|ALL] expr) ;
El tipo de datos del parámetro expr es NUMBER. Esta sintaxis puede descomponerse de la siguiente
forma:
1. AVG(DISTINCT expr)
2. AVG(ALL expr)
3. AVG(expr)
Cuando se invoca AVG(DISTINCT expr), los valores de expr se suman y dividen por el número de
ocurrencias únicas de expr. AVG(ALL expr) y AVG(expr) suman los valores no nulos de expr para cada
registro y dividen la suma por el número de registros no nulos en el grupo.
La función SUM devuelve la agregación de los valores numéricos no nulos en un grupo. Tiene la siguiente
sintaxis:
SUM([DISTINCT|ALL] expr) ;
El tipo de datos expr es NUMBER. Esta sintaxis puede descomponerse de la siguiente forma:
1. SUM(DISTINCT expr)
2. SUM(ALL expr)
3. SUM(expr)
4.
SUM(DISTINCT expr) proporciona un resultado sumando todos los valores únicos devueltos después de
que expr es evaluado para cada registro en el grupo. SUM(expr) y SUM(ALL expr) proporcionan un
resultado añadiendo expr para cada registro del grupo. Los valores nulos son ignorados.
Las funciones MAX y MIN devuelven el valor expr máximo (mayor) y mínimo (menor) en un grupo. Su
sintaxis es la siguiente:
188/306
SQL
El tipo de datos del parámetro expr puede ser NUMBER, DATE, CHAR, o VARCHAR2. Esta sintaxis puede
descomponerse de la siguiente forma:
MAX(expr), MAX(ALL expr) y MAX(DISTINCT expr) examinan los valores de expr en un grupo de registros
y devuelven el valor mayor. Los valores nulos son ignorados. MIN(expr), MIN(ALL expr) y MIN(DISTINCT
expr) examinan los valores de expr en un grupo de registros y devuelven el valor más pequeño.
Las funciones STDDEV y VARIANCE son dos de las muchas funciones GROUP estadísticas que ofrece
Oracle.
VARIANCE([DISTINCT|ALL] expr);
El tipo de datos del parámetro expr es NUMBER. Esta sintaxis puede descomponerse de la siguiente
forma:
1. VARIANCE(DISTINCT expr)
2. VARIANCE(ALL expr)
3. VARIANCE(expr)
La varianza estadística se refiere a la variabilidad de los datos de una muestra o conjunto de datos.
VARIANCE(DISTINCT expr) devuelve la variabilidad de datos únicos no nulos en un grupo.
VARIANCE(expr) y VARIANCE(ALL expr) devuelven la variabilidad de los datos no nulos en el grupo.
El tipo de datos del parámetro expr es NUMBER. Esta sintaxis puede descomponerse de la siguiente
forma:
1. STDDEV(DISTINCT expr)
2. STDDEV(ALL expr)
3. STDDEV(expr)
STDDEV calcula la desviación estándar estadística, que es el grado de desviación del valor medio en un
grupo. Se obtiene encontrando la raíz cuadrada de la varianza. STDDEV(DISTINCT expr) devuelve la
desviación estándar de datos únicos no nulos en un grupo. STDDEV(expr) y STDDEV(ALL expr) devuelven
la desviación estándar de los datos no nulos en el grupo.
Hay dos reglas fundamentales a recordar cuando se estudian las funciones GROUP . Primero,
siempre operan sobre un solo grupo de registros a la vez. El grupo puede ser uno de los
muchos grupos en los que se ha segmentado un conjunto de datos, o puede ser una tabla
189/306
SQL
completa. La función group se ejecuta una vez por grupo. Segundo, los registros con algún
campo nulo en sus columnas o expresiones de grupo son ignorados, a menos que se provea
una función general como NVL, NVL2, o COALESCE para manejarlas.
Considerar el siguiente ejemplo. Si el valor medio de COMMISSION_PCT se recupera de la
tabla EMPLOYEES, sólo se consideran los valores no nulos. La expresión
AVG(COMMISSION_PCT) suma los 35 valores no nulos de COMMISSION_PCT y divide el total
entre 35. El promedio basado en las 107 filas puede calcularse utilizando la expresión
AVG(NVL(COMMISSION_PCT,0)).
a. La función COUNT
La ejecución de COUNT en una columna o en una expresión devuelve un valor entero que representa el
número de registros en el grupo. La función COUNT tiene la siguiente sintaxis:
COUNT({*|[DISTINCT|ALL] expr});
Hay un parámetro que puede ser, o bien *, que representa todas las columnas incluyendo valores nulos,
o bien una columna específica o una expresión. Puede ser precedida por la palabra clave DISTINCT o
ALL. Se consideran las siguientes consultas:
190/306
SQL
La consulta 1 cuenta los registros en la tabla EMPLOYEES y devuelve el resultado 107. La consulta 2
cuenta los registros de COMMISSION_PCT con valores no nulos y devuelve 35. La consulta 3 tiene en
cuenta los 35 registros no nulos, determina el número de valores únicos y devuelve 7. La consulta 4
muestra dos funcionalidades. La primera, es posible usar varias funciones GROUP en la misma consulta
SELECT y segunda, la función COUNT se usa en columnas de tipo DATE y tipo NUMBER. Los resultados
107 y 106 son los devueltos ya que hay 107 valores no nulos de HIRE_DATE y 106 valores no nulos de
MANAGER_ID en el grupo.
En la imagen siguiente, tres funciones COUNT son usadas a la vez. Esta consulta muestra que hay 107
registros de empleados en la tabla EMPLOYEES. Además, estos 107 empleados están en 12
departamentos, incluyendo departamentos nulos y trabajan en 19 trabajos únicos.
b. La función SUM
La suma total de una columna o una expresión se calcula usando la función SUM. Su sintaxis es la
siguiente:
SUM([DISTINCT|ALL ] expr);
Un valor numérico, puede ser precedido por la palabra clave DISTINCT o ALL, se le pasa a la función
SUM, que devuelve un número. Se consideran las siguientes consultas:
Hay 107 registros en la tabla EMPLOYEES. La consulta 1 añade 2 a todos los registros y devuelve 214.
La consulta 2 toma el valor de la columna SALARY para cada registro en el grupo, en este caso es la
tabla entera y devuelve el salario total de 691416. La consulta 3 devuelve un total de 409908 ya que
muchos de los empleados tienen el mismo salario y la palabra clave DISTINCT solo suma los valores
únicos de la columna al total. La consulta 4 devuelve 7.8 después de sumar los valores no nulos.
191/306
SQL
La siguiente imagen muestra dos consultas. La primera calcula el número de días entre el final de 2015
y el valor de la columna HIRE_DATE. La aritmética de fechas se realiza para cada registro. El número
devuelto es sumado usando una llamada a la función SUM.
El resultado está dividido por 365.25 para dar el número total de años trabajados por todos los empleados
actuales. La segunda consulta muestra que la función SUM devuelve el error “ORA-00932: inconsistent
datatypes” si la función recibe un parámetro no numérico.
c. La Función AVG
El valor medio de una columna o expresión divide la suma por el número de registros no nulos en el
grupo. La función AVG tiene la siguiente sintaxis:
AVG([DISTINCT|ALL] expr);
Un valor numérico, puede ser precedido por la palabra clave DISTINCT o ALL, se le pasa a la función
AVG, que devuelve un número. Se consideran las siguientes consultas:
Existen 107 registros en la tabla EMPLOYEES. La consulta 1 añade el número 2 a los 107 registros y
divide el total por el número de registros para devolver el número 2. Las variables numéricas enviadas
a la función AVG son devueltos sin cambios. La consulta 2 suma el valor SALARY en cada registro para
obtener el salario total de 691400. Dicho valor se divide por los 107 registros con valores no nulos de
SALARY y devuelve la media de 6461.83178. Cabría esperar que la consulta 3 devolviese un resultado
menor que la consulta 2, pero no. Existen 58 valores únicos de salario, que sumados dan un total de
409908. Dividiendo 409908 entre 58 devuelve 7067.37931 como media de los salarios distintos. La
consulta 4 puede producir resultados imprevistos si no se entiende de forma adecuada. Tras sumar los
valores no nulos, incluyendo duplicados, suma un total de 7.8 que, dividido entre 35 devuelve una media
de 0.222857143 de COMMISION_PCT.
La siguiente imagen muestra dos consultas. La primera muestra las columnas LAST_NAME y JOB_ID con
una
192/306
SQL
expresión que calcula el número total de años trabajados por los programadores en la organización desde
el final de 2015. El segundo usa la función AVG para calcular el número medio de años que los
programadores actuales han estado contratados desde el año 2015.
Toman un parámetro precedido por la palabra clave DISTINCT o ALL. Se consideran las siguientes
consultas:
La consulta 1 devuelve los valores numérico 0.1 y 0.4 para el mínimo y máximo de los valores de
COMMISION_PCT en la tabla EMPLOYEES. Nótese que los valores nulos de la tabla COMMISION_PCT son
ignorados. La consulta 2 evalúa una columna del tipo DATE e indica que la fecha de START_DATE en la
tabla JOB_HISTORY más antigua es 17-SEP-1995 y la última END_DATE es 31-DEC-2007. La consulta 3
devuelve los valores AC_ACCOUNT y ST_MAN de la columna JOB_ID como primer y último registro
ordenado alfabéticamente en la tabla EMPLOYEES.
La primera consulta mostrada en la siguiente imagen usa las funciones MAX y MIN para obtener
información sobre los empleados con el valor de JOB_ID igual a “SA_REP”. Los resultados indican que los
representantes de ventas trabajando el menor y máximo tiempo fueron empleados el 21-APR-2008 y el
30-JAN-2004, respectivamente. Por otra parte, los representantes de ventas con mayor y menor salario
193/306
SQL
ganan 11500 y 6100, respectivamente. La segunda consulta muestra los valores de la columna
LAST_NAME de los representantes de ventas a los que se aplican los valores mínimo y máximo
HIRE_DATE y SALARY.
Problema Solución
194/306
SQL
MIN(SALARY)
Lowest_Salary,
MAX(SALARY)
Maximum_Salary
FROM EMPLOYEES;
G1(group_item) = result
G1(G2(group_item ) = result
G1(G2(G3(group_item))) no está permitido.
Las funciones GROUP se representan mediante la letra “G” seguida de un número. El primer formulario
simple no contiene funciones anidadas. Los ejemplos incluyen las funciones SUM(group_item) y
AVG(group_item) que devuelven un único resultado por grupo. El segundo formulario contiene dos
funciones de GROUP anidadas: SUM (AVG(group_item)). En este caso, una cláusula GROUP BY es
obligatoria ya que el valor medio del grupo group_item por cada agrupación se calcula antes de ser
agregado por la función SUM.
La tercera forma es rechazada por Oracle. Se considera una expresión que anida tres funciones GROUP
. Si la función MAX se aplica al ejemplo anterior, se forma la expresión MAX(SUM(AVG(group_item))).
Las dos funciones GROUP internas devuelven un único valor que representa la suma de un conjunto de
valores medios. Esta expresión se convierte en MAX (valor individual). Una función GROUP no se puede
aplicar a un valor individual.
195/306
SQL
Esta imagen muestra dos consultas. Ambas restringen los registros devueltos a aquellos con valores de
DEPARTMENT_ID null, 40 y 80. Estos se divididen por sus valores DEPARTMENT_ID en tres grupos. La
primera consulta calcula la suma de los valores de COMMISSION_PCT para cada grupo y devuelve los
valores 0.15, null, y 7.65. La consulta 2 contiene las funciones GROUP anidadas, que se pueden evaluar
como se indica a continuación:
Las funciones de un solo registro pueden anidarse a cualquier nivel, pero las funciones GROUP
pueden anidarse, como máximo, dos niveles de profundidad. La llamada de función anidada
COUNT(SUM(AVG( X))) devuelve el error, “ORA-00935: group function is nested too deeply.”
Es aceptable anidar funciones de un solo registro dentro de funciones GROUP . Se puede
considerar la siguiente pregunta: SELECT SUM(AVG(LENGTH(LAST_NAME))) FROM
EMPLOYEES GROUP BY DEPARTMENT_ID. Calcula la suma de la longitud media de los valores
de LAST_NAME por departamento.
196/306
SQL
Los grupos de datos dentro de un conjunto se crean asociando registros con propiedades o atributos
comunes. Desde ese momento, las funciones GROUP pueden ejecutarse contra cualquiera de esos
grupos.
Se considera la tabla EMPLOYEES. Está compuesta por 11 columnas y 107 registros. Se podrían crear
grupos de registros que compartan el valor de DEPARTMENT_ID. La función SUM podría ser usada para
crear el cómputo de salarios totales por departamento. Otra posible agrupación podría ser para registros
que compartan el mismo valor de la columna JOB_ID. La función AVG podría ser usada para saber el
salario medio pagado a los empleados en diferentes trabajos.
Un grupo es definido como un subconjunto del conjunto de datos entero, cuyo subconjunto comparte
uno o más atributos. Estos atributos son típicamente valores de una columna, pero también pueden ser
expresiones. El número de grupos creado depende de los diferentes valores únicos de un atributo común.
197/306
SQL
El agrupamiento de datos y las funciones de resumen son ampliamente utilizadas como fines
de reporte. Es importante practicar la segmentación de un conjunto de datos en diferentes
agrupaciones. Oracle proporciona el lenguaje analítico para deconstruir conjuntos de datos
en grupos, dividirlos en subgrupos, etc. Se pueden ejecutar funciones de agregación sobre
estos grupos y subgrupos.
SELECT
column|expression|group_function(column|expression [alias]),…}
FROM table
198/306
SQL
[WHERE condition(s)]
[GROUP BY {col(s)|expr}]
[ORDER BY {col(s)|expr|numeric_pos} [ASC|DESC] [NULLS FIRST|LAST]];
Es común ver el atributo de la agrupación en la lista SELECT junto con las funciones GROUP . Si un
elemento que no es una función GROUP aparece en la lista SELECT con otras funciones GROUP y no hay
ninguna cláusula GROUP BY, se produce un error “ORA-00937: not a single-group group function”. Si una
cláusula GROUP BY está presente pero este ítem no es un atributo de agrupación, entonces se devuelve
el error “ORA-00979: not a GROUP BY expression”.
Cualquier elemento de la lista SELECT que no sea una función GROUP debe ser un atributo de agrupación
de la cláusula GROUP BY.
Si se introduce una función GROUP en una cláusula WHERE, se devuelve un error “ORA-00934: group
function is not allowed here”.
Se pueden imponer condiciones a nivel de grupo usando la cláusula HAVING discutida en la siguiente
sección. Sin embargo, las funciones GROUP pueden utilizarse como parte de la cláusula ORDER BY.
La primera consulta de la imagen plantea un error ya que la columna END_DATE está en la lista SELECT
con una función GROUP y no hay ninguna cláusula GROUP BY. Se devuelve un error “ORA-00979” de la
segunda consulta, ya que el elemento START_DATE aparece en la cláusula SELECT, pero no es un atributo
de la agrupación.
La tercera consulta divide los registros de JOB_HISTORY en grupos por año de la columna END_DATE.
Se crean cuatro grupos utilizando este atributo de agrupación. Estos representan diferentes años en los
que los empleados terminaron su trabajo. El COUNT muestra el número de empleados que renunciaron
a sus trabajos durante cada uno de estos años. Los resultados se listan en orden descendente según la
expresión "Number of Employees". Se debe tener en cuenta que la función GROUP COUNT está presente
en la cláusula ORDER BY.
199/306
SQL
200/306
SQL
La consulta 1 restringe los registros devueltos de la tabla EMPLOYEES a 35 registros con valores de
COMMISSION_PCT no nulos. Estos registros están divididos en 2 grupos: 80 y NULL basados en el
atributo de agrupación DEPARTMENT_ID. El conjunto de resultados contiene dos registros, los cuales
devuelven la suma de los valores de COMMISSION_PCT de cada grupo.
La consulta 2 es similar a la primera excepto porque tiene un elemento adicional: JOB_ID en sendas
cláusulas SELECT y GROUP BY. Este segundo atributo de agrupación se descompone en dos grupos
basados en DEPARTMENT_ID en los componentes JOB_ID constituyentes que pertenecen a los registros
de cada grupo. Los distintos valores de JOB_ID para los registros con DEPARTMENT_ID=80 son SA_REP
y SA_MAN. El valor de JOB_ID para los registros con valor de DEPARTMENT_ID nulo es SA_REP. Por lo
tanto, la consulta 2 devuelve dos agrupaciones, una que consiste en dos subgrupos y la otro con
solamente uno, tal y como se muestra en la siguiente imagen:
Problema Solución
201/306
SQL
¿Es posible contar los registros en cada Sí. Agrupar múltiples columnas es una
grupo, primero dividiendo los registros gran opción permitiendo un análisis
de empleados por año de contratación,
bastante fino, tal y como se muestra en
después por trabajo, y finalmente por
salario? la siguiente consulta:
SELECT COUNT(*),
GROUP BY
TO_CHAR(HIRE_DATE,'YYYY') ,
JOB_ID, SALARY;
La siguiente consulta limita las filas recuperadas de la tabla JOB_HISTORY especificando una condición
WHERE basada en la columna DEPARTMENT_ID.
SELECT department_id
FROM job_history
WHERE department_id IN (50,60,80,110);
Esta consulta devuelve siete registros. Si la cláusula WHERE estuviera ausente, se recuperarían los 10
registros. Suponga que desea saber cuántos empleados trabajaban anteriormente en cada uno de estos
departamentos. Hay siete registros que se pueden agrupar y contar manualmente. Sin embargo, si hay
un gran número de registros, se puede utilizar una función GROUP como COUNT, como se muestra en la
siguiente consulta:
202/306
SQL
Esta consulta es muy similar a la anterior. La función GROUP: COUNT se añadió a la lista SELECT, y
también se incorporó una cláusula GROUP BY DEPARTMENT_ID. Se devuelven cuatro registros con su
número total de registros y los siete registros originales restringidos por la cláusula WHERE que se han
agrupado en cuatro grupos basados en valores comunes de DEPARTMENT_ID, como se muestra en la
siguiente tabla:
DEPARTMENT_ID COUNT(*)
50 2
60 1
80 2
110 2
Suponga que desea refinar esta lista para incluir sólo los departamentos con más de un empleado. La
cláusula HAVING limita o restringe el nivel de grupo filas si es necesario.
Esta consulta se construirá siguiendo los siguientes pasos:
203/306
SQL
Una diferencia importante entre la cláusula HAVING y las demás cláusulas de la declaración SELECT es
que sólo puede especificarse si existe una cláusula GROUP BY. Esta dependencia es razonable, ya que
los registros a nivel de grupo deben existir antes de que se puedan restringir. La cláusula HAVING puede
aparecer antes de la cláusula GROUP BY en la sentencia SELECT. Sin embargo, es más común colocar la
cláusula HAVING después de la cláusula GROUP BY. Se realiza toda la agrupación y las funciones GROUP
se ejecutan antes de evaluar la cláusula HAVING.
La siguiente consulta muestra cómo se utiliza la cláusula HAVING para restringuir un conjunto de datos
agregado. Los registros de la tabla JOB_HISTORY se dividen en cuatro grupos. Se devuelven los registros
que cumplen la condición de la cláusula HAVING (contribución de más de un registro al recuento de
registros del grupo):
Dos registros con valores DEPARTMENT_ID de 80 y 110, cada una con un COUNT(*) de 2 son devueltos.
Obsérvese que el atributo de agrupación DEPARTMENT_ID puede estar presente en la cláusula HAVING.
La imagen que se muestra a continuación presenta tres consultas. La primera consulta divide los 107
registros de la tabla EMPLOYEES en 19 grupos basados en valores JOB_ID comunes. Se calcula el salario
medio de cada grupo JOB_ID y el número total de registros. La segunda consulta introduce un grado
más de filtraje, al excluir condicionalmente los registros agregados en las que el salario medio es inferior
o igual a 10000, utilizando una cláusula HAVING. La tercera consulta demuestra que se pueden utilizar
los operadores booleanos para especificar múltiples condiciones de la cláusula HAVING.
204/306
SQL
La cláusula HAVING sólo puede especificarse cuando existe una cláusula GROUP BY. Se puede
especificar una cláusula GROUP BY sin una cláusula HAVING. Se pueden imponer múltiples
condiciones mediante una cláusula HAVING utilizando los operadores booleanos AND, OR, y
205/306
SQL
NOT. Las condiciones de la cláusula HAVING restringen los datos a nivel de grupo y deben
contener una función GROUP o una expresión basada en los atributos de agregación.
6.5. Resumen
Describir las funciones grupales
• Las funciones GROUP se conocen también como funciones de registro múltiple, agregadas o de
resumen. Se ejecutan una vez para cada grupo de datos y agregan la información desde múltiples
registros a un único resultado por cada grupo.
• Los grupos pueden ser tablas enteras o porciones de una tabla agrupada por un atributo de
agrupación común.
Identificar las Funciones GROUP Disponibles.
• La función COUNT devuelve un valor entero que representa el número de registros en un grupo.
• La función SUM calcula la agregación total de todas las expresiones numéricas del grupo que no
sean nulas.
• La función AVG divide la suma de una columna o expresión por el número de registros no nulos
del grupo.
• Las funciones MAX y MIN operan sobre tipos de datos NUMBER, CHAR, DATE y VARCHAR2.
Devuelven los valores mayor y menor del grupo. Las funciones de
grupo solo pueden anidarse con dos niveles de profundidad.
• La cláusula GROUP BY especifica el atributo de agrupación que los registros deben tener en
común para poder ser aglomerados conjuntamente.
• La cláusula GROUP BY permite la creación de grupos dentro de un conjunto de datos
seleccionados y se coloca después de la cláusula WHERE pero antes que la cláusula ORDER BY.
• Cualquier elemento de la lista SELECT que no es una función GROUP , debe ser un atributo de
agrupación.
• Las funciones GROUP no pueden estar colocadas dentro de la cláusula WHERE.
• Los conjuntos de datos se pueden partir en grupos y dividirse en subgrupos basándose en
atributos de agrupación múltiple.
• Las agrupaciones de registros que utilizan un atributo de agregación común con la cláusula
GROUP BY y, sobre las que se aplica una función GROUP para cada uno de los conjuntos,
devuelven resultados a nivel de grupo.
• La cláusula HAVING proporciona el lenguaje para limitar los resultados a nivel de grupo
devueltos.
• La cláusula HAVING solo puede especificarse si hay una cláusula GROUP BY presente.
• Todas las agrupaciones que se llevan a cabo y las funciones GROUP son ejecutadas antes de
evaluar la cláusula HAVING.
206/306
SQL
7.1. Sentencias SELECT para acceder a datos de más de una tabla utilizando
EQUIJOINS y NONEQUIJOINS
Los tres pilares para la teoría relacional son selección, proyección y unión. Este capítulo se
centra en la aplicación práctica de la unión. Registros de tablas diferentes se asocian unas a
otras mediante uniones (joins). Muchos modelos de datos se diseñan para poder usar esta
herramienta, tales como los esquemas en estrella o la tercera forma normal.
Las tablas se pueden unir de varias formas. La más común se llama equijoin. Un registro se asocia con
uno o más registros de otra tabla basándose en la igualdad de los valores o expresiones comprendidas
en dicha columna. Las tablas se pueden también unir con nonequijoin. En este caso, se asocian registros
de tablas diferentes dentro de rangos definidos por operadores de desigualdad. En ambos casos, se
excluyen los registros nulos o que tienen distintas entradas para uniones comunes.
Algo menos común es asociar registros de la misma tabla. Se usa con columnas que tienen relaciones
lógicas y normalmente jerárquicas entre ellas. Este tipo de unión se llama self-join.
Además, existe un OUTER JOIN para buscar registros sin uniones si es necesario.
Un CROSS JOIN o producto cartesiano se forma cuando cada registro de una tabla se une a todos los
registros de otra. Esta unión normalmente es el resultado de uniones inadecuadas, aunque puede ser
intencionado en alguna ocasión.
Consulta 1: SELECT *
FROM countries
WHERE country_id='CA';
Consulta 2: SELECT region_name FROM regions
WHERE region_id=2;
El nombre de la región a la que un país pertenece se puede determinar al obtener su REGION_ID. Este
valor se usa para unirlo con el registro en la tabla REGIONS con el mismo REGION_ID. La Consulta 1
207/306
SQL
recupera los valores de la columna asociada a la tabla COUNTRIES donde COUNTRY_ID = “CA” y su
REGION_ID es 2. La Consulta 2 busca el REGION_NAME “Americas” de la tabla REGIONS para el registro
con REGION_ID =2. Hacer un equijoin hace fácil la recuperación de las columnas de varias tablas
utilizando una única consulta.
Las tablas fuente y objetivo pueden intercambiar su naturaleza, siendo REGIONS la fuente y COUNTRIES
el objetivo.
Considere las dos consultas siguientes:
Consulta 1: SELECT *
FROM regions
WHERE region_name='Americas';
Consulta 2: SELECT country_name
FROM countries
WHERE region_id=2;
La Consulta 1 busca un registro con un REGION_ID = 2. Al unir de esta forma, la pregunta equivalente
sería: ¿Qué países pertenecen a la región Americas? La respuesta de la Consulta 2 son 5
COUNTRY_NAME: Argentina, Brasil, Canadá, México y Estados Unidos de América. Estos resultados se
podrían obtener de una consulta única que uniera ambas tablas. A continuación, se introduce la sintaxis
para hacer equijoins, nonequijoins, outer joins, ycross joins.
a. INNER JOIN
La cláusula INNER JOIN se implementa usando tres posibles cláusulas JOIN: NATURAL JOIN, USING y
ON.
Cuando las tablas fuente y objetivo comparten nombres idénticos de columnas, es posible hacer una
unión natural entre ellas sin especificar una columna de unión. En este escenario, las columnas de mismo
nombre se asocian automáticamente. Los registros con valores de columnas coincidentes en ambas
tablas son recuperados como resultados. Ambas tablas del ejemplo comparten la columna REGION_ID y
se pueden unir de forma natural tal y como se ve en la siguiente figura.
208/306
SQL
Las palabras clave NATURAL JOIN hacen que Oracle identifique las columnas con igual nombre entre las
tablas. Seguidamente, se realiza implícitamente la operación JOIN. En la primera consulta, REGION_ID
se identifica como la única columna común; REGIONS es la tabla fuente y aparece en la cláusula FROM;
la tabla objetivo es COUNTRIES. Para cada registro de las tablas REGIONS se busca una coincidencia
para REGION_ID en la tabla COUNTRIES. Se construye una unión provisional que contiene los registros
que coinciden con la condición de unión. Entonces, este conjunto se restringe con la cláusula WHERE.
Dado que “COUNTRY_NAME” tiene el valor “Canada”, la consulta devuelve “Americas”, que es el valor de
la “REGIONS” a la que pertenece.
La segunda consulta muestra una unión natural donde COUNTRIES es la tabla fuente. El valor de
REGION_ID para cada registro en la tabla COUNTRIES se identifica y se busca una coincidencia en la
209/306
SQL
tabla REGIONS. Si se encuentran, los resultados provisionales quedaran limitados por las condiciones en
la cláusula WHERE. Los COUNTRY_NAME de los registros con “Americas” como REGION_NAME son
recuperados como conjunto de resultados.
A veces se necesita ejercer más control sobre qué columnas se usan para las uniones. Cuando existen
columnas con nombres idénticos, pero se quieren excluir como columnas de unión, se debe usar le
formato JOIN … USING. Recuerde que Oracle no impone ninguna regla que diga que las columnas con el
mismo nombre deben tener necesariamente una relación. La tercera consulta especifica explícitamente
que la tabla REGIONS debe unirse con COUNTRIES a través de la columna unión REGION_ID. Esta
sintaxis permite INNER JOINs sobre columnas especificas en vez de sobre cualquier columna que tenga
el mismo nombre.
La cuarta consulta hace una demostración de cómo usar el formato JOIN_ON de los INNER JOIN, que
permite declarar explícitamente las columnas unión. Este formato no depende de que las columnas
compartan nombre puesto que es mucho más general y de hecho es el método INNER JOIN más usado.
Cuidado cuando se usan uniones naturales puesto que los diseñadores de bases de datos
pueden asignar nombres iguales a columnas únicas. Estas columnas puede que lleven
nombres como ID o SEQ_NO. Si una unión natural se lleva a cabo entre dichas tablas, pueden
aparecer resultados inesperados o ambiguos.
b. OUTER JOIN
No todas las tablas comparten una relación perfecta, donde cada registro de la tabla fuente se puede
unir con al menos un registro de la tabla objetivo. Ocasionalmente se requiere que se recuperen registros
de una columna de registros dispares.
Suponga que las tablas EMPLOYEES y DEPARTMENTS se unen a través de valores comunes
DEPARTMENT_ID. Los registros de EMPLOYEES con DEPARTMENT_ID = Null serán excluidos junto con
los valores ausentes de la tabla DEPARTMENTS. Un OUTER JOIN consigue recuperar esos registros
“perdidos”.
c. CROSS JOIN
Un CROSS JOIN o producto Cartesiano recibe su nombre de matemáticas, donde también se refiere a un
producto cruzado entre dos conjuntos de matrices. Esta unión crea un registro de salida para cada
combinación de tabla fuente y objetivo.
Si la tabla fuente tiene 3 registros y la tabla objetivo tiene 4, la unión cruzada resultará en (3 x 4 =12)
registros de salida. Considérese la siguiente figura, donde los primeros dos recuentos se producen entre
las tablas COUNTRIES y REGIONS con 25 y 4 registros respectivamente. En la consulta 3 el número de
registros recuperado por el producto cruzado de estas tablas es 100. En la consulta 4 se recuperarían
100 registros si la cláusula WHERE no estuviera definida. Cada uno de los cuatro registros de la tabla
REGIONS se une con una de la tabla COUNTRIES. Cada registro obtenido contiene todas las columnas
de ambas tablas.
210/306
SQL
211/306
SQL
FROM regions,countries;
La Consulta 1 procede a realizar un INNER JOIN al especificar la condición de unión mediante la cláusula
WHERE. Esta es la diferencia más importante con respecto a la sintaxis tradicional y la sintaxis de uniones
ANSI SQL. Nótese que renombrar una columna como TABLE.COLUMN_NAME hace que desaparezca la
ambigüedad entre columnas con el mismo nombre. Este tipo de notación se va a desarrollar en
profundidad durante este capítulo.
La Consulta 2 especifica la unión entre ambas tablas mediante la condición WHERE. Hay un signo (+) a
la izquierda del símbolo igual que indica a Oracle que se debe proceder a realizar un RIGHT OUTER JOIN.
Esta consulta devuelve el LAST_NAME de los empleados y los asocia a los valores de DEPARTMENT_NAME.
Además, el OUTER JOIN devuelve DEPARTMENT_NAME de los registros con valores de DEPARTMENT_ID
no asignados a ningún registro de empleado. La Consulta 3 realiza un producto Cartesiano o CROSS JOIN
al excluir la condición de unión.
Esto se analizará y se explicarán los ejemplos en las siguientes secciones. La forma general de la sintaxis
tradicional de Oracle, relevante para las uniones es la siguiente:
Si en las condiciones de la cláusula WHERE no se especifican uniones o hay menos de N-1, donde N se
refiere al número de tablas de la consulta, se realiza una unión cartesiana o cruzada. Si se especifica un
número adecuado de condiciones de unión, entonces la primera cláusula condicional opcional
especifica una unión interna, mientras que las segundas dos cláusulas opcionales especifican la sintaxis
para las uniones externas derecha e izquierda.
212/306
SQL
columna REGION_ID está presente tanto en la tabla de REGIONS y COUNTRIES. Hacer una consulta de
alguna de estas columnas resulta problemática cuando Oracle no puede resolver su origen. Las columnas
con nombres únicos a través de las tablas involucradas en un JOIN no causan ambigüedad ya que Oracle
puede resolver fácilmente su tabla fuente.
El problema de los nombres de columna ambiguos, se aborda con notación por puntos. Una columna
puede ir precedida por el nombre de su tabla y un punto o símbolo para designar su origen, esto lo
diferencia de una columna con el mismo nombre en otra tabla. La notación de puntos se puede utilizar
en consultas que involucren cualquier número de tablas. La referencia a algunas columnas mediante
notación por puntos no implica que todas las columnas deban ser referenciadas de esta manera.
La notación de puntos se puede mejorar añadiendo un alias a la tabla. Un alias en la tabla proporciona
un nombre alternativo, normalmente más corto, para una tabla.
Una columna puede ser referenciada como TABLE_NAME.COLUMN_NAME o
TABLE_ALIAS.COLUMN_NAME.
Como se puede observar en la imagen anterior a la tabla EMPLOYEES se le referencia con el nombre
corto EMP mientras que a la tabla DEPARTMENTS no se le añade ningún alias. La cláusula SELECT hace
referencia a la EMPLOYEE_ID y MANAGER_ID como EMP.EMPLOYEE_ID y EMP.MANAGER_ID. Calificar la
columna EMPLOYEE_ID usando notación por puntos es innecesario porque sólo hay una columna con
este nombre entre las dos tablas. La columna MANAGER_ID debe estar calificada para evitar
ambigüedades ya que aparece en ambas tablas. Dado que se aplica el formato JOIN...USING, sólo se
utiliza DEPARTMENT_ID como columna de unión. Si se empleara un NATURAL JOIN, se utilizarían las
columnas DEPARTMENT_ID y MANAGER_ID. Si la columna MANAGER_ID no estaba cualificada, un error
213/306
SQL
"ORA-00918: column ambiguously defined " será devuelto. Si se creara un alias en DEPARTMENT_ID, se
produciría un error “ORA-25154: column part USING clause cannot have qualifier”.
SQL Developer proporciona el título MANAGER_ID a la primera referencia hecha en la cláusula SELECT.
La cadena "_1" se añade automáticamente a la segunda referencia, creando el título MANAGER_ID_1.
Las referencias de columna que califican con notación de puntos para indicar la tabla de origen
de una columna tienen un beneficio de rendimiento. Se ahorra tiempo porque Oracle es
dirigido instantáneamente a la tabla apropiada y no tiene que resolver el nombre de la tabla.
La unión natural identifica las columnas con nombres comunes en table1 y table2 e implícitamente une
las tablas utilizando todas estas columnas. Las columnas en la cláusula SELECT puede ser calificada
utilizando la notación punto; a menos que sean una de las columnas de unión. Considérense las
siguientes consultas:
Consulta 1: SELECT *
FROM locations
NATURAL JOIN countries;
Consulta 2: SELECT *
FROM locations, countries
La unión natural identifica columnas con nombre comunes entre las dos tablas. En la Consulta 1,
COUNTRY_ID aparece en ambas tablas y se convierte en la columna de unión. La Consulta 2 es escrita
siguiendo la sintaxis tradicional de Oracle y recupera los mismos registros que la Consulta 1. A menos
que se esté familiarizado con las columnas de la tabla origen y destino las uniones naturales deben ser
utilizadas con precaución, ya que las condiciones de unión se forman automáticamente entre todas las
columnas con nombres compartidos.
La Consulta 3 realiza una unión natural entre las tablas JOBS y COUNTRIES. No hay columnas con
nombres idénticos, resultando entonces un producto cartesiano. La Consulta 4 es equivalente a la
Consulta 3, y la unión cartesiana es realizada utilizando la sintaxis tradicional de Oracle.
La unión natural es simple, pero sufre el riesgo de que dos columnas con el mismo nombre no tengan
ninguna relación y ni siquiera tengan tipos de datos compatibles. En la imagen siguiente, las tablas
COUNTRIES, REGIONS y SALE_REGIONS están detalladas. La tabla SALES_REGIONS estaba construida
para ilustrar el siguiente punto importante: Aunque ésta tiene REGION_ID en común con la tabla
COUNTRIES, éstos no pueden ser unidos naturalmente porque sus tipos de datos son incompatibles. Los
tipos de datos de las columnas COUNTRIES.REGION_ID y SALES_REGIONS.REGION_ID son NUMBER y
214/306
SQL
VARCHAR2, respectivamente. El dato tipo carácter no puede ser convertido implícitamente a dato tipo
numérico y aparece el error “ORA-01722: invalid number”. La columna REGIONS.REGION_ID es de tipo
NUMBER y su dato está relacionado con el dato de la tabla COUNTRIES. Por lo tanto, la unión natural
entre las tablas REGIONS y COUNTRIES se realiza perfectamente.
215/306
SQL
216/306
SQL
FROM table1
JOIN table2 USING (join_column1, join_column2…);
Mientras que la unión natural contiene la palabra clave NATURAL en su sintaxis, la sintaxis JOIN...USING
no la contiene. Se produce un error si las palabras clave NATURAL y USING aparecen en la misma cláusula
de unión. La cláusula JOIN...USING permite una o más columnas de EQUIJOIN que se especificarán
explícitamente entre paréntesis después de la palabra clave USING. Esto evita los defectos asociados
con la unión natural. Muchas situaciones exigen que las tablas se unan sólo en ciertas columnas y este
formato satisface este requisito. Considerese las siguientes consultas:
Consulta 1: SELECT *
FROM locations
JOIN countries
USING (country_id);
Consulta 2: SELECT *
FROM locations, countries
WHERE locations.country_id = countries.country_id;
La Consulta 1 especifica que las tablas LOCATIONS y COUNTRIES deben unirse en valores de columna
COUNTRY_ID comunes. Todas las columnas de estas tablas se recuperan para los registros con valores
de columna de unión coincidentes. La Consulta 2 muestra una consulta especificada tradicionalmente
que recupera los mismos registros que la Consulta 1. Las columnas de unión especificadas con la sintaxis
JOIN...USING no se pueden clasificar utilizando nombres de tabla o alias cuando se hace referencia a
ellos en las cláusulas SELECT y JOIN.
Dado que esta sintaxis de unión excluye potencialmente algunas columnas con nombres idénticos de la
cláusula de unión, estas deben ser clasificadas si se hace referencia a ellas para evitar ambigüedades.
Como se muestra en la siguiente figura, las tablas JOB_HISTORY y EMPLOYEES se unieron basándose en
la presencia de valores iguales en sus columnas JOB_ID y EMPLOYEE_ID. Se recuperan los registros que
se ajustan a esta condición de unión.
Estas tablas comparten tres columnas con nombres idénticos. En este ejemplo, sólo dos de ellas se
especifican como columnas de unión. Observe que, aunque la tercera columna con el mismo nombre es
DEPARTMENT_ID, está clasificada con un alias de tabla para evitar ambigüedades, mientras que las
columnas de unión especificadas en la cláusula SELECT no pueden clasificarse con alias de tabla.
217/306
SQL
Las cláusulas NATURAL JOIN y JOIN…USING dependen de las columnas unidas mediante nombres
idénticos de columna. La cláusula JOIN…ON permite la especificación explícita de las columnas unidas,
independientemente de sus nombres de columna. Ésta es la forma más flexible y abierta de utilizar las
cláusulas de unión. Las palabras claves ON y NATURAL no pueden aparecer juntas en una misma cláusula
JOIN. Las columnas EQUIJOIN quedan perfectamente calificadas como table1.column1 = table2.column2
y están especificadas, opcionalmente, entre paréntesis después de la palabra clave ON.
Las siguientes consultas ilustran la cláusula JOIN…ON:
Consulta 1: SELECT *
FROM departments d
JOIN employees e ON (e.employee_id=d.department_id);
Consulta 2: SELECT *
FROM employees e, departments d
WHERE e.employee_id=d.department_id;
La Consulta 1 recupera todos los valores de las columnas de las tablas DEPARTMENTS y EMPLOYEES para
los registros que reúnen una condición EQUIJOIN. Esta condición está satisfecha por los valores de
EMPLOYEE_ID coincidiendo con los valores DEPARTMENT_ID en la tabla DEPARTMENTS. La sintaxis
tradicional de Oracle en la Consulta 2 devuelve el mismo resultado que la Consulta 1. Nótese las
similitudes entre la condición de unión tradicional especificada en la cláusula WHERE y la condición de
unión especificada después de la palabra clave ON.
En la imagen siguiente, la columna STAR_DATE en la tabla JOB_HISTORY está unida a la columna
HIRE_DATE de la tabla EMPLOYEES. Este EQUIJOIN recupera los detalles de los empleados que trabajaron
218/306
SQL
Problema Solución
219/306
SQL
Al unir dos tablas, existe el riesgo No. Oracle no sabe a partir de qué
de que entre ellas haya nombres tablas se originan dichas
de columnas comunes. ¿Sabe columnas, y se produce un error.
Oracle de qué tablas obtener los Las referencias ambiguas a
datos si tales columnas están columnas pueden evitarse
presentes en la lista SELECT? utilizados clasificadores. Los
clasificadores emplean la notación
punto para aclarar la tabla de
origen de una columna.
Navegar sobre este tipo de relaciones mediante uniones permite una recuperación de datos coherente y
fiable. Sin embargo, hay momentos en los que estas relaciones no están definidas entre tablas y, aun
así, pueden ser unidas, aunque el resultado no se beneficie de la integridad referencial impuesta por la
base de datos. Cuando existen uniones múltiples en una consulta, se evalúan de izquierda a derecha.
Considérese la siguiente consulta que mezcla uniones naturales y uniones de Oracle:
La unión natural entre DEPARTMENTS y LOCATIONS crea un resultado provisional que consiste en un
conjunto de 27 registros dado que se unen de manera implícita sobre la columna LOCATION_ID.
Seguidamente, este conjunto se une mediante un producto Cartesiano a la tabla COUNTRIES dado que
la condición de unión no se ha especificado. El resultado provisional se une a los 25 registros de la tabla
COUNTRIES y devuelve un nuevo resultado provisional de 675 (27 X 25) registros y tres columnas:
DEPARTMENT_NAME, CITY y COUNTRY_NAME. Este conjunto se une a su vez a la tabla REGIONS. Una
vez más, el producto cartesiano se aplica dado que no hay ninguna condición para la columna REGION_ID
que lo impida. El resultado final contiene 2700(675 x 4) registros y 4 columnas. La utilización de uniones
naturales y de Oracle de forma conjunta lleva a cometer errores y no se recomienda. En la siguiente
consulta se unen 4 tablas mediante la sintaxis de una unión natural:
220/306
SQL
Tras ejecutar esta petición, se devuelven 27 registros correctamente en el conjunto final de resultados
dado que las columnas de unión se establecen en la sentencia SELECT. La siguiente consulta demuestra
cómo se usaría la cláusula JOIN … ON para obtener las mismas 27 respuestas. En el siguiente ejemplo,
la unión de DEPARTMENTS sobre LOCATIONS no referencia ninguna columna de COUNTRIES o REGIONS,
pero la unión entre ambas puede referirse a cualquier columna de las 4 tablas incluidas en la consulta:
La cláusula JOIN … USING también puede usarse para unir las 4 tablas como se expone seguidamente:
La cláusula WHERE se usa para especificar las condiciones que restringen el conjunto de resultados de
una consulta tanto si contiene uniones como si no. La cláusula JOIN … ON se usa también para especificar
condiciones que limitan los resultados creados por la unión. Considérese las siguientes dos consultas:
221/306
SQL
Hay tres formatos para equijoin o inner join. La unión natural utiliza la cláusula NATURAL JOIN
y une dos tablas basadas en todas las columnas con nombres compartidos. Los otros dos
formatos usan las cláusulas JOIN … USING y JOIN … ON. Preste atención a la sintaxis dado
que una cláusula de unión tal que: SELECT * FROM TABLE 1 NATURAL JOIN TABLE 2 USING
(COLUMN) podría parecer correcta, pero es sintácticamente incorrecta. Se debe recordar que
el uso de las palabras clave USING, ON y NATURAL son mutuamente restrictivas en el contexto
de la misma cláusula de unión.
7.1.8. NONEQUIJOINS
Los NONEQUIJOINS coinciden con los valores de las columnas de diferentes tablas basadas en una
expresión de desigualdad. El valor de la columna de unión en cada registro de la tabla de origen se
compara con los valores correspondientes de la tabla de destino. Una coincidencia se encuentra si la
expresión usada en la unión, basada en un operador de desigualdad, se evalúa como verdadera.
Un NONEQUIJOIN se especifica usando la sintaxis JOIN...ON, pero la condición JOIN contiene un operador
de desigualdad en lugar de un signo igual.
El formato de la sintaxis para una cláusula NONEQUIJOIN es el siguiente:
222/306
SQL
FROM table1
[JOIN table2 ON (table1.column_name < table2.column_name)]|
[JOIN table2 ON (table1.column_name > table2.column_name)]|
[JOIN table2 ON (table1.column_name <= table2.column_name)]|
[JOIN table2 ON (table1.column_name >= table2.column_name)]|
[JOIN table2 ON ([Link] BETWEEN table2.col1 AND table2.col2)]
Considere los 16 registros devueltos por la consulta en la siguiente imagen. La tabla EMPLOYEES no está
ajustada a la tabla JOBS basada en la condición de igualdad de oportunidades
(2*[Link]<J.MAX_SALARY). La tabla JOBS almacena los rangos salariales para empleados con
diferentes funciones en la empresa. El valor SALARY para cada registro de empleado se duplica y se
compara con todos los valores MAX_SALARY de la tabla JOBS. Si la condición de unión se evalúa a TRUE,
se devuelve el registro.
Las NONEQUIJOINS no son tan usadas como las EQUIJOIN. El operador BETWEEN aparece a
menudo con condiciones NONEQUIJOIN. Es más sencillo usar un operador BETWEEN entre dos
condiciones NONEQUIJOIN basado en operadores: <= (menor o igual) y >= (mayor o igual)
223/306
SQL
Cuando dos tablas se unen, cada registro de la tabla fuente está supeditada a la condición de unión con
los registros de la tabla objetivo. Si la condición es VERDADERA, se recupera el registro unido,
consistiendo en columnas de ambas tablas.
Cuando las columnas unión se originan de la misma tabla, un self-join es necesario. Conceptualmente,
la tabla fuente se duplica para crear la tabla objetivo. Posteriormente, funciona como una unión normal
entre ambas tablas. Internamente, Oracle no duplica la tabla y esta descripción es meramente
proporcionada para explicar el concepto. Considere las siguientes tres consultas:
Para identificar el padre de una persona en la tabla FAMILY se puede usar la Consulta 1 para obtener los
valores de ID, NAME y FATHER_ID de la persona.
En la Consulta 2, el valor de FATHER_ID que se obtiene en la primera consulta, se puede sustituir para
obtener el NAME del padre. Nótese que ambas consultas obtienen la información de la tabla FAMILY.
En la Consulta 3 se procede a realizar un self-join utilizando la cláusula JOIN … ON al renombrar la tabla
FAMILY como f1 y f2. Oracle las trata como tablas diferentes, aunque ambas apuntan a la misma tabla
física. F1 se designa como tabla fuente, mientras que f2 es la tabla objetivo.
La condición en la cláusula ON tiene el formato source.child_id=target.parent_id. En la siguiente tabla
se ven las tres formas de self-join para la misma tabla:
224/306
SQL
225/306
SQL
7.3. Visualización de datos que no cumplen una condición JOIN utilizando OUTER JOIN
Los equijoins emparejan los registros entre dos tablas basadas en la igualdad de los datos de las
columnas almacenados en cada tabla. Los nonequijoins se basan en registros coincidentes entre tablas
basadas en una condición de unión que contiene una expresión de desigualdad. Por lo general, no se
requieren registros de la tabla destino sin una columna de unión coincidente en la tabla origen. Cuando
éstos son requeridos, sin embargo, se utiliza un OUTER JOIN para recogerlos. Se pueden utilizar varias
variaciones de OUTER JOIN dependiendo de si faltan datos en la columna unión de la tabla origen o de
la tabla destino o de ambos. Estas técnicas OUTER JOIN se describen a continuación:
226/306
SQL
Un LEFT OUTER JOIN realiza un INNER JOIN de table1 y table2 basado en la condición de unión especifica
después de la palabra clave ON. También se devuelven los registros de la tabla de la izquierda de la
palabra clave JOINexcluidas por no cumplir la condición del JOIN. Considérense las dos siguientes
consultas:
Las Consultas 1 y 2 son idénticas excepto por las cláusulas JOIN, las cuales están formadas por las
palabras claves LEFT OUTER JOIN y JOIN, respectivamente. La consulta 2 realiza un INNER JOIN,
devolviendo 7 registros. Estos registros comparten valores idénticos de DEPARTMENT_ID en ambas
tablas. La Consulta 1 devuelve los mismos 7 registros más un registro adicional. Este registro extra se
obtiene de la tabla que se encuentra a la izquierda de la palabra clave JOIN, que es la tabla
DEPARTMENTS. Este registro contiene detalles del departamento Payroll. El INNER JOIN no incluye este
registro ya que ningún empleado está asignado actualmente a dicho departamento.
En la siguiente imagen se muestra un ejemplo de un LEFT OUTER JOIN. El INNER JOIN produce 27
registros con valores de LOCATION_ID coincidentes en ambas tablas. Se muestran 43 registros en total,
lo que implica que se recuperaron 16 registros de la tabla LOCATIONS, que se encuentra a la izquierda
de la palabra clave JOIN. Ninguna de las filas de la tabla DEPARTMENTS contiene ninguno de estos 16
valores de LOCATION_ID.
227/306
SQL
Un RIGHT OUTER JOIN realiza un INNER JOIN de table1 y table2 basado en la condición de unión
específica después de la palabra clave ON. También se devuelven los registros de la tabla de la derecha
228/306
SQL
de la palabra clave JOINexcluidas por no cumplir la condición del JOIN. Considérese la siguiente consulta:
El INNER JOIN produce 7 registros que contienen detalles sobre los empleados con valores de LAST_NAME
que empiezan por la letra “G”. La tabla EMPLOYEES está a la derecha de la palabra clave JOIN. Cualquier
registro de empleados que no cumpla la condición JOIN está incluido, siempre y cuando cumplan con la
condición de la cláusula WHERE. Además, el RIGHT OUTER JOIN obtiene un registro de EMPLOYEE con
un LAST_NAME que comienza por la letra ‘G’. Este registro actualmente tiene un valor de
DEPARTMENT_ID nulo. El INNER JOIN excluye el registro ya que no se asigna ningún valor de
DEPARTMENT_ID a este empleado.
En la siguiente imagen se muestra un ejemplo de un RIGHT OUTER JOIN entre las tablas JOB_HISTORY
y EMPLOYEES. La tabla EMPLOYEES está a la derecha de la palabra clave JOIN. La palabra clave DISTINCT
elimina combinaciones duplicadas de valores de JOB_ID de las tablas. Los resultados muestran los
trabajos que los empleos que los empleados han dejado históricamente. También se devuelven los
trabajos que ningún empleado ha dejado. Estos tienen valor nulo en la columna “Jobs in JOB_HISTORY”.
229/306
SQL
Hay tres tipos de formatos OUTER JOIN. Cada uno de ellos realiza un INNER JOIN antes de
incluir registros que la condición JOIN excluye. Si se realiza un LEFT OUTER JOIN, entonces
los registros excluidos por el INNER JOIN, a la izquierda de la palabra clave JOIN, también se
devuelven. Si se realiza un RIGHT OUTER JOIN, los registros excluidos por el INNER JOIN, a
la derecha de la palabra clave JOIN, también se devuelven. El FULL OUTER JOIN realiza un
INNER JOIN asi como un LEFT OUTER JOIN y un RIGHT OUTER JOIN.
Un FULL OUTER JOIN devuelve los resultados combinados de un LEFT OUTER JOIN y un RIGHT OUTER
JOIN. Se realiza un INNER JOIN de table1 y table2 antes de que los registros excluidos por la condición
JOIN de ambas tablas sean incluidos en el conjunto de resultados.
230/306
SQL
La sintaxis tradicional de JOIN Oracle no soporta un FULL OUTER JOIN, que se realiza habitualmente por
combinación de resultados de un LEFT OUTER JOIN y un RIGHT OUTER JOIN utilizando el conjunto de
operadores UNION descrito en el capítulo 9. Considérese el FULL OUTER JOIN que se muestra en la
siguiente imagen. La cláusula WHERE, que restringe los resultados a los registros con valores de
DEPARTMENT_ID NULL, muestra los registros huérfanos en ambas tablas. Hay un registro en la tabla
EMPLOYEES que no tiene un valor de DEPARTMENT_ID, y hay 16 departamentos que no tienen ningún
empleado asignado.
Problema y solución
Problema Solución
231/306
SQL
Los datos de las dos tablas que se quieren unir Sí. La cláusula JOIN…ON está prevista para este
están relacionados, pero no comparten ninguna fin. Proporciona una solución flexible y genérica
columna con el mismo nombre. ¿Es posible unir para unir tablas basadas en nombre de columnas
las tablas utilizando columnas que no no idénticos.
comparten el mismo nombre?
Se precisa recuperar una lista de valores de Sí. Dependiendo de a qué lado de la palabra clave
DEPARTMENT_NAME y LAST_NAME para todos JOIN se escriba la tabla DEPARTMENTS, un LEFT
los departamentos, incluyendo aquellos que
OUTER JOIN o un RIGHT OUTER JOIN debe ser
actualmente no tienen empleados asignados.
En tales casos la cadena ‘No Employees’ debe utilizado, ya que ésta es la tabla donde se originan
mostrarse como valor de la columna los registros huérfanos. La siguiente consulta
LAST_NAME. ¿Se puede hacer esto utilizando satisface esta respuesta:
JOIN?
SELECT DEPARTMENT_NAME,
NVL(LAST_NAME, 'No
Employees')
Es importante tener en cuenta que no hay ninguna condición especificada utilizando las palabras clave
ON o USING. Un producto Cartesiano asocia de manera libre los registros de la tabla 1 con cada registro
232/306
SQL
de la tabla 2. Si se quisieran introducir limitaciones, debería utilizarse la cláusula WHERE. Si ambas tablas
contienen x e y número de registros, respectivamente, el producto Cartesiano tendría x por y registros.
El resultado de dicho producto se puede usar para identificar registros huérfanos o para generar un
conjunto de datos grande para la comprobación de aplicaciones. Considérese las siguientes consultas:
Consulta 1: SELECT *
FROM jobs
CROSS JOIN job_history;
Consulta 2: SELECT *
FROM jobs j
CROSS JOIN job_history jh
WHERE j.job_id='AD_PRES';
La Consulta 1 toma 19 registros y 4 columnas de la tabla JOBS y 11 registros con 5 columnas de la tabla
JOBS_HISTORY, generando un conjunto de 190 registros con 9 columnas. SQL*Plus presenta las
columnas con los mismos nombres. SQL Developer, sin embargo, añade al final del nombre un guion
bajo y un número para cada nombre de columna compartida y lo utiliza como título.
La columna JOB_ID es común para ambas tablas. Los nombres para SQL*Plus y SQL Developer son
JOB_ID y JOB_ID_1 respectivamente. En la Consulta 2, se genera el mismo producto, pero los 190
registros están filtrados por una cláusula WHERE y solo se recuperan 11 registros.
La siguiente imagen muestra un producto cruzado entre las tablas REGIONS y COUNTRIES. Hay 4
registros en REGIONS y 25 en COUNTRIES. Dado que hay una cláusula WHERE que limita la primera
tabla de 4 a 2 registros, Se obtendrán 50 resultados que se ordenarán alfabéticamente, primero por
REGION_NAME y después por COUNTRY_NAME. Nótese que COUNTRY_NAME aparece repetido para cada
REGION_NAME.
233/306
SQL
234/306
SQL
especifican menos condiciones que N-1, siendo N el número de tablas, o que especifican
condiciones invalidas, reúnen las características necesarias para generar dicho producto de
manera inintencionada. Una unión natural entre tablas que no comparten columnas con el
mismo nombre también genera un producto cartesiano, dado que hay dos tablas, pero hay
menos de una condición de unión disponible.
7.5. Resumen
Escribir sentencias SELECT para acceder a datos desde más de una tabla usando Equijoins y
Nonequijoins
• Los equijoins se producen cuando una consulta obtiene valores de columna de varias tablas en
las que los registros cumplen una condición de acoplamiento basada en la igualdad.
• La unión natural se realiza usando la sintaxis NATURAL JOIN cuando las tablas fuente y destino
están equijoined usando las columnas con idénticos nombres.
• La sintaxis JOIN...USING permite formar una unión interna en columnas específicas con nombres
compartidos.
• La notación de puntos se refiere a clasificar una columna prefijándola con el nombre de su tabla
y un punto o símbolo de punto. Esto designa la tabla que origina una columna y lo diferencia de
columnas con idénticos nombres de otras tablas.
• La cláusula JOIN...ON permite la especificación explícita para unir columnas independientemente
de sus nombres. Esto proporciona un formato de unión flexible.
• Las palabras clave ON, USING y NATURAL son mutuamente excluyentes y por lo tanto no pueden
aparecer juntas en una cláusula de unión.
• Un nonequijoin se realiza cuando los valores de las columnas de unión cumplen la condición de
unión basada en una expresión de desigualdad.
• Se requiere una SELF JOIN cuando las columnas de unión se originan en la misma tabla.
Conceptualmente, la tabla fuente se duplica y se crea una tabla destino. El self-join funciona
entonces como una unión regular entre dos tablas discretas.
• El almacenamiento de datos jerárquicos en una tabla relacional requiere un mínimo de dos
columnas por registro. Una columna almacena un identificador del registro padre de la línea y la
segunda almacena el identificador de la línea.
Ver datos que no coinciden con una condición JOIN mediante uniones externas
• Cuando se realizan equijoin y nonequijoin, se emparejan los registros de las tablas fuente y
destino. Estos se denominan INNER JOIN.
• Un OUTER JOIN se realiza cuando los registros, que no son recuperadas por un INNER JOIN, se
incluyen para la recuperación además de los registros recuperados por el INNER JOIN.
• Un LEFT OUTER JOIN entre las tablas origen y destino devuelve los resultados de un INNER JOIN
y los registros que faltan de la tabla origen.
• Un RIGHT OUTER JOIN entre las tablas origen y destino devuelve los resultados de una INNER
JOIN y los registros faltantes excluidas de la tabla destino.
235/306
SQL
• Un FULL OUTER JOIN devuelve los resultados combinados de un LEFT OUTER JOIN y un RIGHT
OUTER JOIN.
• Un producto cartesiano es a veces llamado un CROSS JOIN. Es una cuestión matemática que se
refiere al conjunto de datos creados por la fusión de los registros de dos o más tablas.
• El número de registros devueltos de un producto cartesiano es igual al número de registros en
la tabla de origen multiplicado por el número de registros en la tabla de destino.
• Las uniones que especifican menos de N-1 condiciones de unión al unir N tablas, o que especifican
condiciones de unión inválidas, crean productos cartesianos.
Se denomina subconsulta a una consulta que está anidada dentro de una instrucción SELECT, INSERT,
UPDATE, o DELETE o dentro de otra subconsulta. Una subconsulta puede devolver un conjunto de
columnas o solo una de ellas a la consulta padre. Se llama subconsultas escalares a aquellas consultas
que devuelven exactamente un valor: sólo un registro o sólo una columna. Una subconsulta escalar se
puede usar en declaraciones SQL donde suele usarse un valor literal.
Los lugares donde una subconsulta puede ser usada dentro de una consulta son los siguientes:
Una subconsulta puede tener cualquiera de las cláusulas habituales de selección y proyección. Las
siguientes, son cláusulas obligatorias:
236/306
SQL
• WHERE
• GROUP BY
• HAVING
La subconsulta (o subconsultas) dentro de una sentencia debe ejecutarse antes que la consulta de nivel
superior que la llama, para que los resultados de la subconsulta puedan pasarse al nivel superior.
SELECT avg(salary)
FROM employees;
SELECT last_name
FROM employees
WHERE salary < result_of_previous_query;
SELECT last_name
FROM employees
WHERE salary <
(SELECT avg(salary)
FROM employees);
En este ejemplo, la subconsulta se usa para sustituir un valor en la cláusula WHERE de la consulta
principal: devuelve un solo resultado, este valor se usa para filtrar los registros obtenidos en la consulta
principal.
La subconsulta podría devolver varios registros. Por ejemplo, se podría usar la siguiente consulta para
buscar todos los departamentos que tienen uno o más empleados asignados:
237/306
SQL
En el ejemplo anterior, la subconsulta se utiliza como alternativa a un JOIN. Se podría obtener el mismo
resultado con la siguiente consulta tal y como se muestra en la imagen.
SELECT department_name
FROM departments
JOIN employees
ON employees.department_id = departments.department_id
GROUP BY department_name;
Si una subconsulta puede devolver más de un resultado, el operador de comparación tiene que poder
aceptar varios valores. Estos operadores son IN, NOT IN, ANY y ALL.
Si el operador de comparación es EQUAL, GREATER THAN o LESS THAN (solo pueden aceptar un valor),
la consulta principal fallará.
238/306
SQL
El uso de NOT IN está plagado de problemas debido a la forma que SQL maneja valores nulos
(NULL). Como regla general, no se utiliza NOT IN a menos que sea muy claro que el conjunto
de resultados no devolverá ningún valor NULL.
SELECT count(quantity_sold)
FROM sales s, products p, customers c, channels ch
WHERE s.prod_id=p.prod_id
AND s.cust_id=c.cust_id
AND s.channel_id=ch.channel_id
AND p.prod_name='Comic Book Heroes'
AND c.cust_city='Oxford'
AND ch.channel_desc='Internet';
Esta consulta usa la cláusula WHERE para unir las tablas y filtrar los resultados. La siguiente alternativa
que devolverá el mismo resultado como se muestra en la imagen más abajo.
SELECT count(quantity_sold)
FROM sales
WHERE prod_id IN
(SELECT prod_id
FROM products
WHERE prod_name='Comic Book Heroes')
AND cust_id IN
(SELECT cust_id
FROM customers
WHERE cust_city='Oxford')
AND channel_id IN
(SELECT channel_id
FROM channels
WHERE channel_desc='Internet');
239/306
SQL
240/306
SQL
SELECT avg(salary),country_id
FROM (SELECT salary, country_id
FROM employees
NATURAL JOIN departments
NATURAL JOIN locations)
GROUP BY country_id;
La subconsulta construye conceptualmente una tabla con el salario de cada empleado y el país en el que
se encuentra su departamento. La consulta padre se dirige a esta tabla, promediando SALARY y
agrupando por COUNTRY_ID.
En esta sentencia, la lista SELECT se rellena con los resultados de las subconsultas. Una subconsulta
utilizada de esta manera debe ser escalar sino la consulta padre fallará con un error.
FROM sales
UPDATE employees
SET salary = (SELECT avg(salary)
FROM employees);
241/306
SQL
El primer ejemplo, referido al esquema SH, utiliza una subconsulta para identificar un conjunto de
registros en una tabla que se insertarán en otra. El segundo ejemplo utiliza una subconsulta para calcular
el salario medio de todos los empleados y transfiere este valor (una cantidad escalar) a una sentencia
de actualización. El tercer ejemplo utiliza una subconsulta para recuperar todos los DEPARTMENT_ID que
están en uso y pasa la lista a un comando DELETE, que eliminará todos los departamentos que no están
en uso. Se usa la cláusula adicional WHERE en la subconsulta para garantizar que la subconsulta no
devuelva valores NULL. Si no existiera esta cláusula, no se eliminaría ningún registro. Se tiene en cuenta
que no se puede utilizar una subconsulta en la cláusula VALUES de una expresión insertada; esto está
bien:
FROM dual;
Las subconsultas de registros únicos y múltiples se pueden utilizar en las cláusulas WHERE y HAVING de
la consulta principal, pero hay restricciones a la hora de usarlos con operadores de comparación. Si el
operador de comparación es cualquiera de la siguiente tabla, la subconsulta tiene que ser una subconsulta
de registro único:
242/306
SQL
Símbolo Significado
= Igual
<> Diferente
!= Diferente
Si cualquiera de los operadores de la tabla anterior se encuentra en una subconsulta que devuelve más
de un registro, la consulta fallará. Los operadores de la siguiente tabla se usan en subconsultas de
registros múltiples :
Símbolo Significado
243/306
SQL
subconsulta antes de evaluar la consulta padre. En esta consulta, se muestra todos los empleados cuyo
salario es inferior al salario medio:
SELECT last_name
FROM employees
WHERE salary <
(SELECT avg(salary)
FROM employees);
La subconsulta de registro único necesita ser ejecutada una única vez y su resultado se sustituirá en la
consulta principal. Sin embargo, ahora se considera una consulta que muestre a todos los empleados
cuyo salario es inferior a la media de su departamento. En ese caso, la subconsulta tendrá que ejecutarse
para cada empleado para determinar la media del salario para su departamento; la subconsulta necesita
el código del departamento del empleado. Esto se puede hacer de la siguiente forma:
Problema Solución
244/306
SQL
¿Cómo se puede diseñar mejor las Hay dos técnicas comunes: usar una
subconsultas para que no fallen con los agregación por si se obtienen varios
errores “ORA-01427: single-row registros que se reduzca el número a
subquery returns more than one row”? uno, o usar uno de los operadores IN,
ANY, o ALL para que no importe si se
devuelven varios registros. Pero la
solución ideal es utilizar siempre la clave
primaria al identificar el registro a
devolver, no una clave no única.
SELECT last_name
FROM employees
WHERE manager_id IN
(SELECT employee_id
FROM employees
WHERE department_id IN
(SELECT department_id
FROM departments
WHERE location_id IN
(SELECT location_id
FROM locations
WHERE country_id='UK')));
245/306
SQL
En el ejemplo anterior, las subconsultas están agrupadas en tres niveles de profundidad. Observe que
las subconsultas utilizan el operador IN porque es posible que las consultas puedan devolver varios
registros.
Se pide que se busque el trabajo con el salario promedio más alto. Esto se puede hacer con una
subconsulta de un solo registro:
SELECT job_title
FROM jobs
NATURAL JOIN employees
GROUP BY job_title
HAVING avg(salary) =
(SELECT max(avg(salary))
FROM employees
GROUP BY job_id);
La subconsulta devuelve un único valor: el salario medio del departamento con el salario medio más alto.
Es seguro utilizar el operador de igualdad para esta subconsulta porque la función MAX garantiza que
sólo se devuelva un registro. Los operadores ANY y ALL son compatibles con la sintaxis, pero su función
puede duplicarse con la de otros operadores más utilizados combinados con agregaciones.
Por ejemplo, en las siguientes dos sentencias, que recuperan todos los empleados cuyo sueldo es superior
al de cualquier empleado del departamento 80, se obtienen conjuntos de resultados idénticos:
SELECT last_name
FROM employees
WHERE salary > ALL
(SELECT salary
FROM employees
WHERE department_id=80);
SELECT last_name
FROM employees
WHERE salary > (SELECT max(salary)
FROM employees
WHERE department_id=80);
Operador Función
246/306
SQL
= ANY Equivalente a IN
8.5. Resumen
Definición de subconsulta
• La selección de registros de una tabla con una condición que depende de los datos de otra tabla
puede implementarse mediante una subconsulta.
• Los JOINs complejos pueden simplificarse al utilizar subconsultas.
• Las subconsultas pueden añadir valores a la salida de la consulta que las anida, que no están
disponibles desde sus tablas.
• Las subconsultas de registro múltiple pueden devolver varios registros, posiblemente con varias
columnas.
• Las subconsultas de resultado único devuelven un único registro, posiblemente con varias
columnas.
• Una consulta escalar devuelve un único registro; es una subconsulta de registro y columna
únicos.
• Una subconsulta correlacionada es ejecutada una vez por cada registro de la consulta que la
anida.
• Las subconsultas se pueden usar para generar valores en la lista de selección de una consulta y
generar una vista en línea que se puede introducir en las cláusulas FROM, WHERE y HAVING.
• Las subconsultas de registro único, cuando se usan en las cláusulas WHERE o HAVING, deben
ser usadas con operadores de comparación: =, >, >=, <, <=, <>.
• Las subconsultas de registros múltiples pueden usarse con estos operadores de comparación:
IN, NOT IN, ANY, ALL.
• Además, los operadores ALL y ANY pueden ser alternativas al uso de agregaciones.
247/306
SQL
Los operadores de conjunto utilizados en las consultas compuestas son los siguientes:
• La unión de los tres grupos son humanos, loros, murciélagos, abejas y osos. Son todos los
elementos de todos los grupos, sin repeticiones.
• La intersección de los conjuntos consta de todos los elementos que son comunes a los tres
conjuntos, una vez más eliminando las repeticiones. En este sencillo ejemplo, la intersección sólo
tiene un elemento: los murciélagos. La intersección del conjunto de dos patas y el conjunto
volador tiene dos elementos: loros y murciélagos.
• El menor de los conjuntos se define como los elementos de un conjunto sin los elementos de
otro, así que el conjunto de seres vivos de dos patas, menos el conjunto de seres vivos voladores,
menos el conjunto de seres vivos peludos, consta de un solo elemento: los humanos.
Estos conjuntos pueden representarse gráficamente como el diagrama de Venn mostrado en la figura de
abajo. (Los diagramas de Venn llevan el nombre de John Venn, quien formalizó la teoría en la Universidad
de Cambridge en el siglo XIX).
248/306
SQL
El círculo de la parte superior izquierda de la figura representa el conjunto de seres vivos de dos patas;
el círculo superior derecho corresponde a seres vivos que pueden volar; el círculo inferior a animales
peludos. Las uniones, intersecciones, y menor de los conjuntos aparecen inmediatamente al dibujar los
círculos y se corresponden con las regiones superpuestas o no de los círculos. El diagrama de la figura
también incluye el conjunto universal, representado por el rectángulo. El conjunto universal son todos
los elementos que existen, incluyendo aquellos que no son miembros de los conjuntos definidos. En este
caso, el conjunto universal se definiría como todos los seres vivos, incluyendo aquellos que no
desarrollaron piel, dos patas, o la capacidad de volar (como los peces). Después de ver este ejemplo del
concepto matemático de conjuntos se procederá a la implementación en SQL.
Debido al cambio en la prioridad del operador, puede ser una buena práctica utilizar siempre
paréntesis. Esto asegurará que la función del código no cambiará cuando se ejecute con una
versión posterior de la base de datos.
Cada consulta en una consulta compuesta proporcionará su propia lista de columnas seleccionadas. Estas
listas deben tener el mismo número de elementos, estar nominadas en la misma secuencia y tener los
mismos tipos de datos. No deben tener los mismos nombres (o alias de columna), ni deben provenir de
249/306
SQL
las mismas tablas (o subconsultas). Si los nombres de columna (o alias) son diferentes, el conjunto de
resultados de la consulta compuesta tendrá columnas con el mismo nombre que en la primera consulta.
Aunque las listas de columnas seleccionadas no tienen que ser exactamente del mismo tipo de datos,
deben pertenecer al mismo grupo de tipos de datos. Por ejemplo, las columnas seleccionadas por una
consulta podrían ser de tipo NUMBER y DATE y las de la segunda consulta podrían ser INTEGER y
TIMESTAMP. El conjunto de resultados de la consulta compuesta tendrá columnas con el mayor nivel de
precisión: en este caso, serían TIMESTAMP y NUMBER. Además de aceptar tipos de datos del mismo
grupo, los operadores de conjunto no realizarán ningún tipo de conversión implícita. Si la segunda
consulta recuperara columnas del tipo VARCHAR2, la consulta compuesta lanzaría un error incluso si las
variables string pudieran resolverse con valores numéricos y de fecha legítimos.
Las columnas de las consultas que componen una consulta compuesta pueden tener diferentes
nombres, pero el conjunto de resultados de salida utilizará los nombres de las columnas de la
primera consulta.
Las columnas del resultado de una consulta compuesta deben ser del mismo grupo de tipos
de datos que las columnas de la primera consulta.
UNION, MINUS e INTERSECT siempre combinarán los conjuntos de resultados de las consultas de entrada
y luego ordenarán los resultados para eliminar los registros duplicados. La clasificación se basa en todas
las columnas, de izquierda a derecha. Si todas las columnas de dos registros tienen el mismo valor, sólo
se devuelve el primer registro en el conjunto de resultados compuesto. Un efecto secundario de esto es
que la salida de una consulta compuesta será ordenada. Si el sentido de ordenación (que es ascendente,
basado en el orden en el que las columnas aparecen en las listas de selección) no es el orden deseado,
es posible poner una única cláusula ORDER BY al final de la consulta compuesta. No es posible utilizar
ORDER BY en ninguna de las consultas que componen toda la consulta compuesta, ya que esto
interrumpiría la clasificación necesaria para eliminar duplicados.
Una consulta compuesta devolverá por defecto los registros ordenados a través de todas las
columnas, de izquierda a derecha. La única excepción es UNION ALL, donde los registros no
serán ordenados. El único lugar donde se permite una cláusula de ORDER BY es al final de la
consulta compuesta.
UNION ALL es la excepción a la regla de ordenación sin duplicados ya que los conjuntos de resultados de
las dos consultas de entrada se concatenan para formar el resultado de la consulta compuesta. En este
caso tampoco se puede utilizar ORDER BY en las consultas individuales; sólo puede aparecer al final de
la consulta compuesta donde se aplicará al conjunto de resultados completo.
9.2. Utilizar un operador de conjunto para combinar múltiples consultas en una única
consulta
Las consultas compuestas son de dos o más consultas, enlazadas por uno o más operadores conjunto.
El resultado final será un único conjunto de registros.
Los siguientes ejemplos estarán basados en dos tablas, OLD_DEPT y NEW_DEPT. La tabla OLD_DEPT
tiene por objetivo representar una tabla creada con una versión anterior de Oracle, cuando el único tipo
de dato para representar un dato de fecha y hora era DATE, la única opción para un dato de tipo numérico
era NUMBER y para el dato carácter era CHAR (de tamaño fijo). La tabla NEW_DEPT usa el tipo de dato
250/306
SQL
numérico, mejor definido, INTEGER (que Oracle implementa como un NUMBER de hasta 38 dígitos
significantes, pero sin decimales), el tipo de dato de caracteres más eficiente (en cuanto a espacio)
VARCHAR2 y el tipo de dato TIMESTAMP, que puede guardar fechas y horas con seis decimales de
precisión en los segundos por defecto. Hay dos registros en cada tabla.
251/306
SQL
Debido a la ordenación, el orden de las consultas en una consulta compuesta UNION, no habrá diferencia
en el orden en el que los registros son devueltos.
252/306
SQL
Si no pueden haber duplicados entre dos tablas, entonces se usará siempre UNION ALL. La
base de datos ahorrará mucho tiempo de filtrado.
La primera consulta que se muestra, no obtiene ningún resultado ya que todos los registros en las dos
tablas son diferentes. En la siguiente consulta, aplicamos funciones para eliminar algunas de las
diferencias y obtenemos un registro común. En este caso, solo un registro es devuelto; si hubiese varios
registros, estarían en orden. El orden en que las consultas aparecen en la combinación no afecta al orden
de los resultados.
253/306
SQL
254/306
SQL
SELECT name
FROM permstaff
WHERE location = 'Germany'
UNION ALL
SELECT name
FROM consultants
WHERE work_area = 'Western Europe'
MINUS
SELECT name
FROM blacklist;
Se usa UNION ALL porque se asume que nadie estará en la tabla CONSULTANTS y PERMSTAFF; un UNION
forzaría a una ordenación innecesaria. El orden de precedencia para los operadores de colecciones es
especificado por el programador, así que el operador MINUS comparará los registros de BLACKLIST con
el resultado de UNION ALL. El resultado será todo el personal (permanente y asesores) que no aparecen
en la BLACKLIST. Si el listado de expulsados pudiera ser aplicado solo al personal de asesores y no al
personal permanente habría dos posibilidades. La primera, las sentencias podrían ser listadas en orden
diferente:
SELECT name
FROM consultants
WHERE work_area = 'Western Europe'
MINUS
SELECT name
FROM blacklist
UNION ALL
SELECT name
FROM permstaff
WHERE location = 'Germany';
255/306
SQL
Esto devolvería los asesores que no están expulsados y juntaría al personal permanente. Otra opción,
los paréntesis podrían controlar la precedencia explícitamente:
SELECT name
FROM permstaff
WHERE location = 'Germany'
UNION ALL
(SELECT name
FROM consultants
WHERE work_area = 'Western Europe'
MINUS
SELECT name
FROM blacklist);
Esta consulta mostrará a todo el personal permanente y juntaría a todos los asesores que no están
expulsados.
Estas dos consultas devolverán los mismos registros, pero el orden será diferente debido a que las
operaciones UNION ALL muestran las tablas PERMSTAFF y CONSULTANTS en un orden diferente. Para
asegurar que ambos resultados de las consultas sean iguales, necesitaríamos una cláusula ORDER BY en
la última línea.
Las dos consultas anteriores devolverán los mismos registros, pero la segunda versión podría
considerarse mejor ya que es más clara por el uso de paréntesis. Por otra parte, confiar en la
precedencia implícita basándose en el orden de las consultas funciona por ahora, pero en
futuras versiones de SQL podrían incluir otras precedencias.
Problema Solución
256/306
SQL
¿Hay algún problema de rendimiento con Puede haberlo. Con la excepción de las
las consultas combinadas? consultas combinadas con UNION ALL,
las consultas combinadas tienen que
ordenar los resultados por todas sus
columnas. Esto puede ser costoso a nivel
de memoria y CPU. Así mismo, si dos
consultas apuntan a la misma tabla, se
recorrerá dos veces cada registro ya que
cada consulta se ejecuta de manera
independiente; si se pudiese obtener el
mismo resultado con una consulta
(posiblemente aumentaría la
complejidad), sería normalmente una
solución más rápida. Las consultas
combinadas deben ser una herramienta.
No es posible utilizar sintácticamente una cláusula ORDER BY en las consultas individuales que componen
una consulta compuesta. Esto se debe a que la ejecución de la mayoría de las consultas compuestas
tiene que ordenar los registros, lo que entraría en conflicto con el comando ORDER BY. Teóricamente,
podría ser posible que un UNION ALL (que no ordena los registros) pudiera tomar un ORDER BY para
cada consulta, pero la implementación Oracle de UNION ALL no lo permite.
Sin embargo, no hay ningún problema en colocar una cláusula ORDER BY al final de la consulta
compuesta. Esto ordenará toda la salida de la consulta compuesta. La clasificación por defecto de los
registros se basa en todas las columnas de la secuencia en la que aparecen. Una cláusula ORDER BY
especificada no tiene restricciones: puede basarse en cualquier columna (y funciones aplicadas a las
columnas) en cualquier orden. Por ejemplo:
DEPTNO NAME
10 Accounts
30 Admin
20 Support
257/306
SQL
Los nombres (o alias) de columna en la cláusula ORDER BY deben ser el nombre o el alias de las columnas
en la primera consulta de la consulta compuesta.
9.4. Resumen
Definición de los operadores Conjunto
Uso de un operador Conjunto para combinar varias consultas en una única consulta
• Las consultas en la consulta combinada tienen que devolver el mismo número de columnas.
• Las columnas correspondientes tienen que ser de tipos de datos compatibles.
• Los operadores conjunto tienen la misma precedencia y serán aplicados en el orden que están
especificados.
• No es posible usar ORDER BY en una de las consultas que están en una consulta compuesta.
• Una cláusula ORDER BY puede ser usada al final de una consulta compuesta.
• Los registros devueltos por UNION ALL estarán en el orden en el que aparecen en las dos
consultas.
• Los registros devueltos por UNION estarán ordenados por las columnas de izquierda a derecha.
• SELECT INSERT
• UPDATE
• DELETE
• MERGE
258/306
SQL
En la práctica, la mayoría de los profesionales de bases de datos nunca incluyen SELECT como parte del
DML. Se considera un lenguaje separado por derecho propio, lo que no carece de sentido si se tiene en
cuenta que se han necesitado los ocho capítulos anteriores para describirla.
El comando MERGE también suele ser omitido, no porque no sea claramente un comando de manipulación
de datos, sino porque no hace nada que no se pueda hacer con otros comandos. MERGE puede ser visto
como un atajo para ejecutar un INSERT, un UPDATE o un DELETE dependiendo de alguna condición.
Un comando que a menudo se considera parte de DML es TRUNCATE. Esto es en realidad un DDL (Data
Definition Language o lenguaje de definición de datos), pero como el resultado para los usuarios finales
es el mismo que el del comando DELETE (aunque su implementación es totalmente diferente), encaja
con el DML.
Así pues, los siguientes comandos se describen en las siguientes secciones, con su sintaxis y ejemplos:
• INSERT
• UPDATE
• DELETE
• TRUNCATE
Además, veremos, para completar:
• MERGE
Estos son los comandos que manipulan los datos.
10.1.1. INSERT
Oracle almacena los datos en forma de registros en tablas. Las tablas se rellenan con registros de varias
maneras, pero el método más común es con la sentencia INSERT. SQL es un lenguaje orientado a
conjuntos, por lo que un comando puede afectar a un registro o a un conjunto de registros. De ello se
deduce que una sentencia INSERT puede insertar uno o más registros en una o más tablas. Las versiones
básicas de la sentencia insertan sólo un registro, pero variaciones más complejas pueden, con un
comando, insertar múltiples registros en múltiples tablas.
Existen técnicas mucho más rápidas que INSERT para rellenar una tabla con un gran número
de registros. Se trata de la utilidad SQL*Loader, que puede cargar datos de archivos
producidos por un sistema externo, y Data Pump, que puede transferir datos en masa de una
base de datos Oracle a otra, ya sea a través de archivos de disco o a través de un enlace de
red.
Las tablas tienen reglas definidas que controlan los registros que se pueden insertar. Estas reglas son
restricciones. Una restricción es la implementación de una regla de negocio. Los analistas que modelan
los procesos de negocio de una organización diseñarán un conjunto de reglas para los datos de la
organización. Ejemplos de tales reglas podrían ser que cada empleado debe tener un número de
empleado único o que cada empleado debe estar asociado a un departamento válido. La creación de
restricciones se describe en el Capítulo 11; por ahora, hay que recordar que no hay forma de que un
comando INSERT pueda insertar un registro que infrinja una restricción. Así que si se intenta insertar
una línea en EMPLOYEES con un EMPLOYEE_ID que ya existe en otro registro, o con un DEPARTMENT_ID
que no coincide con un registro de la tabla DEPARTMENTS, la inserción fallará. Las restricciones
259/306
SQL
garantizan que los datos de la base de datos se ajustan a las normas que definen los procedimientos
empresariales.
Existen diferentes formas de insertar datos en la base de datos usando la sentencia INSERT. Se puede
insertar un solo registro proporcionando los valores para las columnas del registro individualmente. Dicha
declaración puede construirse escribiéndola en SQL*Plus o SQL Developer, o mediante un proceso de
usuario más sofisticado que presente un formulario que solicite los valores a insertar. Esta es la técnica
utilizada para que el usuario introduzca datos manualmente en una base de datos, por ejemplo.
Para inserciones de varios registros, la fuente de los datos puede ser una instrucción SELECT. La salida
de todas y cada una de las sentencias SELECT vistas en los ocho capítulos anteriores puede utilizarse
como entrada a una sentencia INSERT.
El resultado final de cualquier sentencia SELECT puede considerarse como una tabla: un conjunto
bidimensional de registros. Esta "tabla" puede mostrarse a un usuario (quizás en una herramienta simple
como SQL*Plus), o puede pasarse a un comando INSERT para rellenar otra tabla, definida dentro de la
base de datos. Usar una instrucción SELECT para construir registros para una instrucción INSERT es una
técnica muy común. El SELECT puede realizar muchas tareas. Estas, típicamente, incluyen la unión de
tablas y agregaciones, de modo que los registros resultantes insertados en la tabla de destino contienen
información que es mucho más comprensible para los usuarios finales que los datos sin procesar en las
tablas de origen.
10.1.2. UPDATE
El comando UPDATE se utiliza para modificar registros que ya existen - registros que han sido creados
por un comando INSERT, o posiblemente por una herramienta como Data Pump. Al igual que con
cualquier otro comando SQL, un UPDATE puede afectar a un registro o a un conjunto de registros. El
tamaño del conjunto afectado por un UPDATE se determina por una cláusula WHERE, de la misma manera
que el conjunto de registros recuperados por una instrucción SELECT se define por una cláusula WHERE.
La sintaxis es idéntica.
Todos los registros actualizados estarán en una tabla; no es posible que un único comando UPDATE afecte
a los registros de varias tablas. Cuando se actualiza un registro o un conjunto de registros, el comando
UPDATE especifica qué columnas del registro(s) se deben actualizar. No es necesario actualizar cada
columna de un registro. Si la columna que se está actualizando ya tiene un valor, este valor se sustituye
por el nuevo valor especificado por el comando UPDATE. Si la columna no estaba previamente rellenada
-es decir, su valor era NULL- entonces se rellenará después del UPDATE con el nuevo valor.
Un uso típico de UPDATE es recuperar un registro y actualizar una o más columnas del registro. La
recuperación se hará usando una cláusula WHERE que selecciona un registro por su clave primaria, el
identificador único que permitirá asegúrese de que sólo se recupera un registro. Luego las columnas que
se actualicen serán cualquier columna que no sea la columna principal. Es muy inusual cambiar el valor
de la clave primaria.
La vida útil de un registro comienza cuando se inserta, luego puede continuar a través de varias
actualizaciones, hasta que se borra. A lo largo de esta vida, no se podrá normalmente cambiar su clave
primaria.
Para actualizar un conjunto de registros, se utiliza una cláusula WHERE menos restrictiva que la clave
primaria. Para actualizar todos los registros de una tabla, no se utiliza ninguna cláusula WHERE.
Si se seleccionan los registros que se actualizarán por cualquier columna que no sea la clave primaria,
se pueden actualizar varios registros, no sólo uno. Si se omite la cláusula WHERE por completo, se
actualizará toda la tabla -quizás miles de millones de registros actualizados con una sola sentencia-
cuando se quería cambiar sólo uno.
260/306
SQL
El comando UPDATE debe respetar cualquier restricción definida para la tabla, tal y como lo haría el
INSERT original. Por ejemplo, no será posible actualizar una columna que ha sido marcada como
obligatoria a un valor NULL o actualizar una columna clave primaria para que ya no sea única.
10.1.3. DELETE
Los registros previamente insertados se pueden eliminar de una tabla con el comando DELETE. El
comando eliminará un registro o un conjunto de registros de la tabla, dependiendo de la cláusula WHERE.
Si no hay cláusula WHERE, se eliminarán todos los registros de la tabla (lo que puede ser un problema
si se omite la cláusula WHERE por error).
No hay avisos de "advertencia" para ningún comando SQL. Si le indica a la base de datos que
borre un millón de registros, lo hará. Inmediatamente. No hay nada similar a ventanas
emergentes con mensajes del tipo "¿Estás seguro?" que algunos entornos ofrecen.
No es posible especificar en el comando DELETE qué columnas serán borradas, siempre se borrarán
registros completos. Cuando se insertan registros, se puede elegir qué columnas rellenar. Cuando se
actualizan los registros, se puede seleccionar las columnas que se desea actualizar. Un borrado no
obstante se aplica a todo el registro: la única opción es seleccionar qué registros de qué tabla. Esto hace
que el comando DELETE sea sintácticamente más simple que los otros comandos DML.
10.1.4. MERGE
En versiones anteriores de SQL no existía un comando MERGE. Se introdujo MERGE con el estándar
SQL1999, implementado por Oracle en la versión 9i de la base de datos. La versión 10g (conforme al
estándar SQL2003) proporciona algunas mejoras. Algunas implementaciones de SQL tenían un comando
llamado UPSERT. Esta palabra describe el comando MERGE bastante bien: ejecuta un UPDATE o un
INSERT, dependiendo de alguna condición. El término UPSERT no obstante está actualmente obsoleto,
porque la versión actual de MERGE puede, según las circunstancias, hacer también un DELETE.
Hay muchas ocasiones en las que se desea tomar un conjunto de datos e integrarlo en una tabla
existente. Si ya existe un registro de la nueva tabla origen en la tabla destino, es posible que se desee
actualizar el registro de destino o que desee reemplazarlo completamente, o tal vez se desee dejar el
registro de destino sin cambios. Si un registro en la tabla origen no existe en el destino, es posible que
se desee insertarlo. El comando MERGE permite hacer esto. Un MERGE pasa por los datos de origen, por
cada registro intenta localizar un registro idéntico en la tabla destino. Si no se encuentra ninguna
coincidencia, se puede insertar el registro; si se encuentra una coincidencia, se puede actualizar el
registro correspondiente. El resultado final es una tabla destino en la que se han fusionado los datos de
la tabla de origen.
Una operación MERGE no hace nada que no se pueda hacer con sentencias INSERT, UPDATE y DELETE,
pero con un solo paso a través de los datos de origen, se pueden hacer las tres cosas. Un código
alternativo sin MERGE requeriría tres pasadas a través de los datos, uno por cada comando.
261/306
SQL
MERGE puede ser de vital importancia para codificar aplicaciones que funcionan bien y utilizan
la base de datos eficientemente.
Los datos de origen para una sentencia MERGE pueden ser una tabla o cualquier subconsulta. La condición
utilizada para encontrar registros coincidentes en la tabla de destino es similar a una cláusula WHERE.
Las cláusulas que actualizan o insertan registros son tan complejas como un comando UPDATE o INSERT.
De ello se deduce que MERGE es el más complicado de los comandos DML, lo que no es irrazonable, ya
que es (podría decirse) el más potente.
10.1.5. TRUNCATE
El comando TRUNCATE no es un comando DML, sino DDL. Existe una gran diferencia entre cambos.
Cuando los comandos DML interactúan con los datos, estos insertan, actualizan y eliminan registros de
la base de datos como parte de transacciones. Las transacciones se definen más adelante en este capítulo
en el apartado "Controlar transacciones". Por ahora, se podría decir que una transacción puede ser
controlada por el usuario, en el sentido de que este tiene la opción de hacer que los cambios realizados
en una transacción sean permanentes o se puedan revertir. Esto es muy útil, pero obliga a la base de
datos a realizar un trabajo adicional entre bastidores que el usuario no conoce. Los comandos DDL no
son transacciones que el usuario pueda controlar, por lo que aunque dentro de la base de datos sí que
se implementan como transacciones, el desarrollador no puede hacer los cambios permanentes o
revertirlos. Los comandos DDL son por lo tanto mucho más rápidos que los comandos DML.
Desde el punto de vista del usuario, un truncamiento de una tabla equivale a ejecutar un DELETE para
cada uno de sus registros; es decir, como si fuese un comando DELETE sin cláusula WHERE. Mientras
que un borrado DELETE puede llevar algún tiempo (posiblemente horas, si hay muchos registros en la
tabla) un truncamiento pasará instantáneamente. No importa si la tabla contiene un registro o miles de
millones; un TRUNCATE será virtualmente instantáneo. La tabla seguirá existiendo, pero estará vacía.
Los comandos DDL, como TRUNCATE, fallarán si hay algún comando DML activo en la tabla.
Una transacción bloqueará el comando DDL hasta que el DML termine con un COMMIT o un
ROLLBACK.
• Errores de sintaxis
• Referencias a objetos o columnas inexistentes
• Permisos de acceso
• Violaciones de restricciones de la base de datos
• Cuestiones de espacio
Un comando SQL puede afectar a un conjunto de registros, así pues, existe la complicación de que un
comando pueda tener éxito parcialmente, actuando solo sobre parte de los registros que debiera.
Uno de los propósitos de esta sección es prevenir errores de sintaxis. Cuando ocurren (y es algo bastante
habitual), deben ser detectados por la herramienta que está construyendo el SQL que será enviado a la
base de datos. Hay un número ilimitado de posibles errores de sintaxis, empezando por simples errores
ortográficos o de transposición de caracteres.
Los errores de naturaleza sintáctica no afectarán a la base de datos, porque esta nunca llegará a ejecutar
una sentencia que contenga errores de sintaxis. Será la herramienta que se utilice para trabajar con SQL
la que detecte los errores de sintaxis de las sentencias. Existen multitud de herramientas y programas,
262/306
SQL
263/306
SQL
El segundo intento de ejecutar la sentencia falla con un error que indica que el objeto no existe. Esto se
debe a que no existe en el esquema del usuario actual; existe en el esquema HR.
Una vez corregido esto, el tercer intento de ejecutar la sentencia encuentra otro problema. El valor
pasado en la cláusula WHERE es una cadena, '21-ABR-08', pero la columna HIRE_DATE no está definida
en la tabla como una cadena de texto, sino como una fecha. Para ejecutar la sentencia, la base de datos
tendría que averiguar lo que el usuario realmente quería decir e interpretar la cadena como una fecha.
En el último ejemplo, el casting falla. Esto se debe a que la cadena pasada está formateada como una
fecha de estilo europeo, pero la base de datos ha sido configurada para esperar un NLS_DATE_FORMAT
de DD-MON-RR (Dia-Mes-Año).
Los desarrolladores nunca deben confiar en el casting automático. Es una programación ineficiente.
Siempre se debe hacer cualquier tipo de casting explícito que sea necesario, usando las funciones
apropiadas como se vieron en los capítulos anteriores. Si el casting automático funciona, en el mejor de
264/306
SQL
los casos hay un incremento en el rendimiento de la BBDD ya que esta tiene que hacer trabajo extra.
En este ejemplo, si hay un índice en la columna HIRE_DATE, será un índice de fechas, por lo que no hay
manera de que la base de datos pueda usarla cuando se pasa una cadena de texto. En el peor de los
casos, el resultado será erróneo. Si la cadena de fechas pasada fuera '04/05/2007' esto funcionaría,
¿pero sería el 4 de mayo o el 5 de abril?
Oracle intentará corregir los desajustes de tipos de datos en las sentencias SQL (DML y
SELECT) mediante la creación automática de tipos de casting, pero los resultados pueden ser
impredecibles y no se considera una buena práctica que el programador delegue el hacer las
conversiones de un tipo de dato a otro.
Si una sentencia es sintácticamente correcta y no tiene errores respecto a los objetos a los que hace
referencia, todavía puede fallar debido a los permisos de acceso. Si el usuario que intenta ejecutar la
sentencia no tiene los permisos correspondientes en las tablas a las que hace referencia en la propia
sentencia, la base de datos devolverá un error idéntico al que se produciría si el objeto no existiera. en
lo que respecta a ese usuario concreto, de hecho, no existe.
Respecto a los errores que pueden provocar los permisos de acceso, estos pueden ser diferentes
dependiendo del usuario que esté trabajando con la base de datos. Es posible que un usuario tenga
permisos para realizar consultas a una tabla, pero no para insertar, actualizar o borrar registros. También
es posible que los permisos sean configurados de tal manera que sea posible insertar registros pero no
leerlos, o quizás sea posible borrar registros pero no leerlos y actualizarlos; sin embargo, no es lo común.
Por otra parte, en lo referente a las posibles violaciones de las restricciones, cabe destacar que una
restricción es una regla de negocio, implementada dentro de la base de datos. Una limitación típica es
que una tabla debe tener una clave primaria: un valor de una columna (o combinación de columnas) que
pueden identificar de forma unívoca cada registro. Un comando INSERT puede insertar varios registros
en una tabla, y para cada registro la base de datos comprobará si ya existe un registro en ella con la
misma clave primaria. Esto ocurre a medida que se inserta cada registro. Podría ser que los primeros
registros (o los primeros millones de registros) se inserten sin ningún problema, y luego se encuentre
un registro con un valor de clave primaria duplicado. En este punto se devolverá un error, y la sentencia
fallará. Este fallo provocará que todos los cambios hechos hasta ahora se deshagan, incluso los que ya
habían sido realizados. Esto es parte del estándar SQL: todos los cambios que implica una sentencia
deben llevarse a cabo en su totalidad, o no habrá cambio alguno. La inversión de los cambios se denomina
rollback (implica deshacer todos los cambios provocados por la sentencia que se han realizado hasta el
momento). Los mecanismos de un rollback se describen en la sección de este capítulo titulada "Control
de transacciones".
Si una sentencia falla debido a problemas de espacio en memoria, el efecto es similar. Una parte de la
sentencia puede haber tenido éxito antes de que la base de datos se quedara sin espacio. Los cambios
provocados hasta el momento serán automáticamente deshechos. El hecho de deshacer los cambios
(rollback) de una sentencia es un concepto clave en SQL. Obliga a la base de datos a hacer trabajo extra
y por lo general tomará al menos tanto tiempo como la sentencia en sí ya haya tomado (o a veces incluso
bastante más tiempo).
265/306
SQL
Por ejemplo:
La primera de las sentencias anteriores proporciona valores para ambas columnas de la tabla REGIONS.
Si la tabla tuviera una tercera columna, la sentencia fallaría porque el comando INSERT inserta datos
basándose en notación posicional; es decir, la sentencia no indica qué valor debe insertarse en cada
columna, sino que se basa en la posición de los valores, en el orden de los valores en el comando. Cuando
la base de datos recibe una sentencia utilizando notación posicional, hará coincidir el orden de los valores
con el orden en el que se definen las columnas de la tabla. La sentencia también fallaría si el orden de
las columnas fuera incorrecto: la base de datos intentaría la inserción, pero fallaría debido a desajustes
en el tipo de datos.
En la segunda sentencia se definen explícitamente las columnas que se van a rellenar y los valores con
los cuales se rellenarán. Ahora el orden en el que se mencionan las columnas pasa a ser irrelevante,
siempre y cuando dicho orden se corresponda al orden de los valores a insertar.
En el tercer ejemplo se desean insertar datos en una sola columna y, por lo tanto, se insertará un solo
valor. El resto de columnas adquirirán por defecto valores nulos (NULL). Esta sentencia fallaría si la
columna REGION_NAME no aceptara valores nulos.
El cuarto ejemplo producirá el mismo resultado, pero debido a que no hay una lista de columnas explícitas
a insertar, se debe proporcionar un valor de algún tipo para cada columna; como mínimo, un valor NULL.
Muy a menudo, una sentencia INSERT incluirá funciones de casting (convertir una expresión de un tipo
de datos a otro). Véase la sentencia:
266/306
SQL
upper('Watson'), to_date('03-Nov-
13','dd-mon-yy'),
lower('JWatson@[Link]'),
upper('sa_rep'));
Los registros insertados con cada sentencia serían idénticos. La primera inserta exactamente las cadenas
de caracteres facilitadas.
Es muy posible que la aplicación haga uso de los apellidos de los empleados en mayúsculas, por ejemplo.
Esto podría suponer un grave problema a la hora de realizar búsquedas, ya que si también hay apellidos
que alternen mayúsculas y minúsculas, se pueden obtener resultados no deseados o incorrectos.
Además, la inserción del valor de fecha se basa en el casting automático de una cadena de caracteres a
una fecha, lo que implica un cierto coste computacional, además de que se podrían obtener valores
incorrectos.
En esta sentencia, la columna EMPLOYEE_ID se rellena con el resultado de una operación aritmética, la
columna LAST_NAME se rellena con el resultado de la función USER (que devuelve el nombre del usuario
que está accediendo a la base de datos), y la columna HIRE_DATE se rellena con el resultado de una
función y una operación aritmética: la fecha correspondiente a siete días antes de la fecha actual del
sistema.
La imagen siguiente muestra la ejecución de las tres consultas anteriores, seguidas por los resultados.
267/306
SQL
Usando funciones para pre-procesar los valores antes de insertarlos en los registros puede ser
particularmente importante cuando se ejecutan scripts con variables de sustitución, ya que se podrán
corregir valores no deseados en la entrada de datos, lo cual ocurre frecuentemente cuando el usuario los
introduce interactivamente.
Para insertar muchos registros con una sola sentencia INSERT, los valores a insertar deberán ser los
valores obtenidos como resultado de una subconsulta (subquery) SQL. La sintaxis sería la siguiente:
268/306
SQL
Hay que tener en cuenta que esta sintaxis no usa la palabra clave VALUES. Al igual que en los ejemplos
anteriores, si se omite la lista de columnas, la subconsulta debe proporcionar valores para cada columna
que exista en la tabla.
Supóngase que se quisiesen copiar todos los registros de una tabla a otra tabla, ambas con la misma
estructura de columnas. Podría utilizarse el siguiente comando:
Se asume que la tabla REGIONS_COPY ya existe (con o sin registros). La subconsulta (subquery) SELECT
lee cada registro de la tabla fuente, la cual es REGIONS, e inserta a través del comando INSERT este
conjunto de resultados en la tabla destino REGIONS_COPY.
Cualquier consulta devuelve una matriz bidimensional de registros; si la tabla destino (que también es
una matriz bidimensional) tiene columnas para recibirlas, la inserción funcionará.
Normalmente se pretende presentar los datos a los usuarios finales en una forma que les facilite la
extracción de información y que les impida malinterpretarla. Esto generalmente significa desnormalizar
las tablas relacionales, hacer agregaciones, renombrar columnas y ajustar los datos que pueden
distorsionar los resultados si no se procesan correctamente.
Seguidamente se verá un ejemplo en el esquema HR: supóngase la necesidad de informar sobre los
salarios en cada departamento. La consulta debe realizar un OUTER JOIN para asegurar que no se pierda
ningún empleado sin un departamento, y que todos los departamentos estén listados
independientemente de si tienen empleados o no. También se debe asegurar que no hay ningún valor
nulo que distorsione ninguna operación aritmética sustituyendo ceros o cadenas de texto por NULL.
Esta consulta es normalmente sencilla para cualquier programador SQL, pero cuando los usuarios finales
intentan ejecutar este tipo de consulta, es muy probable que produzcan resultados inexactos al omitir
las comprobaciones. Un proceso (job) de mantenimiento diario en un almacén de datos, que ensamblaría
los datos en una forma adecuada, podría ser un script como este:
La imagen siguiente muestra la ejecución de la sentencia INSERT anterior, seguida del resultado.
269/306
SQL
El comando TRUNCATE vaciará la tabla, la cual se rellenará de nuevo con los datos de la subconsulta.
Haciendo todo el trabajo complejo en la instrucción INSERT, los usuarios pueden entonces ejecutar
consultas mucho más simples en las tablas con datos desnormalizados y agregados.
Sus consultas también serán rápidas: ya se ha hecho todo el trabajo más pesado anteriormente.
270/306
SQL
Para concluir la descripción del comando INSERT, cabe mencionar que es posible insertar registros en
varias tablas con una sola sentencia, como se puede ver en el ejemplo siguiente:
INSERT ALL
WHEN 1=1 THEN
INTO emp_no_name(department_id,job_id,salary,commission_pct,hire_date)
VALUES (department_id,job_id,salary,commission_pct,hire_date)
WHEN department_id <> 80 THEN
INTO emp_non_sales(employee_id,department_id,salary,hire_date)
VALUES (employee_id,department_id,salary,hire_date)
WHEN department_id = 80 THEN
INTO emp_sales(employee_id,salary,commission_pct,hire_date)
VALUES (employee_id,salary,commission_pct,hire_date)
SELECT employee_id,department_id,job_id,salary,commission_pct,hire_date
FROM [Link]
WHERE hire_date > sysdate - 30;
Para leer esta consulta, hay que comenzar por abajo. La subconsulta recupera todos los empleados
contratados en los últimos 30 días. Ahora, se irá leyendo el resto de la sentencia desde arriba.
La palabra clave ALL implica que cada registro obtenido en la subconsulta será considerado para ser
insertado en todas las tablas siguientes, no sólo en la primera tabla para que se cumpla una condición.
La primera condición es 1=1, lo cual es siempre verdadero, entonces cada registro fuente creará un
registro en EMP_NO_NAME. Eso es una copia de la tabla EMPLOYEES con el identificador del personal
borrado, un requisito común en un almacén (warehouse) de datos. La segunda condición es
DEPARTMENT_ID<>80, la cual crea un registro en EMP_NON_SALES para cada empleado que no está
en el departamento de ventas. La tercera condición genera una línea en EMP_SALES para todos los
vendedores; no hay necesidad de la columna DEPARTMENT_ID, porque todos estarán en el departamento
80.
Este es un ejemplo sencillo de una inserción en varias tablas, por lo que se puede ver que, con una sola
sentencia, y por lo tanto un solo paso a través de los datos de origen, es posible poblar muchas tablas
destino, lo cual es eficiente.
271/306
SQL
272/306
SQL
La forma más compleja del comando es utilizar subconsultas para uno o más de los valores de la columna
y para la condición WHERE. La siguiente imagen permite visualizar diversos usos del comando UPDATE,
desde ejemplos simples a más complicados, ejecutados desde SQL*Plus.
El primer ejemplo es el más simple. Se fija el valor de la columna SALARY a 10000 para los empleados
con id=206.
Debido a que el registro a modificar se selecciona con una cláusula WHERE que utiliza la condición de
igualdad con la clave primaria de la tabla, hay una garantía absoluta de que a lo sumo sólo un registro
será afectado. No se cambiará ningún registro si la cláusula WHERE no encuentra ninguna coincidencia.
El segundo ejemplo muestra el uso de operaciones aritméticas aplicadas sobre una columna ya existente
para fijar el nuevo valor de esta. Esta vez los registros a modificar no se seleccionan por su clave primaria,
273/306
SQL
lo cual implica que posiblemente los registros a actualizar sean más de uno. Esto también ocurrirá si se
usan comandos como BETWEEN.
En caso de que la cláusula WHERE se omita por completo, la actualización se aplicará a cada registro de
la tabla.
El tercer ejemplo en la figura anterior introduce el uso de una subconsulta para definir el conjunto de
registros a actualizar. Una complicación adicional es el uso de una variable de sustitución para solicitar
al usuario el valor a utilizar en la cláusula WHERE de la subconsulta.
En este ejemplo, la subconsulta (líneas 4, 5 y 6) seleccionará a cada empleado que esté en un
departamento cuyo nombre incluya la cadena de caracteres 'IT' e incrementará su salario actual en un
diez por ciento.
También es posible utilizar subconsultas para determinar el valor de una columna, como en el cuarto
ejemplo. En este caso, un empleado (identificado por la clave primaria, en la línea 7) se transfiere al
departamento 80 (el departamento de ventas) y a continuación la subconsulta en las líneas 4, 5 y 6
establece su tasa de comisión a la más baja del departamento.
UPDATE table
SET column=[subquery][,column=subquery...]
[AND column=subquery...];
Existe una restricción en las subconsultas que actualizan columnas en la cláusula SET: la subconsulta
debe devolver un valor escalar. Un valor escalar es un valor simple de cualquier tipo de datos; es decir,
la consulta debe devolver un registro asociado a una columna. Si la subconsulta devuelve varios valores,
el UPDATE fallará.
Considérense estos dos ejemplos:
UPDATE employees
SET salary=
(SELECT salary
FROM employees
WHERE employee_id=206);
UPDATE employees
SET salary=
(SELECT salary
FROM employees
WHERE last_name='Abel');
El primer ejemplo, usando la condición de igualdad con la clave primaria, siempre tendrá éxito. Incluso
si la subconsulta no recupera ningún registro (como sería el caso si no hubiera ningún empleado con
EMPLOYEE_ID igual a 206), la consulta todavía devolverá un valor escalar: un NULL. En ese caso, todos
los registros en EMPLOYEES tendrían su SALARY a NULL. Esto será probablemente un resultado no
deseado, pero no es un error en lo que respecta a SQL.
El segundo ejemplo utiliza una condición de igualdad en LAST_NAME, el cual no se garantiza que devuelva
un registro único. La declaración tendrá éxito si sólo hay un empleado con ese nombre, pero si hubiera
más
274/306
SQL
de uno se produciría el error “ORA-01427: single-row subquery returns more than one row.” Para que el
código funcione de forma fiable, sea cual sea el estado de los datos, es vital garantizar que las
subconsultas utilizadas para fijar valores de columna sean escalares.
Una solución comúnmente utilizada para asegurarse que las consultas son escalares es utilizar
MAX y MIN.
UPDATE employees
SET salary=
(SELECT max(salary)
FROM employees
WHERE last_name='Abel');
No obstante que se ejecute de forma correcta no asegura que realice aquello que se esperaba.
Las subconsultas de la cláusula WHERE serán escalares si se está utilizando en ella una condición de
igualdad (como en los ejemplos anteriores) o las condiciones de mayor/menor que. Si se está usando el
predicado IN, entonces la consulta puede devolver múltiples registros, como muestra el siguiente
ejemplo:
UPDATE employees
SET salary=10000
WHERE department_id IN
(SELECT department_id
FROM departments
WHERE department_name LIKE '%IT%');
Esto aplicará la actualización a todos los empleados de un departamento cuyo nombre incluya la cadena
"IT". Pero a pesar de que la consulta puede devolver varios registros, debe devolver únicamente una
columna.
Las subconsultas utilizadas para SET deben ser subconsultas escalares. Las subconsultas
utilizadas para seleccionar los registros también deben ser escalares, a menos que usen el
predicado IN.
DELETE es menos drástico, en el sentido de que un borrado puede deshacerse, mientras que si se ejecuta
un comando TRUCANTE no hay vuelta atrás. DELETE es más flexible, ya que es posible seleccionar qué
275/306
SQL
registros se desean borrar, mientras que el comando TRUNCATE siempre afecta a una tabla en su
totalidad. DELETE es sin embargo mucho más lento y puede suponer una gran carga computacional para
la base de datos. TRUNCATE por otro lado es virtualmente instantáneo y su carga computacional es
mucho menor.
DELETE FROM
[WHERE condition];
Este es el comando más simple del DML, si en el comando anterior se omitiera la condición, todos los
registros de la tabla serían eliminados sin ningún aviso. Para un correcto uso de este comando, es
necesario especificar bien la condición deseada para eliminar los registros correctos. Estas condiciones
pueden contener tanto enteros o cadenas de texto como expresiones SQL.
La condición final elimina a todos los empleados que actualmente no están asignados a un departamento.
La condición de la cláusula WHERE también puede ser una subconsulta:
FROM departments
WHERE location_id IN
(SELECT location_id
FROM locations
276/306
SQL
WHERE country_id IN
(SELECT country_id
FROM countries
WHERE region_id IN
(SELECT region_id
FROM regions
WHERE region_name='Europe'))));
Este ejemplo utiliza una serie de subconsultas para borrar a cada empleado que trabaja en cualquier
departamento con sede en Europa. Se aplica la misma regla para el número de valores devueltos por la
subconsulta que para un comando UPDATE: si la selección del registro se basa en una condición de
igualdad (como en el ejemplo anterior) la subconsulta debe ser escalar, pero si utiliza el comando IN, la
subconsulta puede devolver varios registros.
Si el comando DELETE no encuentra registros que eliminar, no se provocará un error. El comando
devolverá el mensaje "0 rows deleted" en lugar de un mensaje de error porque la sentencia se completó
con éxito, simplemente no encontró ningún registro que tuviese las características especificadas en la
declaración.
277/306
SQL
La sentencia anterior utiliza el contenido de una tabla NEW_EMPLOYEES para actualizar o insertar
registros en la tabla EMPLOYEES. La situación podría ser que la tabla EMPLOYEES contenga todo el
personal, y NEW_EMPLOYEES sólo contenga registros para el personal nuevo y para los cambios salariales
del personal existente. El comando pasará a través de NEW_EMPLOYEES, y para cada registro, intentará
encontrar un registro en EMPLOYEES con el mismo EMPLOYEE_ID. Si se encuentra un registro con el
278/306
SQL
mismo EMPLOYEE_ID, su columna SALARY se actualizará con el valor del registro de la tabla
NEW_EMPLOYEES. Si no existe tal registro, se insertará uno nuevo. Las variaciones de la sintaxis
permiten el uso de subconsultas para seleccionar registros de origen, e incluso es posible eliminar
registros coincidentes.
a. A de Atomicidad
El principio de atomicidad establece que todas las partes de una transacción o ninguna de ellas deben
completarse (la razón detrás de este término es que un átomo no puede ser dividido). Por ejemplo, si
los analistas de negocio dicen que cada vez que cambie el sueldo de un empleado, también debe cambiar
el grado del empleado, entonces la transacción atómica consistirá en dos actualizaciones. La base de
datos debe garantizar que ambas (o ninguna) se realicen. Si solamente una de ellas se actualizara, se
tendría un empleado con un salario incompatible a su grado: una corrupción de datos, en términos
comerciales. Si algo sale mal antes de que se complete la transacción, la propia base de datos debe
garantizar que cualquiera de las partes que hubiera realizado la transacción pueda revertirse; esto debe
ocurrir automáticamente. Pero, aunque el término “atómico” pueda hacer pensar que una transacción es
algo pequeño (como un átomo), en realidad una transacción puede ser enorme. Poniendo otro ejemplo:
supóngase que es imposible que en un determinado libro de contabilidad la mitad de sus cuentas
pertenezcan al mes de agosto y la otra mitad al mes de septiembre. El contenido debe ir de mes a mes,
por lo tanto (en términos comerciales), esto es una transacción atómica, que puede afectar a millones
de registros en miles de tablas y tardar horas en completarse (o en retroceder, si algo saliese mal). El
ROLLBACK de una transacción incompleta puede ser manual (como cuando se emite mediante el
comando ROLLBACK), pero debe ser automática e imparable en caso de error.
b. C de Consistencia
El principio de consistencia establece que los resultados de una consulta deben ser consistentes con el
estado de la base de datos en el momento en el que se ejecuta la consulta. Supóngase una simple
consulta que promedia el valor de una columna de una tabla. Si la tabla es grande, llevará mucho tiempo
279/306
SQL
recorrer toda la tabla. Si otros usuarios están actualizando la columna mientras la consulta está en
progreso, ¿debe la consulta incluir los nuevos o los antiguos valores? ¿Debe incluir los registros que
fueron insertados o borrados después que se empezó la consulta? El principio de consistencia precisa
que la base de datos garantice que los valores modificados no sean tenidos en cuenta al ejecutar la
consulta; dará un promedio de la columna como estaba cuando la consulta se empezó a ejecutar, sin
importar cuánto tarde la consulta o qué otras actividades estén llevándose a cabo en las tablas
correspondientes. Oracle garantiza que, si una consulta tiene éxito, el resultado será consistente. Sin
embargo, si el administrador de la base de datos no ha configurado la base de datos de forma apropiada,
la consulta podrá no tener éxito y se lanzará un error: “ORA-1555 snapshot too old”. Esto solía ser un
problema extremadamente difícil de resolver con versiones anteriores de la base de datos, pero con
versiones recientes, el administrador de la base de datos debería ser capaz siempre de prevenir esto.
d. D de Durabilidad
El principio de durabilidad establece que una vez completada la transacción, debe ser imposible que la
base de datos la pierda. Durante el tiempo que la transacción está en progreso, el principio de aislamiento
requiere que nadie (aparte de la sesión afectada) puede ver los cambios que ha hecho hasta ahora. En
el instante en que la transacción se completa, debe ser transmitida al resto de usuarios, y la base de
datos debe garantizar que el cambio nunca se pierda: una base de datos relacional no puede perder
datos. Oracle cumple este requisito escribiendo todos los vectores de cambio que se aplican a los datos
a medida que se realizan los cambios. Al aplicar este registro de cambios a las copias de seguridad
realizadas anteriormente, es posible repetir cualquier proceso realizado en el caso de que la base de
datos sea dañada. Por supuesto, los datos pueden perderse debido a errores de usuario tales como DML
inapropiado, o tablas caídas o truncadas, pero en lo que concierne a Oracle tales eventos son
transacciones como cualquier otra: de acuerdo con el principio de durabilidad, son absolutamente
irreversibles.
280/306
SQL
estándar de SQL no permite a un usuario empezar una transacción y después otra antes de terminar la
primera. Esto puede hacerse con PL/SQL, pero no con un estándar industrial de SQL.
Las sentencias explícitas de control de transacciones son COMMIT, ROLLBACK y SAVEPOINT. Hay también
otras circunstancias en las que un usuario emite un COMMIT o ROLLBACK que implícitamente terminarán
una transacción:
• Emisión de una sentencia DDL o DCL.
• Salir de la herramienta de usuario (SQL*Plus, SQL Developer o cualquier otra).
• Si la sesión de cliente acaba.
• Si el sistema falla.
Si un usuario emite un comando DDL (CREATE, ALTER o DROP) o DCL (GRANT o REVOKE), la transacción
en progreso (si hay alguna) estará confirmada (se habrá hecho COMMIT), por lo que se hará permanente
y será visible para todos los usuarios. Esto es debido a que los comandos DDL y DCL son transacciones
en sí mismas. Si fuera posible ver el código fuente de esos comandos, se podría ver que estos modifican
las estructuras de datos realizando comandos DML en las tablas que componen el diccionario de datos,
y estos comandos terminan con un COMMIT. Si esto no fuera así, podría no garantizarse la permanencia
de dichos cambios. Como no es posible en SQL anidar transacciones, si el usuario ya ha lanzado una
transacción, las sentencias que el usuario ha lanzado deberán confirmarse junto con las sentencias que
componen el comando DDL o DCL.
Si un usuario empieza una transacción emitiendo un comando DML y luego sale de la herramienta que
está utilizando sin emitir explícitamente un COMMIT o un ROLLBACK, la transacción terminará. Que
termine con un COMMIT o un ROLLBACK depende totalmente de la implementación de la herramienta.
Por ejemplo, en el entorno de Microsoft Windows, es común poder terminar un programa seleccionando
la opción de Archivo|Salir de un menú en la parte superior izquierda de la ventana, o haciendo clic sobre
una “X” en la esquina superior derecha. Los programadores que escribieron la herramienta pueden haber
codificado diferentes lógicas en estas funciones. En cualquier caso, será una salida controlada, por lo que
los programadores deben emitir un COMMIT o un ROLLBACK, la elección depende de ellos.
Si la sesión de un cliente falla por alguna razón, la base de datos siempre hará un ROLLBACK de la
transacción. Tal fallo puede deberse a varias razones: el proceso de usuario puede acabar o ser terminado
a nivel de sistema operativo, la conexión de red del servidor de la base de datos puede caerse o la
máquina en la que se está lanzando la herramienta cliente puede bloquearse. En cualquiera de estos
casos, no hay una emisión ordenada de un COMMIT o un ROLLBACK, y depende de la base de datos
detectar qué ha ocurrido. En estos casos, la sesión termina y se hace un ROLLBACK. El comportamiento
es el mismo si el fallo es del servidor. Si el servidor de la base de datos se bloquea por cualquier razón,
cuando se inicien la próxima vez todas las transacciones de cualquier sesión que estuviera en progreso
harán un ROLLBACK.
281/306
SQL
a. COMMIT
Sintácticamente, COMMIT es el comando más sencillo de SQL. La sintaxis es la siguiente:
COMMIT;
Esto pondrá fin a la transacción actual, además de hacer que los cambios sean permanentes y visibles
para otras sesiones. Hasta que no se confirma una transacción haciendo COMMIT, los cambios provocados
por dicha transacción no pueden verse en ninguna otra sesión, incluso si estas sesiones están conectadas
a la base de datos con el mismo usuario que el de la sesión que ejecuta la transacción.
Hasta que una transacción no se confirma (commited), es invisible para otras sesiones y se puede anular.
Una vez se confirma (commited), es absolutamente irreversible. Se aplica por lo tanto el principio de
durabilidad.
El estado de los datos antes de un COMMIT es que los cambios han sido realizados, pero todas las demás
sesiones, distintas a la que realizó los cambios, son redirigidas a las copias de los datos antes de ser
modificados. Así pues, si una sesión ha insertado registros, el resto de sesiones que hagan un SELECT
de la tabla no verán dichos registros. Si la transacción ha eliminado registros, las otras sesiones que
realicen un SELECT de la tabla seguirán viendo estos registros. Si la transacción ha hecho una
actualización, será la versión anterior a dicha actualización la que se les presente al resto de sesiones.
Esto está en concordancia con el principio de aislamiento: ninguna sesión puede presentarse de forma
que dependa del estado de una transacción no confirmada (commited).
Después de un COMMIT, todas las sesiones verán inmediatamente los nuevos datos en cualquiera de las
consultas que realicen: podrán ver los nuevos registros, no verán los registros eliminados y verán las
nuevas versiones de los registros actualizados, lo cual está en concordancia con el principio de
durabilidad.
b. ROLLBACK
Mientras una transacción está en progreso, Oracle mantiene una imagen de los datos tal y como se
encontraban antes de la transacción. Esta imagen es presentada a las otras sesiones que consultan los
datos mientras la transacción está en progreso. También se utiliza para deshacer automáticamente la
transacción si algo sale mal, o, deliberadamente, la sesión lo solicita. La sentencia para solicitar un
ROLLBACK es la siguiente:
COMMIT;
282/306
SQL
Un COMMIT es instantáneo, porque realmente no tiene nada que hacer. Los cambios ya han
sido realmente realizados. Un ROLLBACK puede ser, no obstante, muy lento: normalmente se
tardará lo mismo (si no más) en anular una transacción que lo que se tardó en hacer los
cambios en primer lugar. Hacer ROLLBACK no es bueno para el rendimiento de la base de
datos.
c. SAVEPOINT
El uso de SAVEPOINT permite al programador establecer un marcador en una transacción que puede ser
utilizado para controlar el efecto del comando ROLLBACK. En vez de revertir la transacción completa y
terminarla, hace posible anular todos los cambios realizados después de un punto en concreto, pero
mantiene intactos los cambios realizados hasta ese punto. La transacción en sí sigue en curso: aún no
se ha confirmado, aún es anulable, y aún es invisible para el resto de sesiones.
La sintaxis es la siguiente:
SAVEPOINT savepoint;
Esto crea un marcador en la transacción que puede ser utilizado en un comando ROLLBACK posterior.
La siguiente tabla ilustra, en varias etapas, el número de registros de una tabla en una transacción.
TRUNCATE TABLE 0 0
tab1;
SAVEPOINT first; 1 0
SAVEPOINT second; 2 0
283/306
SQL
VALUES ('three');
ROLLBACK TO 2 0
SAVEPOINT second;
ROLLBACK TO 1 0
SAVEPOINT first;
COMMIT; 1 1
ROLLBACK; 1 1
El ejemplo muestra dos transacciones: la primera terminó con un COMMIT, la segunda con un ROLLBACK.
Puede verse que el uso de SAVEPOINT es visible solamente dentro de la transacción: las otras sesiones
no ven nada de lo que no está committed.
El comando SAVEPOINT no es (todavía) parte oficial del estándar de SQL, así que puede
considerarse buena práctica evitarlo en sistemas en producción. Sin embargo, puede ser muy
útil en el desarrollo cuando se está probando el efecto de las sentencias DML y yendo a través
de una transacción compleja paso a paso.
SET AUTOCOMMIT ON
En SQL Developer, desde el menú Herramientas, seleccionar Preferencias. A continuación, expandir Base
de Datos y Avanzado y marcar la casilla de confirmación automática.
284/306
SQL
otros programas que no siguen el estándar SQL. Los scripts de SQL escritos para dichos
programas pueden no tener ninguna sentencia COMMIT.
No es inusual que una aplicación recupere un conjunto de registros con un comando SELECT, las presente
al usuario para que las examine y pida cualquier cambio. Debido a que Oracle es una base de datos
multiusuario, no es imposible que otra sesión también haya recuperado los mismos registros. Si ambas
sesiones intentan hacer cambios, puede haber algunos efectos no deseados. La siguiente tabla muestra
dicha situación:
COMMIT;
UPDATE regions
SET region_name='GB'
WHERE region_id=5;
Esto puede ser un poco desconcertante. Una forma de evitar este problema es bloquear los registros en
los que se está interesado.
SELECT *
285/306
SQL
La cláusula FOR UPDATE bloqueará todos los registros recuperados. No se podrán hacer cambios en ellos
por ninguna otra sesión que no sea la que emitió el comando, y, por lo tanto, las actualizaciones
posteriores tendrán éxito: no será posible para los registros que hayan sido cambiados. Esto significa
que una sesión tendrá una vista consistente de los datos (no cambiará), pero, por el contrario, las otras
sesiones se colgarán si intentan actualizar cualquier registro bloqueado (pueden, por supuesto,
consultarlos).
Los bloqueos situados por una cláusula FOR UPDATE se mantendrán hasta que la sesión que realizó el
comando emita un COMMIT o un ROLLBACK. Esto debe hacerse para liberar los bloqueos, incluso si no
se ha ejecutado ningún comando DML.
Problema Solución
10.6. Resumen
Descripción de cada sentencia DML (Lenguaje de Manipulación de Datos)
286/306
SQL
Control de transacciones
• Una transacción constituye una o varias sentencias DML que se ejecutan de forma atómica en la
base de datos.
• Las transacciones son invisibles para otras sesiones hasta que se les efectúa un COMMIT.
• Las transacciones se pueden deshacer mediante un ROLLBACK hasta que se les efectúa un
COMMIT.
• Una vez se ejecuta el comando COMMIT, no se puede revertir.
• Un SAVEPOINT permite que la sesión se pueda retroceder a un punto anterior de la transacción.
287/306
SQL
los registros; estas son conocidas como “constraints”. Las reglas estructurales y las reglas constraint
restringen la información que puede ser insertada dentro de la tabla.
Hay varios tipos de objetos que pueden existir dentro de una base de datos, muchos más con la versión
actual que con las versiones anteriores. Todos los objetos tienen nombres, y todos los objetos son
propiedad de un usuario de base de datos, como HR. Los objetos que el usuario posee son su esquema.
El nombre de un objeto debe cumplir ciertas reglas.
OBJECT_TYPE COUNT(OBJECT_TYPE)
----------------------------------------------
CLUSTER 10
CONSUMER GROUP 12
CONTEXT 6
DIMENSION 5
DIRECTORY 9
EDITION 1
EVALUATION CONTEXT 13
FUNCTION 286
INDEX 3023
INDEX PARTITION 342
INDEXTYPE 12
JAVA CLASS 22018
JAVA DATA 322
JAVA RESOURCE 820
JOB 11
JOB CLASS 11
LIBRARY 177
LOB 769
LOB PARTITION 7
MATERIALIZED VIEW 3
OPERATOR 60
PACKAGE 1240
PACKAGE BODY 1178
PROCEDURE 118
PROGRAM 17
QUEUE 37
RESOURCE PLAN 7
RULE 1
288/306
SQL
RULE SET 21
SCHEDULE 2
SEQUENCE 204
SYNONYM 26493
TABLE 2464
TABLE PARTITION 199
TRIGGER 413
TYPE 2630
TYPE BODY 231
UNDEFINED 6
VIEW 4669
WINDOW 9
WINDOW GROUP 4 XML SCHEMA 93 42 rows selected.
Esta consulta hace referencia a DBA_OBJECTS, que tiene una línea para cada objeto en la base de datos.
Los números son bajos, porque la base de datos es muy pequeña y se utiliza sólo para enseñar. Una
base de datos utilizada para una aplicación de negocio puede tener cientos de miles de objetos. Es posible
que no se pueda ver la vista DBA_OBJECTS, según los permisos de la cuenta.
La vista alternativa es USER_OBJECTS, que mostrará todos los objetos que tiene en propiedad y
ALL_OBJECTS, que mostrará todos los objetos a los que se ha concedido acceso. Todos los usuarios
tienen acceso a estos.
Los objetos de mayor interés para un programador SQL son aquellos que contienen o dan acceso a los
datos, estos son:
• Tablas
• Vistas
• Sinónimos
• Índices Secuencias
Brevemente, una instrucción SELECT almacenada puede ser tratada como si fuera una tabla. No es nada
más que una sentencia SELECT, pero en lugar de ejecutar el comando el usuario emite una instrucción
SELECT contra la vista. Un sinónimo es un alias para una tabla (o una vista). Los usuarios pueden ejecutar
sentencias SQL contra el sinónimo, y la base de datos los mapeará en sentencias contra el objeto al que
se refiere el sinónimo. Los índices son un medio para mejorar los tiempos de acceso a los registros de
las tablas. Si una consulta requiere sólo un registro, en lugar de escanear toda la tabla para encontrar
un índice puede dar un puntero a la ubicación exacta del registro. Por supuesto, el índice debe ser
buscado, pero esto es a menudo más rápido que el escaneo de la tabla. Una secuencia es una
construcción que genera números únicos. Hay muchos casos en los que números únicos son necesarios.
Las secuencias emiten los números en orden, a petición: es absolutamente imposible que el mismo
número se emita dos veces.
Los tipos de objeto restantes son comúnmente menos relevantes para un programador SQL. Su uso
recae más en el ámbito de los programadores PL/SQL y los administradores de base de datos.
289/306
SQL
Algunos esquemas siempre estarán vacíos: el usuario nunca creará ningún objeto, porque no es necesario
y (si el usuario está configurado correctamente) no dispondrá de privilegios de todos modos. A algunos
usuarios se les habrán concedido permisos, ya sea a través de privilegios directos o a través de roles,
para utilizar el código y acceder a los datos en otros esquemas, propiedad de otros usuarios. Otros
usuarios pueden ser lo contrario de esto, poseerán muchos objetos, pero nunca se conectarán a la base
de datos. Ni siquiera se les tiene que haber concedido el privilegio de CREATE SESSION, por lo que la
cuenta estará efectivamente deshabilitada (también puede ser bloqueada). Estos esquemas se utilizan
como repositorios de código y datos a los que acceden otros.
Los objetos de esquema son objetos con un propietario. El identificador único para un objeto de un tipo
particular no es su nombre; es su nombre prefijado con el nombre del esquema al que pertenece. Por lo
tanto, la tabla [Link] es una tabla denominada REGIONS, que es propiedad del usuario HR. Podría
haber otra tabla [Link] que sería una tabla completamente diferente (quizás diferente tanto
en estructura como en contenido) propiedad del usuario SYSTEM y que residen en su esquema.
Se crean automáticamente varios usuarios (y sus esquemas asociados) cuando se produce la creación
de la base de datos. Los principales son SYS y SYSTEM. El usuario SYS posee el diccionario de datos: un
conjunto de tablas (en el esquema SYS) que definen la base de datos y su contenido. SYS también posee
varios cientos de paquetes PL/SQL: código que se proporciona para el uso de administradores y
desarrolladores de bases de datos. Los objetos en el esquema SYS nunca deben modificarse con
comandos DML. Si se ejecutara DML contra las tablas del diccionario de datos, se correría el riesgo de
corromper el diccionario de datos, con resultados desastrosos. El diccionario de datos se actualiza
ejecutando comandos DDL (como CREAR TABLA), que proporcionan una capa de abstracción entre el
usuario y el propio diccionario de datos. El esquema SYSTEM almacena v arios objetos adicionales
utilizados para administración y monitoreo.
Dependiendo de las opciones seleccionadas durante la creación de la base de datos, puede haber más
usuarios creados. Estos usuarios almacenan el código y los datos requeridos por varias opciones de base
de datos.
Por ejemplo, el usuario MDSYS almacena los objetos usados por Spatial, una opción que amplía las
capacidades de la base de datos Oracle para gestionar la información geográfica.
• El nombre puede tener de 1 a 30 caracteres (excepto los nombres de enlaces de la base de datos
que pueden tener hasta 128 caracteres).
• Las palabras reservadas (como SELECT) no pueden utilizarse como nombres de objetos.
• Todos los nombres deben comenzar con una letra de la A a la Z.
• Los caracteres de un nombre sólo pueden ser letras, números, un guion bajo (_), el signo del
dólar ($), o el símbolo de almohadilla (#).
• Las letras minúsculas se convertirán en mayúsculas.
290/306
SQL
Al incluir el nombre entre comillas dobles, todas estas reglas (con la excepción de la longitud) pueden
romperse. El acceso posterior al objeto deberá hacerse siempre especificando su nombre entre comillas
dobles. Téngase en cuenta que las mismas restricciones también se aplican a los nombres de columna.
Aunque herramientas como SQL*Plus o SQL Developer convertirán automáticamente letras minúsculas
a mayúsculas, a menos que el nombre esté entre comillas dobles, recuerde que los nombres de los
objetos siempre distinguen entre mayúsculas y minúsculas. En este ejemplo, los dos son completamente
diferentes:
SELECT table_name
FROM user_tables
WHERE lower(table_name) = 'lower';
TABLE_NAME
------------------------------ lower LOWER
291/306
SQL
Los nombres de objetos no deben tener más de 30 caracteres. Los caracteres usados pueden
ser letras, dígitos, guion bajo, dólar, o almohadilla.
• Tablas
• Vistas
• Secuencias
• Sinónimos privados
Por lo tanto, es imposible crear una vista con el mismo nombre que una tabla, al menos si están en el
mismo esquema. Y una vez creadas, las sentencias SQL pueden referirse a una vista o un sinónimo como
si fuera una tabla. El hecho de que las tablas, las vistas y sinónimos privados comparten el mismo espacio
de nombres significa que se pueden configurar varias capas de abstracción entre lo que ven los usuarios
y las tablas reales, que pueden ser invaluable tanto para la seguridad como para simplificar el desarrollo
de aplicaciones. Los índices y las restricciones, tiene cada uno su propio espacio de nombres. Por lo
tanto, es posible que un índice tenga el mismo nombre que una tabla, incluso dentro del mismo esquema.
Cada tabla aparece como una definición en el diccionario de datos. En la creación, a la tabla se le habrá
asignado una cantidad limitada de espacio (conocido como extensión) dentro de la base de datos. Este
puede ser pequeño, quizás sólo unos pocos kilobytes o megabytes. Cuando se inserten los registros, esta
extensión se llenará. Cuando esté llena, la base de datos asignará otra extensión a la tabla. A medida
que se borran los registros, el espacio dentro de la extensión asignado estará disponible para su
reutilización, incluso si se borran todos los registros de la tabla. Sólo será liberado y devuelto a la base
292/306
SQL
• NVARCHAR2: Igual que VARCHAR2, pero los datos se almacenan en el juego de caracteres de
idioma nacional, uno de los juegos de caracteres Unicode permitidos.
• CHAR: Datos de caracteres de longitud fija, de 1 byte a 2000 bytes. Si los datos no son de la
longitud de la columna, entonces serán rellenados con espacios.
• RAW: Datos binarios de longitud variable, desde 1 byte hasta 4000 bytes si
MAX_STRING_SIZE=STANDARD o 32767 bytes si MAX_STRING_SIZE=EXTENDED. A diferencia
de los tipos de datos CHAR y VARCHAR2, RAW no convierte los datos de tipo carácter de la base
de datos a caracteres del proceso de usuario en SELECT o INSERT.
Los siguientes son los tipos para datos numéricos, todos de longitud variable:
• NUMBER: Datos numéricos, para los que se puede especificar la precisión y la escala. La precisión
puede variar de 1 a 38, la escala puede variar de -84 a 127.
• FLOAT: Éste es un tipo de datos ANSI, un número de coma flotante con una precisión de 126
binarios (o 38 decimales). Oracle también proporciona BINARY_FLOAT y BINARY_DOUBLE como
alternativas.
• INTEGER: Equivalente a NUMBER, con escala cero.
Los siguientes son los tipos para datos de fecha y hora, todos de longitud fija:
• DATE: La longitud es 0 si está vacía, o 7 bytes en caso contrario. Todos los datos de FECHA
incluyen siglo, año, mes, día, hora, minuto y segundo. El rango válido es del 1 de enero de 4712
a.C. al 31 de diciembre de 9999 d.C.
• TIMESTAMP: Esta es de longitud cero si la columna está vacía, o hasta 11 bytes, dependiendo
de la precisión especificada. Similar a DATE, pero con una precisión de hasta 9 decimales para
los segundos, 6 posiciones por defecto.
• TIMESTAMP WITH TIMEZONE: Como TIMESTAMP, pero los datos se almacenan con un registro
de la zona horaria a la que se refiere. La longitud puede ser de hasta 13 bytes, dependiendo de
293/306
SQL
la precisión. Este tipo de datos permite a Oracle determinar la diferencia entre dos horas
normalizándolas a UTC, incluso si las horas son de zonas horarias diferentes.
• TIMESTAMP WITH LOCAL TIMEZONE: Como TIMESTAMP, pero los datos se normalizan a la zona
horaria de la base de datos al guardarlos. Cuando se recupera, se normaliza a la zona horaria
del proceso de usuario que lo selecciona.
• INTERVAL YEAR TO MONTH: Se utiliza para registrar un período en años y meses entre dos DATEs
o TIMESTAMPs.
• INTERVAL DAY TO SECOND: Se utiliza para registrar un período en días y segundos entre dos
DATEs o TIMESTAMPs.
Los siguientes son los tipos de datos de objeto grandes:
• CLOB: Datos de caracteres almacenados en la base de datos, tamaño ilimitado: (4GB -1)
multiplicado por el tamaño del bloque de la base de datos.
• NCLOB: Como CLOB, pero los datos se almacenan en el juego de caracteres de idioma nacional
alternativo, uno de los juegos de caracteres Unicode permitidos.
• BLOB: Como CLOB, pero con datos binarios que no serán convertidos por Oracle Net.
• BFILE: Un puntero que apunta a un archivo almacenado en el sistema operativo del servidor de
base de datos. El tamaño de los archivos está limitado a 4 GB.
• LONG: Datos de caracteres en la base de datos, hasta 2 GB. Toda la funcionalidad de LONG (y
más) es proporcionada por CLOB; LONG no se debería usar en una base de datos moderna, y si
su base de datos tiene alguna columna de este tipo deberían ser convertidas a CLOB. Sólo puede
haber una columna LONG en una tabla.
• LONG RAW: Como LONG, pero con datos binarios que no serán convertidos por Oracle Net.
Cualquier columna LONG RAW debe ser convertida a BLOBs.
El tipo de datos VARCHAR2 debe calificarse con un número que indique la longitud máxima de la columna.
Si se inserta un valor menor en la columna, el valor sólo ocupará el espacio que necesite. Si el valor es
mayor que este máximo, el INSERT fallará con un error. Si el valor se actualiza en un valor mayor o
menor, la longitud de la columna (y por lo tanto el registro) se modificará en consecuencia. Si no se
ingresa en absoluto o se actualiza a NULL, entonces no ocupará ningún espacio.
El tipo de datos NUMBER se puede calificar opcionalmente con una precisión y una escala. La precisión
establece el número máximo de dígitos decimales significativos, donde el dígito más significativo es el
dígito más a la izquierda que no es cero, y el menos significativo es el dígito conocido más a la derecha
del número. La escala es el número de dígitos desde el punto decimal hasta el dígito menos significativo.
Una escala positiva es el número de dígitos significativos a la derecha del punto decimal hasta el dígito
menos significativo (incluido). Una escala negativa es el número de dígitos significativos a la izquierda
del punto decimal hasta el dígito menos significativo (no incluido).
El tipo de datos DATE siempre incluye siglo, año, mes, día, hora, minuto y segundo, incluso si no se
especifican todos estos elementos a la hora de insertar. Se debe especificar el año, el mes y el día; si se
omiten las horas, los minutos y los segundos, el valor predeterminado será medianoche. El uso de la
función TRUNC en una fecha también tiene el efecto de ajustar las horas, minutos y segundos hasta la
medianoche.
294/306
SQL
Oracle proporciona una gama de funciones de conversión de tipos para convertir entre tipos de datos y
en algunas circunstancias hará la conversión de tipos automáticamente. La siguiente figura ilustra el uso
de las técnicas de conversión manual y automática.
En el siguiente ejemplo, el primer INSERT utiliza funciones de tipo casting para convertir los datos de
carácter introducidos en los tipos de datos especificados para las columnas de la tabla. El segundo INSERT
intenta insertar cadenas de caracteres en las tres columnas, pero la inserción sigue teniendo éxito porque
Oracle puede convertir tipos de datos automáticamente si es necesario, pero sólo si el formato de los
datos es adecuado. Si el valor de la fecha se hubiera introducido en cualquier otro formato que no sea
DD-MM-YY, como '23-Nov-13', habría fallado.
• Tablas organizadas indexadas: Almacenan registros en orden según una clave índice.
• Bloques indexados: Pueden desnormalizar las relaciones padre-hijo de las tablas de manera
que se pueden agrupar registros de diferentes tablas.
• Bloques referenciados: Fuerzan una distribución aleatoria de registros, que descompondrá
cualquier orden basado en la secuencia de entrada.
295/306
SQL
Como mínimo, se especifica el nombre de la tabla (se creará en su propio esquema, si no especifica el
de otra persona) y al menos una columna con un tipo de datos. Hay muy pocos desarrolladores que
especifiquen ORGANIZATION HEAP, ya que éste es el valor por defecto y es el estándar SQL de la
industria. La palabra clave DEFAULT en una definición de columna permite proporcionar una expresión
que generará un valor para la columna cuando se inserte una fila si la sentencia INSERT no proporciona
un valor.
Considérese esta sentencia:
• EMPNO: Puede ser de hasta 4 dígitos de longitud sin parte decimal. Si se introducen partes
decimales en un INSERT, el valor se redondeará por exceso o por defecto al entero más próximo.
ENAME: Puede almacenar hasta 10 caracteres de cualquier tipo.
• HIREDATE: Acepta cualquier fecha, opcionalmente con la hora, pero si el valor no se introduce,
se almacenará el valor de la fecha actual a medianoche.
• SAL: Destinada a salarios de empleados, acepta valores numéricos de hasta 7 dígitos. Si incluye
parte decimal, esta se redondeará.
• COMM (para porcentaje de comisión): Tiene un valor por defecto de 0.03 que se introducirá si la
sentencia INSERT no incluye un valor para esta columna.
296/306
SQL
Téngase en cuenta que los valores de las columnas no mencionados en la sentencia INSERT han sido
generadas por las cláusulas DEFAULT. Si esas cláusulas no se hubieran definido en las columnas, habrían
sido NULL. Obsérvese también el redondeo del valor previsto para SAL.
La cláusula DEFAULT puede ser útil, pero tiene una funcionalidad limitada. No se puede utilizar
una subconsulta para generar el valor propuesto. Sólo se pueden especificar valores literales
o funciones.
Todas las consultas devuelven un conjunto bidimensional de registros; este resultado se almacena como
la nueva tabla. Un ejemplo simple de cómo crear una tabla con una subconsulta es:
Esta sentencia creará la tabla EMPLOYEES_COPY, la cual es una copia exacta de la tabla EMPLOYEES,
idéntica tanto en la definición como en los registros que contiene.
Cualquier constraint de tipo “not null” y “check” en las columnas también se aplicará a la nueva tabla,
pero no se aplicará ninguna restricción de clave primaria, única o de clave externa. Las restricciones se
discuten en una sección posterior. Esto se debe a que estos tres tipos de restricciones requieren índices
que podrían no estar disponibles o no ser deseados.
297/306
SQL
Los registros en la nueva tabla serán el resultado de unir las dos tablas, con dos de las columnas
seleccionadas con sus nombres cambiados. La nueva columna SERVICIO se rellenará con el resultado de
la aritmética que calcula el número de días desde que se contrató al empleado. Los registros se insertarán
en el orden especificado. Este orden no será mantenido por el DML subsiguiente, pero suponiendo los
datos del esquema HR estándar, la nueva tabla tendrá el siguiente aspecto:
La subconsulta puede incluir una cláusula WHERE para restringir los registros insertados en la nueva
tabla. Para crear una tabla sin registros, utilice una cláusula WHERE que excluya todos los registros:
La cláusula WHERE 1=2 nunca puede devolver TRUE, así que la estructura de la tabla será creada lista
para usar, pero no se insertarán registros en el momento de la creación.
• Añadir columnas:
• Modificar columnas:
298/306
SQL
• Borrar columnas:
• Renombrar columnas:
READ ONLY;
Todos estos cambios son comandos DDL con el COMMIT incorporado. Estos son irreversibles y fallarán si
hay una transacción activa contra la tabla. También son virtualmente instantáneos, con la excepción de
los borrados de columna. Borrar una columna puede ser un ejercicio que consume mucho tiempo porque
a medida que cada columna se borra, cada registro debe ser reestructurado para eliminar los datos de
la columna. El comando SET UNUSED, que hace que las columnas no existan en lo que se refiere a SQL,
es a menudo una mejor alternativa:
Este borra todas las columnas no utilizadas en un solo paso a través de la tabla.
Marcar una tabla como ‘Sólo lectura’ causará errores en cualquier intento de comando DML. Pero la tabla
todavía se puede borrar. Esto puede ser desconcertante, pero es perfectamente lógico. Un comando
DROP no afecta a la tabla, afecta a las tablas del diccionario de datos que definen la tabla, y éstas no
son de sólo lectura.
299/306
SQL
Al igual que con un TRUNCATE, SQL no producirá una advertencia antes de que la tabla sea borrada,
además como cualquier comando DDL, incluye un COMMIT.
Pero hay algunas restricciones: si alguna sesión tiene una transacción en progreso que incluye un registro
en la tabla, entonces el DROP fallará y también será imposible borrar una tabla a la que se hace referencia
en una restricción de clave foránea definida en otra tabla. Esta tabla (o la restricción) debe ser eliminada
primero.
Oracle 12c incluye una papelera de reciclaje que está habilitada por defecto. Esta permite
restaurar cualquier tabla que se haya borrado a menos que se haya eliminado con la opción
PURGE o se haya desactivado la opción de la papelera de reciclaje.
• UNIQUE
• NOT NULL
• PRIMARY KEY
• FOREIGN KEY
• CHECK
Todas las restricciones tienen nombre. Es una buena práctica especificar los nombres con una convención
de nomenclatura estándar, pero si no se nombran explícitamente, Oracle generará nombres para cada
una de ellas.
300/306
SQL
la restricción está compuesta de más de una columna (conocida como restricción de clave compuesta),
las columnas no tienen que ser del mismo tipo de datos ni estar adyacentes en la definición de tabla.
Una rareza de las restricciones únicas es que es posible introducir un valor NULL en la(s) columna(s)
clave; de hecho, es posible tener cualquier número de registros con valores NULL en su(s) columna(s)
clave. Por lo tanto, seleccionar registros en una columna clave garantizará que sólo se devuelva un
registro, a menos que busque NULL, en cuyo caso se devolverán todos los registros en las que las
columnas clave sean NULL.
Las restricciones únicas son impuestas por un índice. Cuando se define una restricción única, Oracle
buscará un índice en la(s) columna(s) clave, y si no existe se creará. Luego, cada vez que se inserta un
registro, Oracle buscará en el índice para ver si los valores de las columnas clave ya están presentes: si
lo están, rechazará la inserción. La estructura de estos índices (conocidos como índices B-Árbol) no
incluye valores NULL, por lo que se permiten muchos registros con NULL: simplemente no existen en el
índice. Aunque el primer objetivo del índice es hacer cumplir la restricción, tiene un efecto secundario:
mejorar el rendimiento si se utilizan las columnas clave en las cláusulas WHERE de las sentencias SQL.
Sin embargo, al seleccionar WHERE key_column IS NULL no puede usar el índice porque no incluye los
valores NULL y por lo tanto el resultado siempre será el escaneado de toda la tabla.
Cualquier intento de insertar un registro sin especificar valores para las columnas restringidas no nulas
produce un error. Es posible evitar la necesidad de especificar un valor incluyendo una cláusula DEFAULT
en la columna cuando se crea la tabla.
301/306
SQL
Así como una restricción única permite valores nulos en la columna restringida, también lo hace una
restricción de clave ajena. Se puede insertar registros en la tabla secundaria con columnas de clave
ajenas nulas, incluso si no hay ningún registro en la tabla padre con un valor nulo. Esto crea registros
huérfanos y puede causar una terrible confusión. Como regla general, todas las columnas de una
restricción única y todas las columnas de una restricción de clave ajena se definen mejor con restricciones
no nulas también; esto será a menudo un requisito empresarial.
Si se intenta insertar un registro en la tabla secundaria para la que no hay ningun registro coincidente
en la tabla padre, se producirá un error. Del mismo modo, borrar un registro en la tabla padre dará un
error si ya hay registros que se refieran a ella en la tabla secundaria. Hay dos técnicas para cambiar este
comportamiento. En primer lugar, la restricción se puede crear como ON DELETE CASCADE. Por tanto, si
se elimina un registro de la tabla padre, Oracle buscará en la tabla secundaria todas los registros
coincidentes y las eliminará también.
Esto ocurrirá automáticamente. Una técnica menos drástica es crear la restricción como ON DELETE SET
NULL. En este caso, si se elimina un registro de la tabla principal, Oracle buscará en la tabla secundaria
todos los registros que coincidan y establecerá las columnas de clave ajena como nulas. Esto significa
que los registros inferiores quedarán huérfanos, pero seguirán existiendo. Si las columnas en la tabla
secundaria también tienen una restricción no nula, entonces la eliminación de la tabla padre fallará.
No es posible borrar la tabla padre en una relación de clave ajena, incluso si no hay registros en la tabla
secundaria. Esto sigue siendo válido si se utilizaron las cláusulas ON DELETE SET NULL u ON DELETE
CASCADE.
Una variación de la restricción de la clave ajena es la restricción de la clave ajena autorreferenciada. Esto
define una condición en la que los registros padre e hijo existen en la misma tabla. Un ejemplo sería una
tabla de empleados que incluye una columna para el gerente del empleado. El propio gerente es un
empleado y debe existir en la tabla. Por lo tanto, si la clave primaria es la columna EMPLOYEE_NUMBER
y el administrador está identificado por una columna MANAGER_NUMBER, la restricción de clave ajena
indicará que el valor de la columna MANAGER_NUMBER debe referirse a un EMPLOYEE_NUMBER válido.
Si un empleado es su propio manager, la línea se referirá a sí misma.
302/306
SQL
Para las restricciones que requieren un índice (las restricciones clave únicas y primarias). El índice se
creará con la tabla si la restricción se define en el momento de la creación de la tabla.
Problema Solución
Considerar estas dos expresiones de creación de tablas (a las que se han añadido números de registro):
303/306
SQL
1. La primera tabla creada es DEPT, con la intención de tener un registro para cada departamento.
2. DEPTNO es numérico, 2 dígitos sin decimales. Esta es la clave primaria de la tabla. La restricción
se denomina DEPT_DEPTNO_PK.
3. Una segunda restricción que se aplica al DEPTNO es un control que lo limita a los números
comprendidos entre 10 y 90. La restricción se denomina DEPT_DEPTNO_CK.
4. La columna DNAME está formada por caracteres de longitud variable, con una restricción
DEPT_DNAME_NN que la hace no nula.
5. La segunda tabla creada es EMP, con la intención de tener un registro por cada empleado.
6. EMPNO es numérico, hasta 4 dígitos sin decimales. La restricción EMP_ EMPNO_PK lo marca
como la clave primaria de la tabla.
7. ENAME son caracteres de longitud variable, con una restricción EMP_ENAME_NN que lo hace no
nulo.
8. MGR es el gerente del empleado, que debe ser un empleado. La columna se define del mismo
modo que la columna clave primaria de EMPNO de la tabla. La restricción EMP_MGR_FK define
esta columna como autorreferencial por lo que cualquier valor introducido debe referirse a un
registro ya existente en el EMP (aunque no está restringido a no ser nulo, por lo que puede
dejarse en blanco).
9. DOB, la fecha de nacimiento del empleado, es una fecha y no está restringida.
10. HIREDATE es la fecha en que el empleado fue contratado y no está restringido. Al menos, todavía
no.
11. DEPTNO es el departamento al que está asociado el empleado. La columna se define del mismo
modo que la columna clave primaria de DEPTNO de la tabla DEPT, y la restricción
EMP_DEPTNO_FK refuerza una relación de clave ajena: no es posible asignar un empleado a un
departamento que no existe, aunque este sea nulo.
12. La restricción EMP_DEPTO_FK se define más adelante como ON DELETE SET NULL, de modo que,
si se borra el registro padre en DEPT, todos los registros secundarias coincidentes en EMPNO
tendrán DEPTNO a NULL.
13. EMAIL es un dato de caracteres de longitud variable, y debe ser único si se introduce (aunque
puede dejarse vacío).
304/306
SQL
14. Esto define una restricción adicional a nivel de tabla EMP_HIREDATE_CK. La restricción se verifica
para el trabajo infantil, rechazando los registros en los que la fecha de contratación no sea por
lo menos 16 años posterior a la fecha de nacimiento. Esta restricción no se puede definir en línea
con HIREDATE, ya que la sintaxis no permite referencias a otras columnas en ese punto.
15. Se añade una restricción adicional EMP_EMAIL_CK a la columna EMAIL, que realiza dos
verificaciones en la dirección de correo electrónico.
16. Las funciones INSTR buscan los caracteres arroba (@) y punto (.), que siempre estarán presentes
en una dirección de correo electrónico válida. Si no puede encontrar ambos, la condición CHECK
devolverá FALSE y el registro será rechazado.
Los ejemplos anteriores muestran varias posibilidades para definir restricciones en el momento de la
creación de la tabla. Las siguientes son otras posibilidades no cubiertas:
11.6. Resumen
Categorizar los objetos principales de la base de datos
• Las tablas son estructuras bidimensionales que almacenan registros definidos en columnas.
• Las tablas existen dentro de un esquema. El nombre del esquema con el nombre de la tabla
hacen un identificador único.
• Los tipos de datos más comunes son VARCHAR2, NUMBER y DATE. Existen muchos más tipos.
305/306
SQL
306/306