43
Manual de SQL ORACLE 1 Practicas de BB. DD. ORACLE Oracle Es un sistema gestor de Bases de datos relacionales, y utiliza, para consultar los datos que mantiene, el lenguaje SQL. Este lenguaje es el que se analiza a continuación, en sus tres aspectos, consulta, modificación, y manipulación de los datos. Los ejemplos que se incluyen se realizan sobre unas tablas, que corresponden a un modelo relacional sencillo, y son las siguientes: Tabla EMP: (describe a los empleados de una empresa) Nombre de columna Permite Tipo de Dato valores nulos? ------------------------------- ------------------ ---------------- EMPNO NOT NULL NUMBER(4) ENAME VARCHAR2(10) JOB VARCHAR2(9) MGR NUMBER(4) HIREDATE DATE SAL NUMBER(7,2) COMM NUMBER(7,2) DEPTNO NOT NULL NUMBER(2) Tabla DEPT (describe a los departamentos de la empresa) Nombre de columna Permite Tipo de Dato valores nulos? ------------------------------- ------------------ ---------------- DEPTNO NOT NULL NUMBER(2) DNAME VARCHAR2(14) LOC VARCHAR2(13) Tabla SALGRADE (describe un grado de la empresa según el intervalo entre el cual se encuentra el salario del empleado) Nombre de columna Permite Tipo de Dato valores nulos? ------------------------------- ------------------ ---------------- GRADE NUMBER LOSAL NUMBER HISAL NUMBER Toda esta información puede ser obtenida desde Oracle SQL mediante el comando "DESCRIBE nombre_tabla". Las tablas creadas en el perfil de usuario pueden ser consultadas mediante la tabla "user_tables" y una orden de consulta sencilla, que es un

Resumen SQL Oracle

Embed Size (px)

Citation preview

Page 1: Resumen SQL Oracle

Manual de SQL ORACLE

1

Practicas de BB. DD.

ORACLE

Oracle Es un sistema gestor de Bases de datos relacionales, y

utiliza, para consultar los datos que mantiene, el lenguaje SQL. Este

lenguaje es el que se analiza a continuación, en sus tres aspectos, consulta,

modificación, y manipulación de los datos.

Los ejemplos que se incluyen se realizan sobre unas tablas, que

corresponden a un modelo relacional sencillo, y son las siguientes:

Tabla EMP: (describe a los empleados de una empresa)

Nombre de columna Permite Tipo de Dato

valores nulos?

------------------------------- ------------------ ----------------

EMPNO NOT NULL NUMBER(4)

ENAME VARCHAR2(10)

JOB VARCHAR2(9)

MGR NUMBER(4)

HIREDATE DATE

SAL NUMBER(7,2)

COMM NUMBER(7,2)

DEPTNO NOT NULL NUMBER(2)

Tabla DEPT (describe a los departamentos de la empresa)

Nombre de columna Permite Tipo de Dato

valores nulos?

------------------------------- ------------------ ----------------

DEPTNO NOT NULL NUMBER(2)

DNAME VARCHAR2(14)

LOC VARCHAR2(13)

Tabla SALGRADE (describe un grado de la empresa según el intervalo entre el cual se encuentra el salario del empleado)

Nombre de columna Permite Tipo de Dato

valores nulos?

------------------------------- ------------------ ----------------

GRADE NUMBER

LOSAL NUMBER

HISAL NUMBER

Toda esta información puede ser obtenida desde Oracle SQL

mediante el comando "DESCRIBE nombre_tabla".

Las tablas creadas en el perfil de usuario pueden ser consultadas

mediante la tabla "user_tables" y una orden de consulta sencilla, que es un

Page 2: Resumen SQL Oracle

Manual de SQL ORACLE

2

mandato 'SELECT'. Este mandato, es básico en la realización de consultas

al sistema gestor de BBDD de Oracle, y es el que permite mostrar la

información de la base de datos.

TEMA 1: Mandato "Select" Básico. La sintaxis de este mandato es:

SELECT [DISTINCT] {*, nombre_columna [alias], ....}

FROM nombre_tabla [alias];

Este mandato muestra los valores incluidos en las columnas

seleccionadas de la tabla especificada. Los comandos incluidos entre

corchetes, son opcionales, y los incluidos entre llaves indican que ha de

escogerse entre uno de ellos. Por ejemplo, la siguiente consulta:

SELECT ename, job, sal FROM emp;

Muestra el siguiente resultado:

ENAME JOB SAL ---------- --------- --------- KING PRESIDENT 5000 BLAKE MANAGER 2850 CLARK MANAGER 2450 JONES MANAGER 2975 MARTIN SALESMAN 1250 ALLEN SALESMAN 1600 TURNER SALESMAN 1500 JAMES CLERK 950 WARD SALESMAN 1250 FORD ANALYST 3000 SMITH CLERK 800 SCOTT ANALYST 3000 ADAMS CLERK 1100 MILLER CLERK 1300 DOE CLERK 15 rows selected.

La opción "distinct" selecciona únicamente las diferentes ocurrencias

que existen en las tuplas de una columna, o conjunto de ellas.

La opción "*" selecciona todas las columnas de la tabla especificada.

Si especificamos únicamente una columna de la tabla, deberemos incluir su

nombre.

Page 3: Resumen SQL Oracle

Manual de SQL ORACLE

3

Podemos asignarle un alias, es decir, un encabezamiento de la

columna en la salida producida, que describa el contenido de las tuplas de

la columna que se va a mostrar.

Para poder incluir un alias, se escribe dicho alias después del nombre

de la columna, sin coma. Si el alias posee espacios entre sus caracteres

deberemos usar las comillas dobles para delimitar dicho alias. También se

pede incluir opcionalmente la palabra clave "AS" para indicar que se debe

renombrar la columna con la palabra que se incluye después.

Existen operadores que permiten realizar cambios sobre los datos de

salida, estos operadores son:

|| : operador de concatenación, permite concatenar una cadena entre

comillas simples a la cadena de salida del mandato "select".

+: suma, permite sumar una cantidad determinada al dato de salida

del mandato "select".

-: resta, permite restar una cantidad determinada al dato de salida

del mandato "select".

*: multiplicación, permite multiplicar por una cantidad determinada

el dato de salida del mandato "select".

/: división, permite dividir por una cantidad determinada el dato de

salida del mandato "select".

TEMA 2: Restricción y Ordenación de los datos recuperados

Vamos a incluir en la sintaxis del mandato "select" básico, una nueva

sentencia, "WHERE", que nos va ha permitir restringir la salida del

mandato según las condiciones indicadas en esta sentencia. Así, la sintaxis

queda como:

SELECT [DISTINCT] {*, columna [alias],...}

FROM nombre_tabla

[WHERE condition(s)];

Como se puede observar, la inclusión de esta cláusula es opcional.

Un mandato "select" con una cláusula "where" mostrará únicamente los

datos que cumplan la condición especificada en ella. La condición se

expresa mediante una serie de operadores que son:

= (igual), > (mayor que), >= (mayor o igual que), < (menor

que), <= (menor o igual que), <> (distinto de)

"between .... and ...." (entre los valores .... y ....)

"in (..., ..., ......)" (se encuentra en la lista dada entre paréntesis

y cuyos valores están separados por comas)

"like" (igual a, pero para cadenas de caracteres)

"is null" (para cadenas o caracteres nulos)

Page 4: Resumen SQL Oracle

Manual de SQL ORACLE

4

Se pueden concatenar condiciones, de manera que la salida será según el

operador:

"condición AND condición" (mostrará los datos que cumplan

las condiciones que se encuentran antes y después de este

operador).

"condición OR condición" (mostrará los datos que cumpla la

condición que se encuentran antes ó después de este operador).

"NOT condición" (mostrará los datos que no cumplan la

condición que se encuentra después de este operador).

Para ordenar los datos que recuperamos mediante el mandato

"select", se usa la cláusula "ORDER BY nombre_columna" así tenemos

ahora:

SELECT [DISTINCT] {*, columna [alias],...}

FROM nombre_tabla

[WHERE condition(s)]

[ORDER BY column_name [{DESC, ASC}];

Se puede observar que esta cláusula también es opcional. La

ordenación es por defecto ascendente, es decir , de menor a mayor, excepto

en el caso de que se incluya la palabra reservada "DESC". Esta palabra

reservada, hay que incluirla para cada una de las columnas que se incluyen

dentro de la sentencia 'ORDER BY...'. Por ejemplo, la consulta:

SELECT ename, sal, comm

FROM emp WHERE comm IS NOT NULL ORDER BY sal,comm DESC;

Ofrece la salida:

ENAME SAL COMM

---------- --------- --------- MARTIN 1250 1400 WARD 1250 500 TURNER 1500 0 ALLEN 1600 300

Donde se puede observar que se ha ordenado de mayor a menor la columna

de las comisiones ('comm') pero de menor a mayor en el campo del salario,

tomando además este como el campo de ordenación principal. Así, el

salario ('sal') esta ordenado en orden ascendente por defecto. Para poder

ordenar en orden descendente de salario y comisiones la consulta correcta

es:

Page 5: Resumen SQL Oracle

Manual de SQL ORACLE

5

SELECT ename,sal,comm FROM emp WHERE comm IS NOT NULL ORDER BY sal DESC,comm DESC;

que ofrece la salida:

ENAME SAL COMM

---------- --------- --------- ALLEN 1600 300 TURNER 1500 0 MARTIN 1250 1400 WARD 1250 500

TEMA 3: Funciones sobre cadenas de caracteres y tipos de datos especiales.

Funciones para cadenas

Para la manipulación de cadenas de caracteres existen funciones

como:

LOWER({columna,expresion}): Pasa toda la cadena indicada

en el nombre de columna, o en expresión entre comillas

simples a letras minúsculas.

UPPER({columna,expresion}): Pasa toda la cadena indicada

en el nombre de columna, o en expresión entre comillas

simples a letras mayúsculas.

INITCAP({columna,expresion}): Pasa toda la cadena indicada

en el nombre de columna, o en expresión entre comillas

simples a letras donde la primera letra esta en mayúscula y el

resto en minúsculas.

CONCAT(cadena1,cadena2): Devuelve una cadena

concatenación de 'cadena1' y 'cadena2'.

SUBSTR(cadena,n,m,.....): Devuelve los caracteres de la

cadena desde el n, hasta el carácter número m.

LENGTH(cadena): Devuelve un entero con el número de

caracteres de la cadena pasada como parámetro.

LPAD(columna,numero_caracteres,'caracter') ofrece a la

salida un cadena de longitud 'numero_caracteres' que contiene

a caracteres 'caracter' a la izquierda y el contenido de la

columna indicada en 'columna', rellenando dicha cadena, con

los caracteres especificados hasta alcanzar el tamaño indicado.

Estas funciones nos permiten consultas como:

SELECT ename, job, hiredate

Page 6: Resumen SQL Oracle

Manual de SQL ORACLE

6

FROM emp WHERE LOWER(ename)='blake';

Donde el nombre que encontramos en la tabla, puede estar escrito de

cualquier manera, pero se pasa a letras minúsculas para ser comparado con

el nombre 'blake'.

Funciones numéricas

También existen funciones numéricas tales como:

ROUND({columna,expresión,numero}): que obtiene el

redondeo de la cifra pasada como parámetro a un número

entero.

TRUNC({columna,expresion},n): que obtiene el redondeo de

la cifra real pasada como primer parámetro a un número con

tantos decimales como se le indique en el segundo parámetro

'n'.

MOD(m,n): Que obtiene el resto de la división entera entre 'm'

y 'n'.

Donde la utilidad de estas es similar a la que se muestra en el

conjunto de funciones anterior, pero además se puede utilizar (como las

anteriores también) en consultas como la siguiente:

SELECT empno,ename,sal,round (sal*1.15) "New Salary" FROM emp;

Que ofrece la salida siguiente:

EMPNO ENAME SAL New Salary --------- ---------- --------- ---------- 7839 KING 5000 5750 7698 BLAKE 2850 3278 7782 CLARK 2450 2818 7566 JONES 2975 3421 7654 MARTIN 1250 1438 7499 ALLEN 1600 1840 7844 TURNER 1500 1725 7900 JAMES 950 1093 7521 WARD 1250 1438 7902 FORD 3000 3450 7369 SMITH 800 920 7788 SCOTT 3000 3450 7876 ADAMS 1100 1265 7934 MILLER 1300 1495 8000 DOE 15 rows selected.

Page 7: Resumen SQL Oracle

Manual de SQL ORACLE

7

Donde en la columna 'New Salary', se ofrece el redondeo de la cifra

obtenida al multiplicar el salario del trabajador por 1.15.

Funciones para fechas

También existen funciones específicas para el tipo de dato 'fecha', de

Oracle que son:

MONTHS_BETWEEN(date1,date2): Devuelve los meses que

hay entre dos fechas dadas como 'date1' y 'date2'.

ADD_MONTHS(date,n): Devuelve una fecha con 'n' meses

añadidos a la fecha pasada como primer parámetro.

NEXT_DAY(date,'char'): Permite conocer la fecha (valor

devuelto) del día indicado en 'char' siguiente a la fecha pasada

como primer parámetro. Por ejemplo podemos conocer la

fecha del siguiente lunes a partir de una fecha determinada.

LAST_DAY(date): Devuelve el último día del mes.

Para realizar conversiones explicitas entre tipos de datos en relación

al tipo de dato 'fecha', se usan funciones como:

TO_CHAR(number/date,[fmt]): Devuelve una cadena

obtenida a partir de una fecha o un número.

TO_DATE('char',[fmt]): Devuelve una fecha creada a partir de

una cadena pasada como parámetro.

TO_NUMBER(char): pasa a número la cadena pasada como

parámetro.

En este último grupo de funciones, encontramos un parámetro, que

es el formato de fecha. Este formato está formado por una serie de

caracteres dados, que permiten al SGBD determinar el formato en el que se

ha pasado la fecha. El formato por defecto es: DD-Month-YY, es decir, una

fecha con este formato podría ser: '12-May-03'. Estos caracteres especiales

son:

YYYY: Número del año completo y en número entero.

YY: año, en dos cifras (2003-->03)

Year: Forma escrita del año (la primera en mayúscula y las

siguientes en minúscula).

MM: Mes, en cifras numéricas

Month: Mes escrito en letras (la primera en mayúscula y las

siguientes en minúscula).

DD: Cifra numérica del año.

Day: Día escrito en letras (la primera en mayúscula y las

siguientes en minúscula).

Page 8: Resumen SQL Oracle

Manual de SQL ORACLE

8

Como ejemplo, podemos ver los empleados dados de alta entre el 20

de febrero del 81, y el 1 de mayo del mismo año.

SELECT ename,hiredate FROM emp WHERE hiredate BETWEEN to_date('20-February-81','DD-Month-YY') AND to_date('01-May-81','DD-Month-YY');

Funciones especiales

Existen otras funciones especiales, no asociadas a ningún tipo de

dato en especial, entre las que podemos encontrar:

NVL(columna,sustitución): Permite cambiar cualquier valor

nulo por el dato que interese. Detecta los valores nulos en la

columna pasada como primer parámetro y los sustituye por el

dato pasado en el segundo parámetro. Por ejemplo, en esta

consulta, se muestra con un cero a los empleados que no ganan

comisiones: SELECT ename, NVL(comm,0) "Commisions" FROM emp;

Esta función es especialmente interesante ya que cualquier

operación con un dato nulo da como resultado otro dato nulo,

lo cual puede no interesarnos, en casos como el de calcular el

salario total de todos los empleados, ya que aquellos que no

cobran comisión, tienen un valor NULL en este campo

(comm=NULL), y sumado al salario, daría el valor nulo, con

lo que la salida no sería correcta.

DECODE Function: Esta función es similar a un "case" de C,

o un "Según" en pseudocódigo, permite especificar los valores

a mostrar, según una columna dada, o el valor de una

expresión. Por ejemplo:

SELECT job, sal, DECODE (job, 'ANALYST', sal*1.1,

'CLERK', sal*1.5, 'MANAGER',sal*1.20, sal) "Revised Salary" FROM emp;

De esta manera adecuamos la subida de salario en

función del trabajo.

Page 9: Resumen SQL Oracle

Manual de SQL ORACLE

9

TEMA 4: Productos Cartesianos.

En este tema se aprende a obtener datos de múltiples tablas dentro de

la base de datos que tenemos, así en nuestro caso, tenemos las tablas 'emp'

y 'dept' definidas al comienzo del presente documento. Para ello es

necesario que ambas tablas posean una clave foránea, que es un campo que

permite relacionar los datos que ambas contienen, así, para conocer la

localización del departamento donde trabaja un empleado, necesitaremos

ambas tablas.

Este tipo de consultas se realiza teniendo en cuenta los siguientes

puntos:

Incluir las tablas que vamos a necesitar en la cláusula 'from'

que en nuestro caso serán, como ya se ha dicho antes, las

tablas 'emp' y 'dept'.

Es necesario, en algunos casos, definir a que tabla pertenece la

columna que deseamos recuperar con nuestra consulta. Así,

en caso de que una columna este en ambas tablas, se deberá

hacer mención a esas columnas mediante el nombre de la

tabla, un punto, y el nombre de la columna.

También, debemos evitar que se produzca un producto

cartesiano. Siempre que utilicemos dos o más tablas en una

consulta, deberemos "emparejar" las tuplas de las tablas, de

manera que el SGBD de Oracle pueda mostrarnos la

información correcta. si no se realiza esta acción, emparejará

cada tupla de una tabla con todas las de la otra u otras, es

decir, realiza un producto cartesiano de las tablas que

intervienen en la consulta.

A continuación veremos un ejemplo de lo que se acaba de explicar.

Supongamos que queremos recuperar los nombres de los trabajadores, y el

departamento donde trabajan, así como la localización de este

departamento. Podríamos realizar la siguiente consulta, sin tener en cuenta

el producto cartesiano, que provocará que la salida sea incorrecta:

SELECT ename, deptno, loc FROM emp, dept;

Esta consulta ofrece a la salida lo siguiente:

SELECT ename, deptno, loc * ERROR at line 1: ORA-00918: column ambiguously defined

Page 10: Resumen SQL Oracle

Manual de SQL ORACLE

10

Debido a que la columna 'deptno', esta definida tanto en la tabla

'emp' como en la tabla 'dept', así es que nos informa de que la columna esta

definida ambiguamente. Si subsanamos ese error, queda la consulta:

SELECT ename, dept.deptno, loc FROM emp, dept;

Ahora se nos ofrece a la salida la siguiente lista de tuplas:

ENAME DEPTNO LOC ---------- --------- ------- KING 10 NEW YOR BLAKE 10 NEW YOR CLARK 10 NEW YOR JONES 10 NEW YOR MARTIN 10 NEW YOR ALLEN 10 NEW YOR TURNER 10 NEW YOR JAMES 10 NEW YOR WARD 10 NEW YOR FORD 10 NEW YOR SMITH 10 NEW YOR SCOTT 10 NEW YOR ADAMS 10 NEW YOR MILLER 10 NEW YOR DOE 10 NEW YOR KING 20 DALLAS BLAKE 20 DALLAS CLARK 20 DALLAS JONES 20 DALLAS MARTIN 20 DALLAS ALLEN 20 DALLAS ............................................. ............................................. FORD 40 BOSTON SMITH 40 BOSTON SCOTT 40 BOSTON ADAMS 40 BOSTON MILLER 40 BOSTON DOE 40 BOSTON 60 rows selected.

Tal y como podemos comprobar, esta no es la salida que deseamos

obtener, ya que tenemos 60 filas, y en realidad en nuestra empresa tan solo

hay 15 trabajadores, luego algo ha pasado. Efectivamente se ha producido

un producto cartesiano entre las tuplas de las tablas 'emp' y 'dept'. Para

evitar esto, debemos emparejar cada empleado con la localización del

departamento en que trabaja, ya que antes se han emparejado todos los

Page 11: Resumen SQL Oracle

Manual de SQL ORACLE

11

empleados con todos los departamentos existentes en nuestra empresa

(producto cartesiano). Así, la consulta correcta que nos ofrece los datos

requeridos es:

SELECT ename, dept.deptno , loc FROM emp, dept WHERE emp.deptno=dept.deptno;

Consulta que ofrece a la salida los datos correctos sobre la

localizacion del departamento, donde trabajan todos los empleados:

ENAME DEPTNO LOC ---------- --------- ------------- KING 10 NEW YORK BLAKE 30 CHICAGO CLARK 10 NEW YORK JONES 20 DALLAS MARTIN 30 CHICAGO ALLEN 30 CHICAGO TURNER 30 CHICAGO JAMES 30 CHICAGO WARD 30 CHICAGO FORD 20 DALLAS SMITH 20 DALLAS SCOTT 20 DALLAS ADAMS 20 DALLAS MILLER 10 NEW YORK DOE 10 NEW YORK 15 rows selected.

Dependiendo del tipo de relación a que estén sujetas las tablas, se

pueden definir varios tipos de emparejamiento dentro de este tipo de

consultas que veremos mediante ejemplos, así, tenemos:

Equijoins (igualdad): Cuando la relación es de uno a uno, es el

caso anterior. Un ejemplo es la consulta realizada

anteriormente.

Non-equijoins (no igualdad): son relaciones que no son de

igualdad, como ejemplo utilizaremos la tabla 'salgrade' en la

siguiente consulta: SELECT ename, sal, grade FROM emp, salgrade WHERE sal BETWEEN losal AND hisal;

que ofrece la siguiente salida:

ENAME SAL GRADE ---------- --------- --------- JAMES 950 1

Page 12: Resumen SQL Oracle

Manual de SQL ORACLE

12

SMITH 800 1 ADAMS 1100 1 MARTIN 1250 2 WARD 1250 2 MILLER 1300 2 ALLEN 1600 3 TURNER 1500 3 BLAKE 2850 4 ......... 14 rows selected.

Outer-joins (filas que no tienen ningún valor): Si existen filas

que no tiene ningún valor asociado, ejemplo:

SELECT e.ename, d.deptno, d.dname FROM emp e, dept d WHERE e.deptno(+)=d.deptno ORDER BY e.deptno;

que ofrece al siguiente salida:

ENAME DEPTNO DNAME

---------- --------- --------------

KING 10 ACCOUNTING

CLARK 10 ACCOUNTING

DOE 10 ACCOUNTING

MILLER 10 ACCOUNTING

JONES 20 RESEARCH

SCOTT 20 RESEARCH

ADAMS 20 RESEARCH

SMITH 20 RESEARCH

FORD 20 RESEARCH

BLAKE 30 SALES

MARTIN 30 SALES

ALLEN 30 SALES

TURNER 30 SALES

JAMES 30 SALES

WARD 30 SALES

40 OPERATIONS 16 rows selected.

Donde se puede observar que se coloca el símbolo (+) para

indicar que la salida puede ser nula en los campos que poseen

ese símbolo, y así, mostramos todos los departamentos

existentes, aunque estos no tengan asignado ningún trabajador.

Page 13: Resumen SQL Oracle

Manual de SQL ORACLE

13

Self-joins (para datos almacenados en la misma tabla): este

tipo de consultas, se realizan entre datos de la misma tabla.

Como se ha podido observar, se pueden asignar alias a las

tablas, de manera que no haga falta que se escriba el nombre

completo de la tabla cuando queremos distinguir dos campos

de igual nombre, pero que pertenecen a tablas distintas. esto

podemos usarlo para realizar consultas como la siguiente:

SELECT worker.ename||' works for '||manager.ename FROM emp worker, emp manager WHERE worker.mgr=manager.empno;

Consulta que ofrece a la salida, el nombre de todos los

empleados, y el jefe del cual depende:

WORKER.ENAME||'WORKSFOR'||MANAG

-------------------------------

BLAKE works for KING

CLARK works for KING

JONES works for KING

MARTIN works for BLAKE

ALLEN works for BLAKE

TURNER works for BLAKE

JAMES works for BLAKE

WARD works for BLAKE

FORD works for JONES

SMITH works for FORD

SCOTT works for JONES

ADAMS works for SCOTT

MILLER works for CLARK

DOE works for BLAKE

14 rows selected.

TEMA 5: Funciones de grupo. Agrupar datos.

Existen funciones no especificadas en el tema 3 que permiten

calcular valores como medias, valores máximos etc. Estas funciones son

entre otras:

MAX(columna): ofrece a la salida el valor máximo encontrado

en la columna especificada en el parámetro.

Page 14: Resumen SQL Oracle

Manual de SQL ORACLE

14

MIN(columna): ofrece a la salida el valor mínimo encontrado

en la columna especificada en el parámetro.

AVG(columna): ofrece a la salida el valor de la media

aritmética en la columna especificada en el parámetro.

SUM(columna): Que ofrece a la salida, la suma de todas las

ocurrencias encontradas en la columna que se pasa como

parámetro a la función.

COUNT(columna): Cuenta el nº de filas en una columna de la

tabla.

STDDEV(columna): Obtiene la desviación típica en los valore

de una columna de la tabla.

Así, podemos crear consultas tales como la siguiente:

SELECT max(sal), min(sal), avg(sal), sum(sal)

FROM emp WHERE job like 'sales%';

Que ofrece a la salida una sola fila que contendrá los valores

especificados en las funciones definidas anteriormente.

Dentro de estas funciones, es de especial importancia, la función

COUNT, ya que esta puede tener en cuenta valores nulos en el momento de

realizar la cuenta, o no. Así, podemos ver que en la siguiente consulta, se

realiza una cuenta de todas las ocurrencias de las columnas, sin importar si

estas contienen valores nulos o no:

SELECT count(*) FROM emp WHERE deptno=30;

Esta consulta ofrece a la salida una sola fila (y columna) con el valor

de todas las ocurrencias de la tabla en las que se encuentre un valor en la

columna 'deptno' igual a 30. Sin embargo, en el siguiente caso, en el que se

especifica un nombre de columna, si se tienen en cuenta aquellos valores

que poseen un valor nulo:

SELECT count(comm) FROM emp WHERE deptno=30;

Así, se ofrece a la salida de nuevo una sola fila con el número de

ocurrencias que poseen en la columna de las comisiones un valor distinto

de NULL. Esta función, permite además la inclusión de la palabra

reservada DISTINCT para contar las ocurrencias de valores distintos como

Page 15: Resumen SQL Oracle

Manual de SQL ORACLE

15

se muestra en la siguiente consulta que muestra el número de managers que

existen en la empresa:

SELECT count(distinct mgr) FROM emp;

El resto de funciones no tienen en cuenta el valor NULL, es decir,

cualquier otra función de las especificadas anteriormente (sum, avg, max,

min...) no tienen en cuenta el valor nulo a la hora de realizar los cálculos,

debido a que tampoco aceptan el '*' como un nombre de columna válido.

Si queremos que estas funciones tengan en cuenta los valores nulos,

tendremos que valernos de la función NVL, como se muestra en el

siguiente ejemplo:

SELECT avg(nvl(comm,0)) FROM emp;

En este caso, la media tendrá en cuenta todos los valores nulos, que

serán sustituidos por un cero.

Estas funciones son llamadas "de grupo" debido a que permiten la

inclusión de una nueva cláusula que permite presentar la información por

grupos de datos que tengan características distintivas. Así podremos

agrupar la salida de una consulta que calcule la media del salario para los

distintos departamentos que existen en nuestra empresa. Esto es posible

mediante la cláusula GROUP BY que se añade a la sintaxis original de la

orden SELECT quedando como se muestra a continuación en caso de que

utilicemos funciones de grupo:

SELECT {columna [alias],funcion_de_grupo(columna)}

FROM nombre_tabla

[WHERE condition(s)]

[GROUP BY columna];

Como ejemplo, se mostrará la siguiente consulta:

SELECT deptno, avg(sal) FROM emp GROUP BY deptno;

Que nos mostrará a la salida, la media del salario de cada uno de los

diferentes departamentos que podemos encontrar en nuestra empresa.

DEPTNO AVG(SAL) --------- --------- 10 2916.6667

Page 16: Resumen SQL Oracle

Manual de SQL ORACLE

16

20 2175 30 1566.6667

Tambien podemos agrupar por más de una columna, como se

muestra en la siguiente consulta:

SELECT deptno, avg(sal) FROM emp GROUP BY deptno, job;

Que ofrece la siguiente salida:

DEPTNO AVG(SAL) --------- --------- 10 1300 10 2450 10 5000 20 3000 20 950 20 2975 30 950 30 2850 30 1400 9 rows selected.

Consulta que no tiene mucho sentido si no se muestra el trabajo por

el cual se agrupan los datos, pero se ha realizado de esta manera para

mostrar la posibilidad de hacerlo. En cambio hay que destacar que no se

puede realizar esta consulta sin incluir la cláusula GROUP BY, ya que

Oracle intentará mostrar la media del salario, para todas las tuplas

(ocurrencias) de la tabla, y calcular la media para una sola ocurrencia, lo

cual carece de sentido. Es decir, si incluimos una función de grupo en la

lista de columnas y un(os) nombre(s) de columna simple, debemos agrupar

por ese(os) nombre(s) de columna ya que esta cláusula, debe poseer como

campos de agrupamiento todas las columnas que no estén incluidas en

funciones de grupo. Así, la siguiente consulta sería incorrecta:

SELECT dept.dname, dept.loc, count(empno), avg(sal) FROM emp, dept WHERE emp.deptno=dept.deptno GROUP BY dept.dname;

Y nos ofrecería un mensaje de error a la salida, a no ser que

agrupásemos por nombre de departamento y por localización, en cuyo caso,

ofrecería el número de trabajadores que hay en cada departamento así:

Page 17: Resumen SQL Oracle

Manual de SQL ORACLE

17

SELECT dept.dname, dept.loc, count(empno), avg(sal) FROM emp, dept WHERE emp.deptno=dept.deptno GROUP BY dept.dname;

Consulta que ofrecería a la salida lo siguiente:

DNAME LOC COUNT(EMPNO) AVG(SAL) -------------- ------------- ------------ --------- ACCOUNTING NEW YORK 4 2916.6667 RESEARCH DALLAS 5 2175 SALES CHICAGO 6 1566.6667

Otra de las restricciones a tener en cuenta cuando utilizamos

funciones de grupo, es que no podemos incluir funciones de grupo en la

cláusula WHERE, es decir, no están permitidas consultas como la

siguiente:

SELECT deptno, count(ename)

FROM emp WHERE avg(sal)>2000

GROUP BY deptno;

Para ello se habilita una nueva cláusula, HAVING, que si permite la

inclusión de este tipo de funciones en las agrupaciones de datos. Esta

cláusula siempre se añade al final de la consulta excepto en el caso de que

debamos incluir una cláusula ORDER BY, y se puede utilizar en consultas

como la siguiente:

SELECT deptno, count(ename),avg(sal)

FROM emp WHERE deptno in (10,20)

GROUP BY deptno HAVING avg(sal)>2200;

Esta consulta muestra el numero de empleados en los departamentos

que tienen una media de salario mayor a 2200$ y tan solo para los

departamentos 10 y 20,(la media del salario en el departamento 20 es 2175)

luego la salida será:

DEPTNO COUNT(ENAME) AVG(SAL)

--------- ------------ ---------

10 4 2916.6667

En el siguiente ejemplo, se muestra el numero de manager, y el

salario del empleado peor pagado (salario mínimo) para aquellos

Page 18: Resumen SQL Oracle

Manual de SQL ORACLE

18

empleados que tengan manager (su manager no sea un valor NULL) y

excluyendo aquellos grupos cuyo mínimo salario sea menor de 1000$ y en

orden descendente de salario mínimo:

SELECT mgr, min(sal) FROM emp WHERE mgr is not null GROUP BY mgr HAVING min(sal)>1000 ORDER BY min(sal) desc;

Así la salida es:

MGR MIN(SAL)

--------- ---------

7566 3000

7839 2450

7782 1300

7788 1100

TEMA 6: Subconsultas

Son consultas dentro de la cláusula WHERE de una consulta. Este

tipo de consultas debe devolver un solo valor en cada fila, ya que se

utilizan para la comparación dentro de la cláusula antes indicada. Como

ejemplo, podríamos buscar el nombre y el número del empleado que tenga

el salario mínimo.

Así, deberemos incluir en la cláusula WHERE una comparación con

el salario del empleado que posea el salario mínimo, lo cual se hace de la

siguiente manera.

SELECT ename, empno FROM emp WHERE sal =(SELECT min(sal) FROM emp);

Es de destacar que dentro de la subconsulta no podemos incluir

ninguna cláusula ORDER BY. Si se puede usar sin embargo la cláusula

WHERE para restringir al salida a una sola fila. Por ejemplo podemos

buscar aquellos empleados que posean un salario mayor que el salario que

gana el empleado número 7566 y que tengan el mismo trabajo que el

empleado número 7369 mediante la siguiente consulta:

SELECT ename, job FROM emp

Page 19: Resumen SQL Oracle

Manual de SQL ORACLE

19

WHERE sal>(SELECT sal FROM emp WHERE empno=7566)

AND job like (SELECT job FROM emp WHERE empno = 7369);

De esta manera mediante dos subconsultas podemos hallar los datos

pedidos.

También se puede incluir la cláusula HAVING en una subconsulta,

si utilizamos funciones de grupo de manera que restrinjan la salida a una

sola fila.

Existen casos en los que podemos realizar consultas que devuelvan

más de una fila. En estos casos el criterio de comparación debe ser

mediante uno de los siguientes operadores:

IN: Para que los valores devueltos coincida con uno de los

valores de la lista. Es equivalente a '=ANY'.

ANY: Se utiliza siempre detrás de algún operador de

comparación, tal como <,>,<=,>=,<>,..... e indica que debe ser

comparado con alguno de los valores de la lista.

ALL: Este operador también va precedido de un operador de

comparación (<,>,<=,>=,.....), pero esta vez indica que la

comparación debe cumplirse para todos los valores que

devuelva la subconsulta.

Como ejemplo de lo expuesto anteriormente, vamos a obtener el

nombre y el numero de los empleados que trabajan en un departamento que

tenga algún empleado cuyo nombre contenga una 'T'.

SELECT ename, empno FROM emp WHERE deptno IN (SELECT deptno FROM emp WHERE lower(ename) like lower( '%T%'));

También, como ejemplo vamos a hallar el nombre de los empleados

cuyo salario sea menos que alguno de los empleados cuyo trabajo sea

CLERK así:

SELECT ename, empno FROM emp WHERE sal <ANY (SELECT sal FROM emp WHERE job like 'CLERK');

Page 20: Resumen SQL Oracle

Manual de SQL ORACLE

20

Por último, hallaremos los empleados cuyo salario sea mayor que el

de todos los empleados (mayor que el mayor de todos los salarios) de lso

empleados cuyo trabajo sea CLERK de la siguiente manera:

SELECT ename, empno FROM emp WHERE sal >ALL (SELECT sal FROM emp WHERE job like 'CLERK');

TEMA 7:Subconsultas que devuelven múltiples columnas

Este tipo de consultas, son similares a las anteriores, pero en este

caso se devuelven varias columnas, no solo una. La forma de hacerlo,

normalmente es incluyendo entre paréntesis los dos campos o columnas

con las que se pretende comparar la salida de la subconsulta, ya que en el

caso de necesitar una consulta de este tipo, podremos encontrarnos con

varias posibilidades. La primera de ellas es el caso mencionado en el que

necesitamos que coincidan ambas columnas (matches both) que se llama

'Pairwise', y el segundo caso es en el que necesitemos que coincida alguno

de los campos o columnas con la restricción a imponer, llamada 'Non-

pairwise'. Vamos a citar dos ejemplos, uno para cada tipo.

En primer lugar, hallaremos el nombre, el numero de departamento y

la comisión de aquellos empleados cuyo salario y comisión coinciden

ambos a la vez con el salario y la comisión de algún empleado del

departamento 30:

SELECT ename, deptno, comm FROM emp where (sal, nvl(com,-1)) in (SELECT sal, nvl(comm,-1) FROM emp WHERE deptno=30);

Este es un ejemplo de Pairwise, en el que las columnas o campos

deben compararse por pares, es decir debe coincidir la pareja de valores de

salario y comisión de un empleado con la pareja salario y comisión de un

empleado del departamento 30. Es de destacar el uso de la función NVL

para evitar los valores nulos, ya que cualquier operación entre dos valores

nulos da como resultado el valor nulo, luego en la comparación de igualdad

entre dos valores nulos, nos daría falso (null=null ->null -falso-).

Como ejemplo de Nonpairwise, podemos encontrar una consulta

como:

SELECT ename, job

Page 21: Resumen SQL Oracle

Manual de SQL ORACLE

21

FROM emp WHERE sal>(SELECT sal

FROM emp WHERE empno=7566)

AND job like (SELECT job FROM emp WHERE empno = 7369);

Anteriormente descrita, y que pretende buscar aquellos empleados

que posean un salario mayor que el salario que gana el empleado número

7566 y que tengan el mismo trabajo que el empleado número 7369.

Las subconsultas no solo pueden estar en la cláusula WHERE,

también podemos tener subconsultas dentro de la cláusula FROM, donde se

crea una nueva tabla que contendrá las columnas y las filas que devuelva la

consulta realizada. Para ilustrar esto, vamos a realizar una consulta que

muestre el número de empleado, el departamento al que pertenece, y la

media del salario de dicho departamento. En un principio, podemos pensar

que la siguiente consulta obtiene dichos valores:

SELECT empno, deptno, avg(sal) FOM emp GROUP BY empno, deptno;

Pero esto es incorrecto, ya que intentará calcular la media para un

grupo por cada número de empleado (empno), y la salida será incorrecta.

Sin embargo, podemos calcular la media para cada departamento, incluirla

en una tabla, y asociarla con cada empleado. Así, deberemos crear la

siguiente consulta:

SELECT empno, deptno, avg.media FROM emp, (SELECT deptno, avg(sal) media FROM emp GROUP BY deptno) avg WHERE emp.deptno=avg.deptno;

Donde como se puede comprobar, la subconsulta de la cláusula

FROM, crea una tabla llamada 'avg', que contiene la media del salario de

cada departamento.

TEMA 8: Operadores de conjunto

En este tema se analizan los operadores de conjunto 'intersect',

'union', 'union all' y 'minus'. Estos operadores, nos permiten tomar las

consultas por conjuntos de tuplas, que tienen varias columnas. Así,

podemos hallar la intersección, la resta, o la union de los elementos de cada

conjunto. La descripción de cada operación, es la siguiente:

Page 22: Resumen SQL Oracle

Manual de SQL ORACLE

22

Intersect: Devuelve los elementos comunes a dos conjuntos,

es decir las tuplas que coinciden en dos consultas distintas.

Hay que tener en cuenta, que para que pueda haber una

intersección, ambas consultas deben seleccionar las mismas

columnas.

Union / Union all: Estos operadores actúan de forma muy

similar, ambos devuelven la salida de una consulta más la

salida de otra. La diferencia es que el primero, no incluye

elementos repetidos, sin embargo, 'Union all' si incluye estos

elementos repetidos.

Minus: Este operador, devuelve las tuplas de la primera

consulta menos las tuplas de la segunda consulta.

Como ejemplo de consultas, podemos mostrar todos los empleados

que han trabajado en la empresa, ayudándonos de la tabla 'emp_history' que

contiene el historial de todos los trabajadores que hay y han habido en la

empresa, así, tendremos:

SELECT ename,job, deptno FROM emp UNION SELECT name,title,deptid FROM emp_history;

Otro ejemplo del uso de este tipo de operadores nos permite mostrar

aquellos empleados que están en ambas tablas a la vez de la siguiente

manera: SELECT ename,job, deptno FROM emp INTERSECT SELECT name,title,deptid FROM emp_history;

También podemos encontrar aquellos que tendríamos que introducir

en la tabla de la siguiente manera:

SELECT ename,job, deptno FROM emp MINUS SELECT name,title,deptid FROM emp_history;

Así, para realizar este tipo de consultas, tenemos que tener en cuenta

los siguientes puntos:

Page 23: Resumen SQL Oracle

Manual de SQL ORACLE

23

Las expresiones de las consultas tienen que coincidir en

cantidad y tipo de los datos que se van a mostrar (ej: ename ->

name).

Automáticamente en todos los operadores de conjuntos las

filas repetidas son borradas (en la salida y excepto en el

operador 'union all')

Los encabezamientos de las filas que se ofrecen a la salida son

los de la primera consulta realizada.

TEMA 9: Manipulación de datos

El lenguaje de manipulación de datos es el que nos permite tanto la

inserción como el borrado de los datos en las tablas de que dispone nuestra

base de datos. Asi, se definen varias ordenes que permiten realizar este tipo

de acciones.

Añadir una nueva fila en la tabla:

INSERT INTO tabla[(columa[, columna,....])] VALUES (valor[, valor, ......]); [consulta]

Si se omiten los campos después del nombre de la tabla, es que

deseamos introducir una fila con todos los campos que contiene la tabla, y

si lo que añadimos es una consulta, se introducen los datos devueltos por

esa consulta.

Así, como ejemplo, podemos incluir una fila en la tabla 'dept' que

contenga el número de departamento 50, llamado 'development' y

localizado en 'detroit', así deberemos introducir la siguiente orden de

entrada de datos:

INSERT INTO dept(deptno,dname,loc) VALUES (50,'DEVELOPMENT','DETROIT');

Se pueden crear macros para la introducción de los datos, y usar asi

variables para la introducción de estos datos. Para ello, utilizamos el

comando ACCEPT, que nos permite declarar una variable de entorno con

un nombre cualquiera:

ACCEPT nombre_variable PROMPT 'mensaje_introducción';

Page 24: Resumen SQL Oracle

Manual de SQL ORACLE

24

Esta orden, nos permite sacar por pantalla el mensaje

'mensaje_introducción' y despues quedar a la espera de la introducción del

valor que se asignará a la variable nombre_variable. Asi, un ejemplo de

macro para realizar la introducción de la fila que se ha introducido antes es:

ACCEPT num_dept PROMPT 'introduzca el número de depto.: '; ACCEPT nom_dept PROMPT 'introduzca el nombre de depto.: '; ACCEPT loc_dept PROMPT 'introduzca la localización de depto.: '; INSERT INTO dept(deptno,dname,loc) VALUES (&num_dept,'nom_dept','loc_dept');

Esto provocará la siguiente salida por pantalla:

SQL> @a:/p2ej.sql introduzca el número de depto.: 50 introduzca el nombre de depto.: DEVELOPMENT introduzca localizacion de depto.: DETROIT old 2: VALUES (&num_dept,'nom_dept','locdept') new 2: VALUES (50,'nom_dept','locdept') 1 row created. SQL>

Habiendo guardado previamente esta macro en el archivo p2ej.sql en

la ruta especificada. Es de destacar, que las variables, se deben referenciar

mediante el '&' delante del nombre de variable y las cadenas además entre

comillas simples.

Modificacion de datos en la tabla:

Para la modificación de datos de la tabla se usa el mandato UPDATE

de la siguiente manera:

UPDATE nombre_tabla

SET columna=valor [, columna2=valor2, .....]

[WHERE condicion]

En este caso, substituimos el valor de la columna especificada por el

valor introducido. La sentencia WHERE, es opcional, y si se omite, se

modificarán todos los valores de la(s) columna(s) especificada(s) pero si se

especifica, la modificación tendrá lugar tan solo en la fila que se seleccione

según la condición. También es posible especificar una macro que realice

Page 25: Resumen SQL Oracle

Manual de SQL ORACLE

25

esta acción, de la misma manera en la que se realizó en la sentencia de

manipulación anterior.

Eliminación de datos en la tabla:

Para la eliminación de datos de una tabla de nuestra base de datos, se

utiliza el comando DELETE. La sintaxis de dicho comando es la siguiente:

DELETE [FROM] nombre_tabla

[WHERE condición];

Este comando posee la posibilidad de borrar una sola fila de la tabla,

añadiendo las opciones FROM, y WHERE, ya que se eliminaran las filas

de la tabla que cumplan la condición especificada en la sentencia WHERE,

pero si estas opciones no se incluyen, se vacía la tabla al completo.

Existen una serie de ordenes, que nos permiten una gran seguridad

dentro de las bases de datos creadas con Oracle y que son los comandos

commit, savepoint y rollback:

COMMIT: este comando, verifica que las modificaciones

realizadas se guardan en la base de datos. Así tras realizar

cualquier cambio en esta, mediante el DML (Data

Modification Languaje) deberemos ejecutar dicho comando.

SAVEPOINT nombre_savepoint: Permite realizar una copia

de seguridad de los datos guardados en las tablas hasta el

momento para luego poder recuperarlos. Se puede indicar el

nombre (por ejemplo la fecha y hora) del punto de guardado.

Mediante otro comando, podemos volver a los datos que

teníamos antes de guardar mediante SAVEPOINT.

ROLLBACK / ROLLBACK TO nombre_savepoint: Permite

volver atrás en los cambios realizados en una tabla. cuando

ejecutamos este comando, deshacemos los cambios realizados

hasta el último savepoint. Si queremos volver atrás hasta un

determinado savepoint, deberemos especificar el savepoint

hasta el que queremos volver, mediante la segunda opción de

este comando.

Como ejemplo citamos:

SQL> savepoint update_done; Savepoint created. SQL> rollback to update_done;

Page 26: Resumen SQL Oracle

Manual de SQL ORACLE

26

Rollback complete. SQL>

TEMA 10: Creación de tablas.

Create table

Para la creación de tablas, se utiliza la orden CREATE TABLE, que

tiene varias opciones que iremos viendo poco a poco. La sintaxis básica de

esta orden es:

CREATE TABLE [esquema.]nombre_tabla [(columna tipo_de_dato [default_expr])];

De esta manera, creamos una tabla con el nombre indicado, y las

columnas indicadas si se desea. Si no se desea definir las columnas se

puede realizar más adelante con el comando ALTER TABLE que veremos

más adelante. Los tipos de datos a los que puede pertenecer una columna

son entre otros:

1. VARCHAR2(tamaño): texto de tamaño variable.

2. CHAR(tamaño): carárcter de tamaño variable.

3. NUMBER(p,s): número de tamaño fijo, donde 'p' es el tamaño

máximo, y 's' el número de bits después de la coma.

4. DATE: tipo de dato fecha.

5. LONG: Cadena de caracteres de longitud variable hasta 2GB.

6. CLOB: Cadena de caracteres de longitud variable hasta 4GB.

7. RAW y LONG RAW: Datos binarios de tamaño pequeño.

8. BLOB: Datos binarios de hasta 4GB.

9. BFILE: Para ficheros externos.

10. BINARY: Para valores binarios (verdadero,falso).

Por ejemplo, podemos citar la orden de creación de la tabla 'dept',

que es la siguiente:

CREATE TABLE dept (deptno NUMBER(2), dname VARCHAR2(14), loc VARCHAR2(13));

También podemos crear tablas a partir de subconsultas, mediante

esta misma orden, pero en este caso, la sintaxis es la siguiente:

Page 27: Resumen SQL Oracle

Manual de SQL ORACLE

27

CREATE TABLE AS subconsulta;

Asi se crea una tabla que contiene todas las columnas que devuelva

la consulta realizada en esta orden, y con todas las tuplas que devuelva esta

orden. Como ejemplo vamos a crear una tabla llamada 'dept30' que

contendrá todos los empleados de dicho departamento, y las columnas

empno, ename, y sal:

CREATE TABLE deptno30 AS SELECT empno, ename, sal FROM emp WHERE deptno=30;

Alter table

Esta orden, nos permite modificar las columnas de una tabla, para

añadir o para modificar el tipo de dato de la columna en cuestión. La

sintaxis de la sentencia ALTER TABLE es la siguiente:

ALTER TABLE nombre_tabla ([ADD (columna tipo_de_dato)], [MODIFY (columna nuevo_tipo_de_dato)]);

Drop table

Esta elimina la estructura de la tabla por completo, y por tanto la

borra por completo. La sintaxis de esta sentencia es la siguiente:

DROP TABLE nombre_tabla;

Truncate table

Esta orden vacía el contenido de la tabla, es decir borra todas las filas

que contiene, pero deja la estructura. La sintaxis es la siguiente:

TRUNCATE TABLE nombre_tabla;

Rename table

En este caso la orden cambia el nombre de la tabla por el

especificado mediante la siguiente sintáxis:

Page 28: Resumen SQL Oracle

Manual de SQL ORACLE

28

RENAME nombre_tabla_antiguo TO nombre_tabla_nuevo;

Comment on table

En este caso se le añaden comentarios a las tablas, que permiten

describir el contenido de las mismas. Esto se realiza con la orden

Comment, que tiene la siguiente sintaxis:

COMMENT ON TABLE nombre_tabla IS 'comentario de la tabla';

Restricciones de las tablas (constraints)

Existen varias restricciones posibles para las columnas de las bases

de datos mantenidas por Oracle, estas son llamadas 'constraints' y

permiten cualidades de las columnas de una tabla tales como hacer cumplir

reglas a nivel de tablas, o prevenir el borrado de una tabla si hay

dependencias con otra tabla. Los tipos de restricciones posibles en

Oracle son:

NOT NULL: Especifica que esa columna no debe contener un

valor nulo.

UNIQUE key: Especifica una columna o combinación de ellas

cuyos valores no deben estar repetidos.

PRIMARY KEY: Especifica que debe ser llave primaria, por

lo tanto, esta, no debe contener valores duplicados, ni poseer

valores nulos.

FOREIGN KEY: Establece y hace cumplir una relación

foránea entre la columna, y la otra columna referenciada de la

tabla.

CHECK: Especifica una condición que debe ser cierta.

La sintaxis de creación de una constraint en una tabla es la siguiente:

CREATE TABLE [esquema.]nombre_tabla [(columna tipo_de_dato [default_expr] [constraint de columna], ........... [constraint de tabla])];

Page 29: Resumen SQL Oracle

Manual de SQL ORACLE

29

Donde el constraint de columna, es una constraint formada por la

palabra clave constraint, seguido de un nombre orientativo que entra en la

tabla 'user_constraints' (esto es opcional pero recomendable), y después el

tipo_constraint, que es uno de los tipos antes definidos (NOT NULL,

PRIMARY KEY,.....) de la siguiente manera:

[CONSTRAINT constraint_name] tipo_constraint, Las constraints de tabla, no incluyen la constraint NOT NULL, van

siempre al final, y el añadir el nombre de la constraint es también opcional.

Se forma mediante la palabra reservada CONSTRAINT y el nombre de

constraint (opcional), después el tipo de constraint a aplicar (excepto NOT

NULL) y entre paréntesis el nombre de la columna a la que se aplica dicha

constraint. Hay que tener en cuenta que estos tipos de constraints se ponen

siempre después de haber definido todas las columnas de la tabla:

[CONSTRAINT constraint_name] tipo_constraint (nombre_columna,...),

Así como ejemplo, introduciremos la constraint que posee la tabla

dept, que es NOT NULL en la columna 'deptno' de la siguiente manera:

CREATE TABLE dept (deptno NUMBER(2) CONSTRAINT dept_nn NOT NULL, dname VARCHAR2(14), loc VARCHAR2(13));

Por otro lado, podemos definir algunas de las constraints de la tabla

emp de la siguiente manera:

CREATE TABLE emp (empno NUMBER(4), ename VARCHAR2(10), .... deptno NUMBER(7,2) NOT NULL, CONSTRAINT emp_empno_pk

PRIMARY KEY (empno) CONSTRAINT emp_deptno_fk FOREIGN KEY (deptno)

REFERENCES dept (deptno) CONSTRAINT emp_deptno_ck CHECK

Page 30: Resumen SQL Oracle

Manual de SQL ORACLE

30

(deptno BETWEEN 10 AND 99));

Se puede observar que todas estas son líneas de la creación de una

tabla, que por lo tanto pueden añadirse mediante la orden ALTER TABLE,

para añadir dichas constraints posteriormente a las tablas. Así podríamos

poner también, una vez creada la tabla sin constraints:

ALTER TABLE emp ADD CONSTRAINT emp_empno_pk

PRIMARY KEY (empno);

Para borrar cualquier constraint, se utiliza la orden ALTER TABLE,

que actúa de igual manera que anteriormente, pero ahora, deberemos

indicar que queremos borrar y la constraint que queremos borrar, mediante

el nombre que le hemos asociado. Así, la orden de borrado de esta última

constraint 'emp_empno_pk' es:

ALTER TABLE emp DROP CONSTRAINT emp_empno_pk;

También podemos deshabilitar dicha constraint, en vez de borrarla,

mediante la siguiente orden:

ALTER TABLE emp DISABLE CONSTRAINT emp_empno_pk;

TEMA 11: Vistas y secuencias. Objetos de la base de datos.

Dentro de los objetos de una base de datos de Oracle, hemos visto

tan solo las tablas, pero también existen objetos tales como vistas,

secuencias, índices y sinónimos. En este documento nos centraremos tan

solo en las tablas, como ya se ha hecho, en las vistas y secuencias.

Vistas

Una vista crea un subconjunto de datos a partir de una tabla. Sirve

para tener un acceso más rápido a una determinada tabla, para dar acceso

solo de lectura a un usuario de las tablas etc. Existen dos tipos de vistas ,

simples y compuestas.

Las vistas simples, contienen una sola tabla, y no contiene funciones,

ni grupos de datos, así como DML (data modification languaje) a través de

Page 31: Resumen SQL Oracle

Manual de SQL ORACLE

31

la vista. En cambio, las vistas complejas, contienen más de una tabla, y

contienen el resto de características antes mencionadas.

La orden de creación de una vista es mediante la orden CREATE,

vista anteriormente. Así la sintaxis es la siguiente:

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

nombre_vista AS (subconsulta)

[WITH CHECK OPTION [CONSTRAINT constraint]]

[WITH READ ONLY];

Las opciones dignas de comentario, son:

OR REPLACE: vuelve a crear la vista, incluso si esta existe o

no.

FORCE | NO FORCE: Crea la vista incluso si las tablas base

de la consulta que se realiza existen o no (en el caso de que

incluyamos FORCE) o no crea la vista en caso de que no

existan dichas tablas (si incluimos la opción NO FORCE).

WITH CHECK OPTION: Especifica que solo las filas

accesibles a la vista, pueden ser insertadas o modificadas.

WITH READ ONLY: Asegura que ningún tipo de DML

puede ser utilizado en esta vista (luego ninguna modificación

de los datos puede ser realizada).

Así como ejemplo vamos a crear una vista llamada EMPVU10 que

contenga el numero de empleado, el nombre y el trabajo, de todos los

empleados que pertenecen al departamento 10.

CREATE OR REPLACE VIEW empvu10 AS SELECT empno, ename, job FROM emp WHERE deptno=10;

De esta manera creamos una vista con las características antes

mencionadas. Para ver el contenido de dichas vistas, utilizamos una orden

SELECT en la que el nombre de la tabla será un nombre de vista. También

podemos ver la estructura de una vista mediante la orden DESCRIBE. Para

ver las vistas que tenemos creadas, existe la tabla user_views, en cuya

columna view_name, podemos encontrar todos los nombres de vistas que

tengamos creadas.

Una vista compuesta puede ser una vista tal como la siguiente:

CREATE VIEW dept_sum_vu (name,minsal,avgsal)

Page 32: Resumen SQL Oracle

Manual de SQL ORACLE

32

AS SELECT d.dname, MIN(e.sal), MAX(e.sal), AVG(e.sal) FROM emp e, dept d WHERE e.deptno=d.deptno GROUP BY d.dname; Orden que crea una vista que contendrá un campo (columna) que

será el nombre de departamento, otra columna con el salario mínimo del

departamento, otra con el salario máximo del departamento y otra con la

media del salario del departamento.

Se pueden usar operaciones DML en vistas simples. No se pueden

borrar filas si contienen funciones de grupo, una cláusula GROUP BY o la

palabra clave DISTINCT.

Para borrar una vista, se utiliza la orden DROP VIEW nombre_vista.

Secuencias

Una secuencia genera automáticamente números consecutivos. Es un

objeto ocultable y típicamente usado para crear valores de llaves primarias.

Se crean mediante la orden CREATE con la siguiente sintaxis.

CREATE SEQUENCE nombre_secuencia [INCREMENT BY n]

[START WITH n] [MAXVALUE n | NOMAXVALUE] [MINVALUE n | NOMINVALUE] [CYCLE | NOCYCLE];

Por la simple traducción de las palabras clave que se usan como

opciones de la sentencia de creación, podemos determinar la función de las

mismas. Como ejemplo vamos a crear una secuencia llamada dept_deptno

usada por la primary key de la tabla dept:

CREATE SEQUENCE dept_deptno INCREMENT BY 1 START WITH 91 MAXVALUE 100 NOCACHE

NOCYCLE;

Para hacer referencia a los valores de una secuencia, deberemos

introducir el nombre de la secuencia, seguido de un punto, y después una

de las siguientes opciones:

NEXTVAL: Accede al próximo valor disponible.

Page 33: Resumen SQL Oracle

Manual de SQL ORACLE

33

CURRVAL: El valor actual en el que se encuentra la

secuencia.

Como ejemplo utilizaremos la secuencia para añadir una nueva fila a

la tabla dept utilizando la secuencia antes creada.

INSERT INTO dept(deptno, dname, loc) VALUES (dept_deptno.NEXTVAL, 'MARKETING','SAN

DIEGO');

Para ver el valor actual de la secuencia que deseemos, tan solo

deberemos realizar una consulta con la tabla 'DUAL', en la que

referenciemos el valor actual de una secuencia, es decir, para consultar el

valor actual de la secuencia que acabamos de crear, deberemos introducir la

siguiente orden:

SELECT dept_deptno.CURRVAL FROM dual;

Tambien es posible tanto la modificación de la secuencia, así como

el borrado de la misma, mediante las ordenes ALTER SEQUENCE y

DROP SEQUENCE.

TEMA 12: Bloques PL/SQL básicos.

Esta lección presenta la estructura básica de un bloque de código

PL/SQL. Estos bloques de código son una especie de scripts, que se

transfieren por completo al SGBD y son ejecutados por completo, lo cual

permite una secuenciación entre las distintas consultas y acciones sobre la

base de datos. La estructura básica de un bloque de código SQL consta de

las siguientes dos partes principales que comienzan con las siguientes

palabras reservadas:

'DECLARE' (opcional): A Partir de esta se declaran las

variables, los cursores, y las excepciones (errores) declaradas

por el usuario.

'BEGIN': Después de esta palabra, comienza la segunda parte

y en ella se incluyen los mandatos SQL y PL/SQL.

'EXCEPTION' (opcional): A partir de esta palabra reservada

se incluye la definición de las excepciones del bloque

PL/SQL.

'END;' : Esta es la palabra final después de la cual, no hay más

código.

Page 34: Resumen SQL Oracle

Manual de SQL ORACLE

34

Se debe colocar un punto y coma (;) después de cada sentencia SQL

o PL/SQL y una barra invertida (/) para poder ejecutar el bloque.

Existen varios tipos de bloques PL/SQL, anónimos, procedimientos

y funciones. Los bloques anónimos son bloques sin nombre empotrados

dentro de una aplicación o emitidos para su ejecución interactivamente. El

resto, tanto los procedimientos, como las funciones, son bloques de código

PL/SQL que quedan grabados en el servidor de Oracle, pueden ser

invocados repetidamente por su nombre y pueden aceptar parámetros.

Comencemos describiendo las variables. Estas son utilizadas para

guardar datos temporalmente, manipular estos datos etc. Para su

manipulación, debemos declararlas, le asignamos un valor, pasamos los

valores y vemos los resultados. También se pueden declarar variables

globales, lo cual se realiza antes de la palabra reservada DECLARE. Para

la declaración de variables se usa la siguiente sintaxis:

nombre_variable tipo_de_dato;

Y para las variables globales (BIND), se realiza mediante la

siguiente sintaxis:

VARIABLE nombre_variable tipo_de_dato Este tipo de variables, se declaran fuera del bloque de código

PL/SQL, y se pueden referenciar dentro de este poniendo dos puntos antes

del nombre de la variable.

El operador de asignación de valores a una variable es ':=', poniendo

primero el nombre de la variable a la cual queremos asignar el valor,

después el símbolo ':=' y después el valor que queremos asignarle, que

puede ser el valor de otra variable por ejemplo.

Para imprimir por pantalla, siempre hay que declarar variables

globales, y estas se referencian dentro del bloque PL/SQL añadiendo dos

puntos (:) antes del nombre de la variable, ej: ':v_ejemplo'. El resto de las

variables no pueden ser aceptadas como parámetro de la orden 'PRINT' (La

orden PRINT, seguida de un nombre de variable y un punto y coma

muestra el contenido de la variable por pantalla, y el nombre de la variable

que posee dicho valor.).

El uso de las variables esta restringido únicamente por el tipo de

datos al que pertenece una determinada variable. Es decir, es importante

asignar a una variable, datos del tipo al cual pertenecen, por lo que es útil la

utilización de funciones antes comentadas como 'to_char()', para pasar un

tipo de dato fecha ('date') a cadena por ejemplo si vamos a asignarlo a una

Page 35: Resumen SQL Oracle

Manual de SQL ORACLE

35

cadena. Por ejemplo, si declaramos la variable 'v_cadena' de tipo varchar2

así:

DECLARE v_cadena varchar2(30); ......... Y a continuación escribimos en la parte de código ejecutable:

BEGIN v_cadena:='Anderson'||':'||sysdate; ...........

Esto daría un error, ya que sysdate, es de tipo 'date', con lo que el

bloque no se ejecutaría correctamente. Así, la correcta formulación que

deberíamos realizar para esta acción sería:

BEGIN v_cadena:='Anderson'||':'||to_char(sysdate); ...........

Nótese que se han utilizado comillas simples para delimitar los

valores de cadenas constantes, el operador '||' para concatenar cadenas, y un

punto y coma al final de la sentencia.

Hasta aquí se ha visto lo mas importante que debemos saber sobre

las variables, a partir de ahora describiremos las acciones básicas que se

pueden realizar con un bloque de código PL/SQL.

Los bloques de código se pueden anidar. Es decir podemos incluir

un bloque de PL/SQL dentro de otro, pero hay que tener cuidado con el

ámbito de las variables que declaramos, es decir, las variables declaradas

en el bloque más exterior, se 'ven' dentro de los bloques de código

interiores, pero esto no es cierto al contrario, es decir, las variables de los

bloques interiores, no pueden referenciarse por los bloques externos.

La orden para pedir datos por pantalla se ha explicado en temas

anteriores, esta es la orden 'accept' que debe ponerse fuera de los bloques

PL/SQL, con la siguiente sintaxis:

ACCEPT nombre_variable PROMPT 'mensaje_introducción'; De esta manera se introducen datos en una variable de entorno, que

podemos utilizar luego. Para borrar todas las variables de entorno que

tengamos creadas, deberemos introducir la orden 'set verify off'. Para

referenciarlas, se incluye un '&' antes del nombre de dicha variable.

Page 36: Resumen SQL Oracle

Manual de SQL ORACLE

36

Para la salida de datos por pantalla, se utiliza la orden

dbms_output.put_line con la siguiente sintaxis:

dbms_output.put_line({'cadena_a_mostrar',variable_de_cadena});

Dentro de los bloques de PL/SQL, podemos escribir diferentes tipos

de consultas. El mandato select que podemos introducir dentro de un

bloque de código debe incluir después de la lista de columnas a mostrar

(SELECT *) la palabra reservada INTO nombre_variable, para introducir

los datos dentro de la variable que se especifique. Así la sintaxis de un

mandato select básico queda de la siguiente manera:

SELECT [DISTINCT] {*, columna [alias],...}

INTO {lista_de variables}

FROM nombre_tabla

[WHERE condition(s)];

Así, podemos deducir que la lista de variables, debe corresponderse

con el número y el tipo de las columnas que estemos seleccionando, para

que sean asignadas a las variables correctamente. También debemos notar

que estos mandatos select, deben devolver tan solo una fila, es decir que

debemos incluir una condición que haga que la consulta devuelva una sola

fila en el momento de ser ejecutada.

Ahora ya estamos preparados para ver el primer ejemplo de bloque

PL/SQL mediante el cual obtendremos el número y la localización de el

departamento de ventas (sales) de la tabla dept así:

DECLARE v_deptno dept.deptno%TYPE; v_loc dept.loc%TYPE; BEGIN select deptno,loc into v_deptno,v_loc from dept where dname='SALES';

dbms_output.put_line(v_deptno); dbms_output.put_line(v_loc); END; /

Que ofrece a la salida el siguiente mensaje:

Page 37: Resumen SQL Oracle

Manual de SQL ORACLE

37

SQL> @a:/plsql1.sql 30 CHICAGO PL/SQL procedure successfully completed. SQL> Se debe de destacar que el tipo de dato al cual pertenecen las

variables declaradas v_deptno y v_loc, es el tipo de dato de las variables

detpno y loc de la tabla dept.

Vamos a realizar ahora una inserción de datos en una tabla mediante

un bloque PL/SQL para ver más ejemplos:

DECLARE v_empno emp.empno%TYPE; BEGIN select empno_secuence.NEXTVAL into v_empno from dual; insert into emp(empno, ename, job, deptno) values (v_empno,'Harding','clerk', 10); END; / Suponiendo que ya tenemos creada la secuencia empno_sequence,

que nos devuelve el valor correcto de número de empleado. Es de notar el

uso de la variable declarada como valor a introducir en la orden insert.

Dentro de las ordenes de un bloque PL/SQL también existen

sentencias de control del flujo del programa y dentro de ellas vamos a

comenzar con el mandato IF. Este mandato tiene la siguiente sintaxis:

IF condición THEN

sentencias_1;

[ELSIF condición THEN

sentencias_2;]

[ELSE

sentencias_3;]

ENDIF;

Siendo el control de flujo el mismo para todos los lenguajes que

poseen una sentencia de bifurcación condicional, es decir , se ejecutarán

la(s) sentencia(s) 1 en caso de cumplirse las primeras condiciones, o las

Page 38: Resumen SQL Oracle

Manual de SQL ORACLE

38

sentencias 2 en caso de que se cumplan las segundas condiciones, o si no se

cumplen ningunas de las condiciones, se ejecutaran las sentencias 3.

Así, podemos realizar bloques de código que realicen acciones en

función de el cumplimiento de ciertas condiciones.

Otro tipo de sentencias de control del flujo de ejecución son los

bucles, dentro de los cuales podemos encontrar bucles tales como LOOP,

FOR y WHILE. La sintaxis de estos bloques de código es la siguiente:

LOOP sentencias: ... EXIT [WHEN condición]; END LOOP;

Para la orden FOR tenemos la siguiente sintaxis:

FOR contador IN [REVERSE] limite_inferior..limite_superior LOOP sentencias; ... END LOOP; Y para la orden WHILE tenemos la siguiente sintaxis:

WHILE condicion LOOP sentencias; ... LOOP;

TEMA 13: Tipos de datos compuestos

Existen dos tipos de datos compuestos que son:

RECORDS: Son un tipo de datos definido por el usuario, que

contiene varias variables en una sola estrucutura. Es similar a

un 'struct' de C.

TABLES: Son un tipo de dato similar a una tabla, o a un array,

en el que se introducen datos de un solo tipo y luego podemos

acceder a ellos segun un índice.

Así, la sintaxis para definir estos tipos de datos es la siguiente, para

los records:

Page 39: Resumen SQL Oracle

Manual de SQL ORACLE

39

TYPE type_name IS RECORD (nombre_variable1 tipo_de_dato,

[nombre_variable2 tipo_de_dato,...]);

Y para declarar un record de ese tipo se pone:

nombre_record type_name;

En ese momento ya podemos utilizar el record mediante la inclusión

de un punto, seguido del nombre de la variable que deseamos acceder.

Para las TABLES, que son parecidas a los arrays, tenemos la

siguiente sintaxis:

TYPE type_name IS TABLE OF {(tipo_columna),variable%TYPE} [INDEX BY BINARY INTEGER];

Así, tenemos un array al cual podemos acceder mediante un índice

que se pone entre paréntesis. También tenemos una serie de métodos

asociados a las TABLES, que nos permiten realizar acciones como:

EXISTS(n): devuelve verdadero si el valor del índice que

contenga no el nulo, es decir tiene asignado algún valor.

COUNT: devuelve el número de elementos que posee la Table

FIRST and LAST: Devuelve el valor final o el inicial,

dependiendo del método utilizado.

PRIOR(n): Devuelve el elemento anterior al indicado en el

índice.

NEXT(n): Devuelve el siguiente elemento del indicado por el

índice.

EXTEND(n,i): agrega valores 'i', a partir de 'n'.

TRIM(n): Elimina los 'n' últimos valores.

DELETE[(n,m)]: Si no lleva índices, vacía la TABLE entera,

si lleva un solo índice borra el elemento indicado, y si lleva los

dos índices, borra desde el indice 'n' hasta el índice 'm'.

Vamos a ver dos ejemplos de utilización de estos tipos de datos.

Para los tipos de datos RECORD, declararemos uno que almacenará el

nombre, el trabajo, u el salario, de un nuevo empleado:

TYPE emp_record_type IS RECORD (ename VARCHAR2(10),

Page 40: Resumen SQL Oracle

Manual de SQL ORACLE

40

job VARCHAR2(9), sal NUMBER(7,2));

En este momento tendríamos definido el tipo de dato

emp_record_type, y ahora crearíamos una instancia de ese tipo de dato

llamado emp_record:

emp_record emp_record_type;

Para el uso de los distintos campos que contiene la variable que

acabamos de declarar, podemos acceder por ejemplo al nombre de la

siguiente manera: 'emp_record.ename'.

Existe un atributo especial, llamado %ROWTYPE que recoge un

dato que puede poseer más de un atributo y asignarlo a un tipo record, así,

para crear un record con todas las variables necesarias para guardar una fila

completa de la tabla dept, deberíamos poner:

dept_record dept%ROWTYPE;

Para declarar una table, seguiremos la sintaxis antes definida, y

crearemos una table para almacenar nombres de empleados contenidos en

la tabla emp así:

TYPE ename_table_type IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;

Ya tendríamos creado el tipo de TABLE ename_table_type, que

ahora es un tipo de dato más, y ahora necesitamos una instancia, o variable

de ese tipo, así:

ename_table ename_table_type;

Ahora nos referiremos a los distintos elementos de dicha variable así

ename_table(1):='Cameron';

O también podremos acceder a alguno de los métodos antes

especificados para realizar acciones como la siguiente:

IF ename_table.EXISTS(1) THEN INSERT INTO...........

Page 41: Resumen SQL Oracle

Manual de SQL ORACLE

41

TEMA 14: Cursores

Un Cursor es un área de trabajo de SQL. Cuando emitimos una

sentencia SQL, el servidor de Oracle abre un área de memoria, en la que el

comando es analizado y ejecutado, este área es llamada cursor. Cuando la

parte ejecutable de un bloque emite una sentencia SQL, PL/SQL crea un

cursor implícito, que tiene el identificador 'SQL'. Oracle cuenta con dos

tipos de cursores, los explícitos y los implícitos, los implícitos están

definidos por el identificador 'SQL', y posee atributos que entre otros son:

SQL%ROWCOUNT: cuenta el número de filas que fueron

accedidas en la última operación.

SQL%FOUND: Posee el valor TRUE si el cursor anterior es

igual o mayor que uno, es decir, que se pone a valor TRUE si

se a accedido a alguna fila.

SQL%NOTFOUND: Poseerá el valor TRUE en el caso de que

el cursor anterior tenga el valor FALSE, es decir este cursor

toma el valor TRUE si en la última operación no se accedió a

ninguna fila.

SQL%ISOPEN: Posee siempre el valor FALSO, porque

PL/SQL cierra los cursores explícitos inmediatamente después

de ser ejecutados.

Como ejemplo de uso de un cursor explícito, expongo el siguiente

boque PL/SQL que imprime el número de columnas que han sido borradas:

VARIABLE rows_deleted NUMBER DECLARE v_ordid NUMBER:=605; BEGIN DELETE FROM item WHERE ordid=v_ordid; :rows_deleted:=SQL%ROWCOUNT; END; / PRINT rows_deleted

Los cursores explícitos sin embargo, son definidos por el usuario, y a

la zona de memoria, le asignamos una sentencia SELECT. Para controlar

un cursor explícito, debemos seguir los siguientes pasos:

1. Declaramos el cursor en DECLARE.

2. Se abre el cursor con OPEN, y estamos en la primera posición.

Page 42: Resumen SQL Oracle

Manual de SQL ORACLE

42

3. Leemos la primera fila con FETCH.

4. Comprobamos si ha leído algo, y cerramos el cursor con

CLOSE.

La sintaxis de declaración de un cursor, es la siguiente:

CURSOR nombre_cursor IS SELECT [lista_de variables] FROM nombre_tabla;

Donde la sentencia SELECT, es una sentencia cualquiera, que puede

incluir cualquier tipo de restricción. La sintaxis de las ordenes open y close

es:

OPEN nombre_cursor; CLOSE nombre_cursor;

Cuando queramos recuperar información del cursor, deberemos

utilizar la orden FETCH, con la siguiente sintaxis:

FETCH nombre_cursor INTO variable1, variable2,.....;

Orden que devolverá una fila cada vez que sea ejecutada, y avanzará

a la siguiente posición dentro de las filas que devuelve la consulta

especificada en la declaración del cursor. El funcionamiento de los

atributos de los cursores vistos anteriormente (%ROWCOUNT, %FOUND,

%NOTFOUND, %ISOPEN) es similar, solo que el valor de %ISOPEN,

puede ser TRUE en este caso si el cursor esta abierto.

Existe un tipo de bucle para los cursores, que ejecuta

automáticamente las ordenes OPEN, CLOSE y FETCH, y es el bucle FOR,

cuya sintaxis es la siguiente:

FOR record_name IN cursor_name LOOP statements; ....... END LOOP;

En caso de no usar este bucle, se debería especificar la condición de

salida que puede ser cuando el cursor haya recorrido todas las filas, en ese

caso, la condicion sera:

EXIT WHEN nombre_cursor%NOTFOUND;

Page 43: Resumen SQL Oracle

Manual de SQL ORACLE

43

Por ejemplo, voy a escribir dos formas de realizar la misma acción,

una mediante el bucle FOR antes mencionado, y otra mediante la forma

clásica, así, mediante la forma clásica, podríamos hacer:

DECLARE CURSOR c1 IS SELECT empno, ename FROM emp; emp_record c1%ROWTYPE; BEGIN OPEN c1; LOOP FETCH c1 INTO emp_record; dbms_output.put_line(to_char(emp_record.empno));

dbms_output.put_line(emp_record.ename); EXIT WHEN c1%NOTFOUND;

END LOOP; CLOSE c1; END; /

Sin embargo, esto puede realizarse de forma mucho más sencilla,

utilizando el bucle LOOP de la siguiente manera:

DECLARE CURSOR c1 IS SELECT empno, ename FROM emp; emp_record c1%ROWTYPE; BEGIN FOR emp_record IN c1 LOOP dbms_output.put_line(to_char(emp_record.empno));

dbms_output.put_line(emp_record.ename); END LOOP; END; /