Date post: | 04-Jul-2015 |
Category: |
Documents |
Upload: | luis-flores-ramos |
View: | 177 times |
Download: | 4 times |
Escribiendo consultas
Para obtener datos se utiliza el comando SELECT. El formato es el siguiente:
SELECT [ALL|DISTINCT] [expre_colum1, expre_column2, ..., expre_columN | * ]
FROM [tabla1, tabla2, ..., tablaM]
[WHERE condición]
[GROUP BY col, col, ...]
[HAVING condición]
[ORDER BY col [DESC|ASC] [, col [DESC|ASC] ...]];
Donde expre_colum puede ser un a columna de tabla, una constante, una expresión aritmética, una función o varias funciones anidadas.
Es importante hacer notar que cada comando SQL finaliza con punto y coma(;). Cuando se escriben scripts, estos utilizarán un slash (/) al final del comando.
FROM
Especifica la tabla o lista de tablas de las que se recuperarán los datos. Por ejemplo para obtener los datos del nombre y departamento de los empleados de la empresa, se puede utilizar la siguiente consulta:
SELECT ename, deptno
FROM emp;
En el caso de que el usuario propietario de la tabla emp fuera distinto del usuario actual debe indicarse de forma prefija el esquema dueño, quedando de la siguiente forma:
SELECT ename, deptno
FROM dueño.emp;
Debe notarse que esto para efectos de un sistema no es conveniente, pues si fuese necesario mover tablas entre esquemas o bien utilizar las mismas aplicaciones en distintas bases de datos, deben actualizarse las aplicaciones, por esta razón es conveniente definir sinónimos para las tablas de tal forma que no haya que especificar el esquema dueño, salvo casos muy específicos.
WHERE
Este permite filtrar las filas seleccionadas, por medio de una condición, que define el criterio de selección. El formato de la condición es la mayoría de los casos: expresión operador expresión.
Las expresiones pueden ser constantes, operaciones aritméticas, valores nulos o el nombre de una columna. Mientras que los operadores de comparación son los siguientes:
Operadores Comparación
=, >, <, >=, <=, !=, <>
IN, NOT IN, BETWEEN, NOT BETWEEN
LIKE
IS NULL, IS NOT NULL
Se pueden construir condiciones múltiples basados en los operadores lógicos AND, OR y NOT. También se pueden utilizar los paréntesis para establecer el orden de precedencia. Algunos ejemplos de cláusulas WHERE son:
WHERE job = 'SALESMAN'
WHERE sal >= 500
AND hiredate < TO_DATE ( '01-01-1990', 'DD-MM-YYYY' )
WHERE mgr IS NULL
AND (
( sal > 500 ) OR
( job = 'SALESMAN' AND comm >= 20 )
) ORDER BY
Este especifica un criterio de clasificación del resultado de la consulta, ASC especifica orden ascendente (este es el valor por defecto) y DESC, descendente. Por ejemplo,
SELECT *
FROM dept
ORDER BY dname
Se pueden situar varios criterios, siendo la precedencia de izquierda a derecha.
ALL
Esta es la opción para recuperar todas las filas de la consulta, aunque se encuentre repetidas. Es la opción por defecto.
DISTINCT
Sólo recupera las filas que son distintas. Si se consultamos los departamentos de la tabla de empleados, el resultado serían los números de departamento de existentes:
SELECT deptno
FROM emp
En este caso aparecen todos los departamentos de los empleados, aunque el número de departamento se repita entre filas. Para eliminar los repetidos se puede hacer de la siguiente forma:
SELECT DISTINCT deptno
FROM emp
Alias para tablas
En la cláusula FROM pueden utilizarse alias para distinguir o abreviar el nombre de las tablas y así referenciar las columnas en las demás secciones del SELECT.
SELECT cust.name, cust.address, cust.city
FROM customer cust;
Este ejemplo presenta un uso sencillo y pareciera no ser importante, sin embargo su mayor uso se da cuando se necesitan diferenciar columnas con idénticos nombre, entre distintas tablas.
En el caso del WHERE se utiliza para crear el criterio de selección del grupo y hacer las uniones entre tablas.
SELECT DISTINCT city, state
FROM addresses
WHERE state IN ('CA','NY','CT')
AND city IS NOT NULL;
Alias para columnas
Este se utiliza para la presentación de los encabezados en las consultas, de tal forma que no aparezca el nombre físico de la columna, sino el que nosotros deseemos. Por ejemplo:
SELECT d.dname "Nombre Departamento",
d.deptno "Número Departamento"
FROM dept d
Operadores aritméticos
Estos son utilizados para formar expresiones con constantes, valores de columnas y funciones de valores de columnas. Estos son los conocidos: +, -, * y /.
Por ejemplo:
SELECT ename, sal, comm, sal + comm "sal total"
FROM emp
WHERE comm > 0
ORDER BY ename
Operadores de comparación y lógicos
A continuación se listan dichos operadores
Operadores de Comparación
Operador Función
= Igual a
> Mayor que
>= Mayor o igual que
< Menor que
<= Menor o igual que
!= <> Distinto de
Operadores Lógicos
Operador Función
AND TRUE si ambas condiciones son TRUE
OR TRUE si una de ambas condiciones es TRUE
NOT TRUE si la condición es FALSE y FALSE si la condición es TRUE.
Operadores de comparación de hileras
Para comparar hileras podemos hacer uso del igual (=). Así podemos ubicar dentro de los empleados aquellos que sean jefes:
SELECT *
FROM emp
WHERE job = 'MANAGER'
Sin embargo, este operador no nos sirve si lo que deseamos es listar los empleados cuyo nombre inicie con la letra 'E', en cuyo caso podemos utilizar el operador LIKE, el cual permite incluir los siguientes caracteres especiales:
'%' Comodín: representa cualquier cadena de 0 o más caracteres.
'_' Marcador de posición: representa un carácter cualquiera.
Se pueden utilizar de la siguiente manera:
SELECT *
FROM emp
WHERE ename LIKE 'E%'
Comprobaciones con conjuntos
Tenemos, además de las operaciones binarias ya vistas, otras que comparar los datos contra una lista.
De esta forma el IN se puede utilizar para verificar si una expresión pertenece o no a un conjunto de valores. Su forma general es
expresión [NOT] IN (lista de valores separados por coma)
Ejemplos de utilización del IN pueden ser los siguientes:
SELECT *
FROM emp
WHERE deptno IN ( 10, 20 );
SELECT ename
FROM emp
WHERE job IN ( 'CLERK', 'SALESMAN' )
Otra opción puede ser el verificar si una expresión se encuentra o no en un rango específico, esto por medio del BETWEEN, cuyo formato es:
Expresión [NOT] BETWEEN valor_inicial AND valor_final
Ejemplo de su utilización:
SELECT ename, sal
FROM emp
WHERE sal BETWEEN 200 AND 500;
Nota: Puede observarse que ambas cláusulas pueden sustituirse por expresiones que utilicen el OR y AND. En caso del IN se crean n comparaciones de la expresión contra el conjunto de valores, unidas mediante ORs. Para el BETWEEN se pueden hacer dos comparaciones con el mayor-igual y menor-igual, y la expresión, estas unidas por un AND.
Agrupación de elemento GROUP BY y HAVING
Existen algunas funciones que permiten obtener resultados sobre un conjunto de datos, como puede ser el tener el total, promedio, máximo, etc., de una columna. Por ejemplo, podemos obtener el salario promedio de los empleados de la compañía:
SELECT AVG(sal)
FROM emp
A pesar de que aquí la totalidad de los empleados se manejan como un grupo, puede ser necesario trabajar sobre grupos más pequeños o determinados. Este podría ser el caso que querer tener el salario promedio por departamento:
SELECT deptno, AVG(sal)
FROM emp
GROUP BY deptno
Es importante hacer notar que en el group by deben de incorporarse aquellas columnas del select que no son funciones de agrupamiento o constantes.
El uso de having sirve para expresar condiciones sobre las agrupaciones, de tal forma que podemos escoger que grupos se despliegan. De esta forma podemos limitar la consulta ya vista solo para los departamentos que tengan más de 3 empleados:
SELECT deptno, AVG(sal)
FROM emp
GROUP BY deptno
HAVING COUNT(*) > 3
El having a pesar de funcionar de forma similar al where, solo puede referenciar columnas definas en el grupo o funciones de grupo.
Para conocer sus tablas y vistas
Es importante familiarizarse con el esquema de la base de datos, principalmente conocer las estructuras que nos permiten conocer la definición de nuestros esquemas.
Por ejemplo existen vistas que indican el nombre de las tablas, en este caso la vista dictionary nos muestra las tablas de la base de datos junto con sus comentarios.
SELECT table_name
FROM dictionary
ORDER BY table_name;
Otras tablas interesantes son all_tables, all_columns, all_views y all_constraints.
Para visualizar el nombre de las columnas que componen una tabla se utiliza la instrucción "DESC
nombre_tabla". El DESC viene de DESCribe, en este caso la abreviación es la más utilizada.
Otra vista muy utilizada es el cat, que muestra los objetos como tablas, secuencias y vistas propios del usuario que está conectado.
Uniones entre tablas
Esta operación de combinar las tablas incluidas en la cláusula FROM, es en la mayoría de los casos sencilla, sin embargo el no hacerlo bien puede provocar problemas de rendimiento. Debe considerarse que en una unión (join) no deben de haber demasiadas tablas juntas, pues quizás implique un mal diseño y la denormalización sea una salida para mejorar el rendimiento.
SELECT d.dname,
e.ename,
e.hiredate
FROM emp e, dept d
WHERE d.deptno = e.deptno
ORDER BY d.dname,e.ename;
Ahora agregamos el nombre del jefe del empleado a la misma consulta.
SELECT d.dname,
e.ename,
e.hiredate,
m.dname manager
FROM emp e, emp m, dept d
WHERE d.deptno = e.deptno
AND m.empno = e.mgr
ORDER BY d.dname,e.ename;
En este caso para la salida se utilizó un alias para el nombre jefe "manager".
Recuerde no crear productos cartesianos
Recuerde que esto sucede cuando dos o más tablas incluidas en el FROM no tiene la estructura adecuada en la cláusula WHERE. Por ejemplo:
SELECT X.dname,
Z.ename
FROM emp Z,
dept X
ORDER BY X.dname, Z.ename;
En este caso si emp tiene 10 empleado y departamento 3 departamentos, la consulta retornará 30 filas. Esto es por cada nombre departamento se listan todos los empleados sin importar el departamento. Es entonces necesario para agregar la cláusula WHERE X.deptno = Z.deptno, para que el resultado sea el deseado, o sea 10 filas.
Outer Joins
Cuando se habla de utilizar outer join, quiere decir que se pueden seleccionar filas de una tabla aunque no existan correspondientes en la otra tabla. Para ello se utiliza el símbolo (+):
SELECT d.dname,
e.ename
FROM emp e,
dept d,
WHERE d.deptno(+) = e.deptno
ORDER BY d.dname,e.ename
En un caso hipotético, el presidente de la compañía nunca fue asignado a un departamento, por que nunca hubiese sido obtenido en las consultas anteriores, dado que el número de departamento está nulo. El outer join hace que todos los registros de la tabla de empleados sean obtenidos, por lo cual las columnas de la tabla de departamentos quedan vacías (en este caso el nombre del departamento).
Subconsultas (subqueries)
Las subconsultas o consultas anidadas (nested), son utilizadas partiendo de una liga con la consulta padre. Dependiendo como se cree la subconsulta, ella puede ser una vez para consulta padre o bien una vez para cada registro retornado por la consulta padre, en este caso esta es una consulta correlacionada.
Una consulta correlacionada se identifica fácilmente si ella contiene referencias a columnas de la consulta padre en la cláusula WHERE. Véase que las columnas de la subconsulta no pueden ser referenciadas por la consulta padre.
SELECT e.ename,
e.job
FROM emp e
WHERE e.deptno IN (SELECT deptno
FROM dept
WHERE dname = 'ADMIN');
El anterior es un ejemplo de una consulta no correlacionada. En este caso se buscan los empleados que estén en departamento ADMIN. El uso del IN es para indicar si está contenido (puede combinarse con el NOT), y es utilizado cuando la subconsulta devuelve cero, uno o más registros. Si se utilizará el operador de igualdad (=), se asume que solo una fila es retornada. Si la subconsulta no devuelve ninguna columna o más de una se daría un error Oracle.
Además véase que consulta podría escribirse directamente con un join. Por lo que las subconsultas son utilizadas generalmente por criterios de rendimiento o porque los joins no dan la posibilidad de construir la consulta.
SELECT d.dname,
e.ename,
e.job
FROM emp e,
dept d
WHERE e.deptno = d.deptno
AND e.empno IN (SELECT repid
FROM customer
WHERE repid = e.empno)
ORDER BY d.dname, e.ename
En este caso solo los empleados que tengan al menos un cliente son tomados en cuenta. Véase que esta es una subconsulta correlacionada, pues referencia a una columna de la consulta padre dentro de ella.
SELECT d.dname,
e.ename,
e.job
FROM emp e,
dept d
WHERE e.deptno = d.deptno
AND NOT EXISTS (SELECT 'X'
FROM customer
WHERE city in ('ROCHESTER','NEW YORK')
AND repid = e.empno)
ORDER BY d.dname, e.job, e.ename;
En este caso se muestran todos los empleados y departamentos, excepto aquellos departamentos que tengan clientes que se ubiquen en 'ROCHESTER' y 'NEW YORK'. SELECT 'X' será retornado y para evaluado por el NOT EXISTS (cuando no encuentre filas en la subconsulta es falso y cuando encuentra al menos uno es verdadero).
Puede utilizar cualquier constante en lugar de la 'X' o bien un campo de las tablas de la subconsulta (es mejor la constante).
Funciones (Built-In Functions)
Las funciones son parte intrínseca de cualquier comando SQL. Aquí se muestra una lista de las funciones más comunes.
Nombre Tipo Sintaxis Retorna
ABS Number ABS(n) Valor absoluto de n.
ADD_MONTHS Date ADD_MONTHS(a,b) Suma a la fecha a, b meses (b puede ser negativo).
ASCII Character ASCII(c) Representación decimal de c.
AVG Group AVG(DISTINCT|ALL n) Promedio del valor de n. ALL es el valor por defecto default.
CEIL Number CEIL(n) Menor entero mayor o igual a n.
CHARTOROWID Conversión CHARTOROWID(c) Convierte un carácter a un tipo de datos rowid.
CHR Character CHR(n) Representación carácter del valor decimal n.
CONCAT Character CONCAT(1,2) Carácter 1 concatenado con el 2.
CONVERT Conversion CONVERT(a, dest_c [,source_c])
Convierte una hilera de caracteres a de un conjunto de caracteres a otro.
COS Number COS(n) Coseno de n.
COSH Number COSH(n) Coseno hiperbólico de n.
COUNT Group COUNT(DISTINCT|ALL e)
Número de registros en una consulta. ALL es el default y e puede ser representado como * para indicar todas las columnas.
EXP Number EXP(n) e elevado a la enésima potencia.
FLOOR Number FLOOR(n) Mayor entero menor o igual a n.
GREATEST Other GREATEST(e [,e]...) El mayor elemento de una lista de expresiones e.
HEXTORAW Conversión HEXTORAW(c) Convierte de una carácter hexadecimal a un raw.
INITCAP Character INITCAP(c) c con la primer letra de cada palabra en mayúscula.
INSTR Character INSTR(1, 2 [, n [, m]]) Busca 1 con n caracteres para la emésima ocurrencia de 2 y retorna la posición de la ocurrencia.
INSTRB Character INSTRB(1,2[,n[,m]]) Igual a INSTR, solo que los parámetros n y m se esperan en términos de bytes.
LAST_DAY Date LAST_DAY(a) Ultimo día del mes que contiene a.
LEAST Other LEAST(e [,e]...) El menor de una lista de expresiones e.
LENGTH Character LENGTH(c) Número de caracteres en c. Si c es un tipo de datos de largo fijo, todos los blancos son incluidos.
LENGTHB Character LENGTHB(c) Igual que LENGTH excepto que en bytes.
LN Number LN(n) Logaritmo natural de n, donde n > 0.
LOG Number LOG(b,n) Logaritmo en base b de n.
LOWER Character LOWER(c) c con todas las letras en minúsculas..
LPAD Character LPAD(1,n [,2]) La hilera 1 rellena a la izquierda hasta completar el largo n. Si el
carácter 2 es indicado se usa como patrón de relleno y sino se utilizan blancos.
LTRIM Character LTRIM(c [,set])
Remueve caracteres a la izquierda de c. Si el conjunto s es definido, remueve los caracteres iniciales hasta que no aparezca el conjunto set.
MAX Other MAX(DISTINCT|ALL e) Máximo de una expresión e.. ALL es el default.
MIN Other MIN(DISTINCT|ALL e) Mínimo de una expresión e. ALL es el default.
MOD Number MOD(r,n) Residuo de dividir r por n..
MONTHS_BETWEEN Date MONTHS_BETWEEN(a,b) Número de meses entre dos fechas a y b..
NEW_TIME Date NEW_TIME(a, z1, z2) Día y hora en la zona z2, cuando la fecha y hora de z1 es a.
NEXT_DAY Date NEXT_DAY(a, c) Primer día de la semana identificada por c que está después de c.
NLSSORT Character NLSSORT((c [,parm]) Hilera de bytes para ordenar c.
NLS_INITCAP Character NLS_INITCAP(c [,parm]) c con la primer letra de cada palabra en mayúscula.
NLS_LOWER Character NLS_LOWER(c [,parm]) c con todas las letras en minúscula
NLS_UPPER Character NLS_UPPER(c [,parm]) c con todas las letras en mayúscula.
NVL Other NVL(e1, e2) Si e1 es nulo, retorna e2. Si e1 no es nulo retorna e1.
POWER Number POWER(m,n) m elevado a la enésima potencia
RAWTOHEX Conversión RAWTOHEX(raw) Convierte un valor raw a su equivalente hexadecimal.
REPLACE Character REPLACE(c, s1 [, r2])
Remplaza cada ocurrencia de la hilera s1 en c con r2. Si r2 se omite las ocurrencias de r1 son borradas.
ROUND Date ROUND(n [,f])
Redondea la fecha al formato del modelo f. Si f es omitido, n será retornado para el día más cercano.
ROUND Number ROUND(n[,m]) n redondeado a m. Si m está, es redondeado a m lugares.
ROWIDTOCHAR Conversion ROWIDTOCHAR(rowid) Convierte de rowid a varchar2.
RPAD Character RPAD(1, n [, 2]) 1 rellenado a la derecha con largo n y con la hilera 2.
RTRIM Character RTRIM(c [, s]) c con los caracteres removidos al final de la hilera.
SIGN Number SIGN(n) -1 if n < 0, 0 if n = 0, 1 if n > 0.
SIN Number SIN(n) Seno de n
SINH Number SINH(n) Seno hiperbólico de n.
SOUNDEX Character SOUNDEX(c) Una hilera con la representación fonética de c.
SUBSTR Character SUBSTR(c, m [,n]) Una porción de c, iniciando en el carácter m por n caracteres. Si m
es negativo se cuentan los espacios a partir del final. Si n es omitido, son retornados todos los caracteres hasta el final de c.
SUBSTRB Character SUBSTRB(c, m [,n]) Igual que SUBSTR excepto que m y n son número de bytes.
SQRT Number SQRT(n) Raíz cuadrada de n.
STDDEV Group STDDEV(DISTINCT|ALL n) Desviación estándar de n.
SUM Group SUM(DISTINCT|ALL n) Suma de números n.
SYSDATE Date SYSDATE Fecha y hora actual.
TAN Number TAN(n) Tangente de n.
TANH Number TANH(n) Tangente hiperbólica de n.
TO_CHAR Conversion TO_CHAR(d [,f [,parm]) Convierte la fecha d a carácter con el formato f y el nls_date_language para parm.
TO_CHAR Conversion TO_CHAR(n [,f [,parm]) Convierte un número n a varchar2, según formato de parm.
TO_DATE Conversion TO_DATE(c [, f [, parm]) Convierte un varchar2 c a un tipo fecha, con el formato f y nls_date_formate parm.
TO_MULTI_BYTE Conversion TO_MULTI_BYTE(c) Convierte c a su equivalente en multibyte.
TO_NUMBER Conversion TO_NUMBER(c [,f [, parm]]) Convierte el carácter c a un número, utilizando el formato f y el nls_number_format parm.
TO_SINGLE_BYTE Conversion TO_SINGLE_BYTE(c) Convierte el carácter multibyte c a su equivalente en byte simple.
TRANSLATE Character TRANSLATE(c, f, t) c con cada ocurrencia en f con cada correspondiente carácter en t.
TRUNC Date TRUNC(c [,f]) c con la porción de hora truncada al formato f.
TRUNC Number TRUNC(n[,m]) n truncado a emésimo decimal.. Si m es omitido, se toma 0.
UID Other UID Un entero que en forma única identifica al usuario.
USER Other USER Usuario actual como varchar2.
UPPER Character UPPER(c) c con las letras en mayúscula.
VARIANCE Group VARIANCE(DISTINCT|ALL n) Varianza de n.
VSIZE Other VSIZE(e) Número de bytes que necesita la representación interna de e.
Algunos ejemplos utilizando funciones.
SELECT SUBSTR(address,1,20),
city
FROM customer
WHERE address IS NOT NULL
AND UPPER(city) = 'ROCHESTER'
Véase que UPPER hacer que al convertir a mayúscula el nombre de la ciudad, hará que si 'Rochester' aparece se convierta para luego compararse con 'ROCHESTER', de tal forma que sean iguales.
SELECT dept_no, SUM(emp_salary), AVG(emp_salary)
FROM emp
WHERE dept_no = dept_no
GROUP BY dept_no;
Aquí se puede ver el uso del SUM y AVG. Véase que cuando se utilizan otras columnas (sin uso de funciones resumen) se debe hacer el GROUP BY por estas columnas.
El comando DECODE
Este es uno de los comandos más importantes. El DECODE tiene la siguiente sintaxis:
DECODE(val, exp1, exp2, exp3, exp4, ..., def);
DECODE primero evalúa el valor o expresión val, y compara con exp1. Si val es igual exp1, la expresión exp2 es retornada. Si val no es igual a exp1, la expresión exp3 será evaluada y retorna la expresiónexp4 si val es igual a exp3. Este proceso continúa hasta que todas las expresiones hayan sido evaluadas. Si no hay coincidencias, el valor por defecto def será retornado.
Es importante siempre agregar un valor por defecto.
SELECT e.ename,
e.job,
DECODE(e.job, 'President', '******', e.sal)
FROM emp e
WHERE e.empno IN (SELECT NVL(z.mgr, e.empno)
FROM emp z);
En esta consulta todos los nombres de los jefes serán obtenidos junto con su salario. Cuando la fila del presidente es obtenida se presentará '******' en lugar de su salario.
Véase que con la función NVL para evaluar el manager_id. En este caso solo el presidente tiene el manager_id nulo y por tanto no será obtenido sin el NVL.
Aunque sal es de distinto tipo de '******', no da error pues Oracle hacer la conversión automática de sal a carácter.
SELECT e.ename,
e.job,
e.sal
FROM emp e
WHERE DECODE(USER,'PRES',e.empno, UPPER(e.ename),e.empno, 0) = e.empno;
En este caso, si el usuario es el presidente todos los empleados serán obtenidos, con los demás empleados solo se obtiene el correspondiente salario.
SELECT e.ename,
e.job
DECODE(USER,'ADMIN', DECODE(e.job, 'PRESIDENT', '*****', e.sal),
'PRES', e.sal, '******')
FROM emp e
WHERE e.empno in (SELECT NVL(z.mgr, e.empno)
FROM emp z);
Acá se utiliza un DECODE anidado dentro de otro. Si el usuario Oracle es 'ADMIN' se muestra el salario de todos excepto del presidente, si el usuario es el presidente presenta todos los salarios y para cualquier otro solo asteriscos.
SELECT d.dname,
e.job,
e.ename
FROM emp e,
dept d
WHERE d.deptno = e.deptno
ORDER BY DECODE(e.job,'PRESIDENT', 0,
DECODE(d.dname,'SALES', 1, 'ADMIN', 2, 3)),
e.ename;
En este caso se utiliza el ORDER BY para ordenar según el job, pero se ajusta para que aparezca primero el presidente luego los vendedores, administradores y todos los demás. Luego del decode son ordenados por el ename.
DDL (Data Definition Language)
El comando CREATE
El CREATE es el comando que inicia al desarrollador, acá se cubrirán los usos más comunes.
Tablas
Cada diseñador de base de datos tendrá que crear una tabla alguna vez. El privilegio de sistema CREATE TABLE es necesario para ejecutar este comando. El DBA es el responsable de administrar dichos privilegios. La sintaxis para crear una tabla es la siguiente
CREATE TABLE [schema.]nombre_tabla
(
columna tipo_dato [default expression] [NOT NULL]
[column_constraint],
...
[constraint de tabla]
)
PCTFREE x PCTUSEDx
INITRANS x MAXTRANS x
TABLESPACE nombre_tablespace
STORAGE clauseCLUSTER cluster clause
ENABLE clause DISABLE clause
AS subconsulta
Ejemplos:
CREATE TABLE addresses (
ADRS_ID NUMBER(6),
ACTIVE_DATE DATE,
BOX_NUMBER NUMBER(6),
ADDRS_1 VARCHAR2(40),
ADDRS_2 VARCHAR2(40),
CITY VARCHAR2(40),
STATE VARCHAR2(2),
ZIP VARCHAR2(10)
);
Este fue un ejemplo sencillo sin utilizar varias capacidades. A continuación se muestra otro ejemplo
CREATE TABLE addresses (
ADRS_ID NUMBER(6) CONSTRAINT PK_ADRS PRIMARY KEY,
ACTIVE_DATE DATE DEFAULT SYSDATE,
BOX_NUMBER NUMBER(6) DEFAULT NULL,
ADDRS_1 VARCHAR2(40) NOT NULL,
ADDRS_2 VARCHAR2(40) DEFAULT NULL,
CITY VARCHAR2(40) DEFAULT NULL,
STATE VARCHAR2(2) DEFAULT 'NY',
ZIP VARCHAR2(10)
)
PCTFREE 5
PCTUSED 65
TABLESPACE adrs_data
STORAGE (INITIAL 5140 NEXT 5140
MINEXTENTS 1 MAXEXTENTS 10
PCTINCREASE 10);
Índices
Estos son utilizados para incrementar el rendimiento de la base de datos. El comando es el CREATE INDEX y cada tabla puede tener varios índices.
CREATE INDEX [schema.]nombre_indice
ON schema.table (nombre_columna ASC/DESC)
CLUSTER schema.cluster
INITRANS x MAXTRANS x
PCTFREE X
TABLESPACE nombre_tablespace
STORAGE clause NOSORT
Ejemplos:
CREATE INDEX x_adrs_id ON ADDRESSES (ADRS_ID);
CREATE INDEX x_city_state ON ADDRESSES (CITY,STATE)
TABLESPACE application_indexes;
El orden de creación es importante a la hora de crear las consultas, para ellas el orden de aparición en el where debe ser el mismo del orden físico de las columnas.
Secuencias
Estas son utilizadas para la generación de llaves únicas consecutivas y enteras, de forma sencilla.
CREATE SEQUENCE [schema.]name
INCREMENT BY x
START WITH x
[MAXVALUE x | NOMAXVALUE]
[MINVALUE x | NOMINVALUE]
[CYCLE | NOCYCLE]
[CACHE x | NOCACHE]
[ORDER | NOORDER]
Para crear una secuencia para adrs_id se puede hacer de la siguiente forma:
CREATE SEQUENCE adrs_seq INCREMENT BY 5 START WITH 100;
Para obtener el nuevo número de una secuencia se utiliza la seudo columna NEXTVAL, precedida del nombre de la secuencia, por ejemplo adrs_seq.nextval retornará 100 en la primer llamada y 105 en la segunda.
Si desea obtener el valor actual de secuencia se utiliza la seudo columna CURRVAL, siempre y cuando haya accedido alguna vez al NEXTVAL.
Otros Objetos
El comando CREATE puede ser utilizado para crear otros objetos como los siguientes:
CREATE xxx, donde xxx es uno de los siguientes:
CLUSTER CONTROLFILE DATABASE
DATABASE LINK
DATAFILE FUNCTION
INDEX PACKAGE BODY PACKAGE
PROCEDURE PROFILE ROLE
ROLLBACK SEGMENT
SCHEMA SEQUENCE
SNAPSHOT SNAPSHOT LOG SYNONYM
TABLE TABLESPACE TRIGGER
USER VIEW
INSERTs, UPDATEs, y DELETEs
El comando INSERT es utilizado para agregar nuevas filas a la base de datos. Este puede ser utilizado para crear una fila a la vez utilizando la expresión VALUES o un conjunto de registros a la vez utilizando una subconsulta. La sintaxis es la siguiente:
INSERT INTO [schema.]nombre_tabla
[(columna [,columna] ...)]
{VALUES (valor [,valor] ...) | subconsulta};
Ejemplo:
INSERT INTO dept (deptno, name, loc)
VALUES (dept_seq.NEXTVAL,'CUSTOMER SERVICE', 'NEW YORK');
En este caso se insertan una fila en la tabla de departamentos. Acá se utiliza la secuencia dept_seq para obtener el siguiente valor de deptno.
INSERT INTO emp (empno, ename, deptno, hire_date,
job, sal, mgr)
SELECT emp_seq.NEXTVAL, new.ename, 30, SYSDATE,
'CUSTOMER REPRESENTATIVE', new.sal, 220
FROM candidates new
WHERE new.accept = 'YES'
AND new.deptno = 30;
En este caso se insertarán todas las filas de la tabla de candidates que han sido asignados al departamento número 30. Dado que el número de departamento y mgr son conocidos se pueden utilizar constantes en la subconsulta.
UPDATE
El comando UPDATE es utilizado para cambiar la información existente en las filas de la base de datos. La sintaxis del UPDATE es
UPDATE [schema.]nombre_tabla
SET columna1 = {expr | subconsulta}
...
[, columnan = = {expr | subconsulta}]
WHERE condicion;
Ejemplos:
UPDATE emp
SET deptno = 30
WHERE ename = 'DOE';
En este ejemplo se transfiere al empleado DOE al departamento 30. Si hubiesen más de un empleado con el nombre DOE tendría que agregarse condiciones en el WHERE.
UPDATE emp
SET sal = sal + (sal * .05);
Este da a cada empleado un 5 por ciento de incremento en el salario.
UPDATE emp a
SET a.sal = (SELECT a.sal +
(a.sal * DECODE(d.dname,
'SALES', .1,
'ADMIN', .07,
.06)
)
FROM dept d
WHERE d.deptno = a.deptno)
WHERE a.deptno = (SELECT deptno
FROM dept y
WHERE y.loc = 'ROCHESTER');
Este ejemplo da un incremento a los empleados de Rochester. El monto del incremento es manejado por el DECODE, evaluando el nombre del departamento. Los empleados de ventas reciben un 10%, los de administración reciben un 7% y los demás un 6%.
DELETE
El comando DELETE es utilizado para borrar registros de la base de datos. La sintaxis de DELETE es:
DELETE [FROM] [schema.]nombre_tabla
WHERE condición
Ejemplos:
DELETE FROM emp e
WHERE e.ename = 'DOE';
Si el empleado Doe sale de la compañía, se borra de la base de datos.
DELETE FROM dept
WHERE loc IS NULL;
En este ejemplo, todos los registros en la tabla departamento serán borrados si el loc está nulo.
Véase que en ningún caso el comando es permanente. Para que sea permanente debe aplicarse el comando COMMIT. Si se desea reversar los cambios realizados se debe utilizar el ROLLBACK (si fue usada una secuencia el consecutivo no se devuelve).
Notas
Cuando desea comparar fechas, si la idea es verificar el día y no interesa la hora (con minutos y segundos), es recomendable utilizar el TRUNC para hacerlo (siempre y cuando usted sepa que se guarda la hora).
Recuerde que cuando se comparan nulos en expresiones booleanas, siempre devuelven falso.
PL/SQL
PL/SQL
Hasta el momento se han visto distintos comandos para crear scripts SQL, sin embargo, estos tienen limitantes importantes en cuanto a la secuencia de ejecución de instrucciones, el uso de variables, la modularidad y la gestión o manejo de posibles errores.
Para poder solventar estas limitantes se incorpora en el servidor una gestor PL/SQL, al igual que en las diferentes herramientas. Este permite el manejo de variables, estructura modular (procedimientos y funciones), estructuras de control, manejo de excepciones y una integración con el entorno Oracle.
Los programas creados con PL/SQL pueden ser almacenados en la base de datos como cualquier otro objeto, de esta forma se facilita a los usuarios el acceso a estos programas. De igual forma el lenguaje permite la incorporación disparadores en el ámbito de base de datos, que permiten reflejar de mejor manera las reglas del negocio e implementar elementos de auditoría en la base de datos.
Bloques PL/SQL DECLARE-BEGIN-END
El DECLARE es un comando que limita la creación de bloques dentro de PL/SQL, como se presenta a continuación:
BEGIN
...
<<inner>>
[DECLARE
...]
BEGIN
...
END inner;
...
[EXEPTION
...]
END;
Véase que se permite el anidamiento de bloques. Ahora bien el uso del DECLARE para la creación de bloques es necesario cuando es necesario definir variables o bien cursores a ser utilizados en el cuero de ejecución.
El BEGIN y END fija el primero el inicio del bloque (cuando no está el DECLARE) y el segundo el fin de dicho BLOQUE.
En el caso de bloques anidados el bloque de adentro puede referenciar variables del bloque externo, pero no a la inversa. Ahora se presenta un ejemplo en donde se borra el departamento 20, pero antes se crea un departamento provisional, al que asigna los empleados del departamento 20.
DECLARE
v_num_empleados NUMBER(2);
BEGIN
INSERT INTO dept
VALUES ( 99, 'PROVISIONAL', NULL );
UPDATE emp
SET deptno = 99
WHERE deptno = 20;
-- se asigna el total de empleados cambiados de
-- departamento
v_num_empleados := SQL%ROWCOUNT;
DELETE FROM dept
WHERE deptno = 20;
-- para que este mensaje se muestre en SQL*PLUS
-- asegúrese de ejecutar previamente
-- SET SERVEROUTPUT ON
Dbms_output.put_line ( v_num_empleados || ' empleados ubicados en
PROVISIONAL.' );
EXCEPTION
WHEN OTHERS THEN -- en cualquier error ejecutar
ROLLBACK;
RAISE_APPLICATION_ERROR ( -20000, 'Error en la aplicación.' );
END;
Tipos de datos básicos
PL/SQL cuenta con los mismos tipos de datos de SQL, además de otros propios, para lo cual se muestra a continuación una descripción de cada uno de ellos.
Las longitudes máximas según versiones de bases de datos y PL/SQL son:
Variables
Dentro del DECLARE de un bloque se pueden declarar las variables necesarias en la ejecución del bloque PL/SQL.
Declaración e iniciación
La sintaxis para declarar variables es la siguiente:
<variable> <tipo> [NOT NULL] [{:=|DEFAULT} <valor>]
Por ejemplo
DECLARE
mi_var VARCHAR2(10) := 'AMIGOS';
tu_var NUMBER(5,2) DEFAULT 5.32;
...
Uso de %TYPE y %ROWTYPE
Estos pueden ser utilizados cuando se necesita no declarar con un tipo de datos explícito, sino que se desea obtener de una definición previa el tipo. En este caso el %TYPE sirve para declara una variable del mismo tipo de datos de otra y el %ROWTYPE para declarar un registro con los campos de otro.
Ejemplos:
DECLARE
My_employee_id emp.empid%TYPE;
Rec_cliente customer%ROWTYPE;
BEGIN ...
DECLARE
My_sal emp.sal%TYPE := 0;
My_ename emp.ename%TYPE:= 'SMITH';
BEGIN ...
Manualmente declaración de registro
DECLARE TYPE
t_employee IS RECORD ( My_empid emp.empid%TYPE,
My_lastname emp.ename%TYPE,
My_salary emp.sal%TYPE);
My_employee t_employee;
BEGIN ...
Constantes
Se pueden declarar constantes mediante el siguiente formato:
<nombre constante> CONSTANT <tipo> := <valor>
Ejemplo
CREATE FUNCTION find_circle_area ( p_radius IN circle.radius%TYPE )
RETURN NUMBER IS
My_area number := 0;
Pi CONSTANT NUMBER := 3.14159265358;
BEGIN
My_area := (p_radius*p_radius)* Pi;
RETURN my_area;
END;
Operador asignación, comparación y lógicos
Para asignar valores a las variables se utiliza el símbolo :=, de esta forma,
DECLARE
V_fecha_nac DATE;
V_nombre VARCHAR2 := 'Sin Asignar'; -- inicializa
BEGIN
. . .
V_fecha_nac := TO_DATE ( '01-01-2000', 'DD-MM-YYYY' );
V_nombre := 'Pedro Perez';
. . .
END;
En el caso de tener que comparar elementos se pueden utilizar los siguientes símbolos de comparación y lógicos:
Símbolo Descripción
> Mayor
>= Mayor o igual
< Menor
<= Menor o igual
= Igual
IN Contenido en un conjunto
AND Y lógico
OR O lógico
NOT Negación
Estructuras de Control
Las estructuras de control presentes en PL/SQL son las comunes de los lenguajes de programación estructurados: IF, WHILE, FOR y LOOP.
Control alternativo
El control para manejo de opciones es el IF, el cual tiene la siguiente sintaxis:
(1)
IF <condición> THEN
Instrucciones;
...;
END IF;
(2)
IF <condición> THEN
Instrucciones;
...;
ELSE
Instrucciones;
...;
END IF;
(3)
IF <condición> THEN
Instrucciones;
...;
ELSIF <condición2> THEN
Instrucciones;
...;
ELSIF <condición3> THEN
Instrucciones;
...;
ELSE
Instrucciones;
...;
END IF;
Vea el siguiente ejemplo:
PROCEDURE init_recip_list IS
recipient_num NUMBER;
i BINARY_INTEGER;
j BINARY_INTEGER := 1;
k BINARY_INTEGER;
BEGIN
FOR i in 1..10 LOOP
IF i = 1 THEN
j := j + 1;
ELSE
FOR k in 1..j LOOP
IF k = i THEN
j := j + 2;
ELSIF k = j THEN
j := j + 1;
END IF;
END LOOP;
END IF;
END LOOP;
END;
Otro control interactivo es el EXIT-WHEN, el cual permite combinarse con el LOOP.
OPEN c_line_item;
LOOP
FETCH c_line_item INTO rec_info;
EXIT WHEN (c_line_item%NOTFOUND) OR (c_line_item%NOTFOUND is NULL);
END LOOP;
CLOSE c_line_item;
Control repetitivo
Pueden tenerse varias condiciones para los ciclos.
WHILE
Este verifica una condición, que mientras sea verdadera se mantiene en el ciclo. La sintaxis es la siguiente:
WHILE <condición> LOOP
Instrucciones;
...;
END LOOP;
FOR numérico
Utilice este ciclo para realizar iteraciones sobre un rango de números.
FOR <variable> IN <mínimo>..<máximo> LOOP
Instrucciones;
...;
END LOOP;
FOR con cursores
Este es un tipo que combina el control de cursores y el uso de ciclos para recorrerlo. Acá no hace falta abrir y cerrar el cursor directamente, sino que el FOR se encarga de ello.
CURSOR c_line_item IS
(estatuto SQL)
BEGIN
FOR rec_info IN c_line_item LOOP
Intrucciones;
END LOOP;
END;
Véase que uno declara el rec_info, que para los efectos es un registro de tipo c_line_item (%ROWTYPE), el cual no es necesario declararlo, sino que se crean como una variable local al FOR. Por último, el FOR realiza de forma implícita el FETCH sobre el rec_info.
LOOP
Utilice el LOOP para realizar procesamiento interactivo basado en escogencias lógicas. La sintaxis común es
LOOP
Instrucciones;
...;
EXIT WHEN <condición>;
Instrucciones;
...;
END LOOP;
Cursores
En general PL/SQL utiliza cursos para todos los comandos de acceso a la base de datos. En este caso el lenguaje permite los cursores implícitos y explícitos. Los cursos implícitos son aquellos establecidos para los comandos que no cuentan con un cursor explícito declarado. Usted deberá utilizar cursores explícitos para aquellas consultas que retornen más de una fila.
Declaración de Cursores
Se debe definir el curso en el área de definición de variables, pero se utilizan las palabras reservadas CURSOR nombre_cursor IS, como se muestra a continuación:
CURSOR c_line_item IS
(comando sql)
El comando SQL puede ser cualquier consulta válida. Una vez creada la definición del cursor, usted puede ser capaz del controlar el flujo del mismo por medio del OPEN, FETCH y el CLOSE.
Control del Cursor
Para manipular los datos del cursor, usted debe usar primero el comando OPEN seguido del nombre del cursor. Posterior a esto debe utilizar el comando FETCH para extraer las filas del cursor, según el criterio seguido por el select. Por último, una vez que ha sido procesado por completo, debe utilizarse el comando CLOSE seguido del nombre del cursor, para esta forma terminar cualquier actividad asociada con el cursor abierto. Veamos un ejemplo:
OPEN c_line_item;
...
FETCH c_line_item INTO li_info;
...
(retrieved row processing)
...
CLOSE c_line_item;
En este caso el código abre el cursor c_line_item y procesa las filas extraídas. Luego de procesar toda la información cierra el cursor.
Atributos del cursor explícito
Existen cuatro atributos asociados con los cursores de PL/SQL:
%NOTFOUND
%FOUND
%ROWCOUNT
%ISOPEN
El %NOTFOUND devuelve FALSE cuando es extraída una fila, TRUE si el último FETCH no extrajo fila alguna y NULL si el SELECT del cursor no ha retornado datos.
El %FOUND es lógicamente opuesto al %FOUND en cuanto al TRUE y FALSE, pero sigue
retornando NULL si el cursor no ha retornado datos.
El %ROWCOUNT se utiliza para determinar cuantas filas han sido extraídas en un punto. Este valor se incrementa con cada fila extraída y tiene valor cero cuando apenas ha sido abierto el cursor.
Por último, el %ISOPEN, tiene valores TRUE o FALSE, dependiendo de si el cursor asociado ha sido abierto o no.
Parámetros de Cursores
Se pueden especificar parámetros para los cursores de la misma forma que se pasan a procedimientos y/o funciones. Veamos el siguiente ejemplo:
CURSOR c_line_item (p_order_num IN NUMBER) IS
SELECT merch_gross, recipient_num
FROM line_item
WHERE order_num = p_order_num;
Véase que los parámetros son siempre de tipo IN (solo de entrada), pero el tipo de datos es cualquier tipo de datos válido. La idea es referenciar el parámetro dentro de la consulta, y este se pasa a la hora de abrir el cursor.
Es posible también definir los parámetros con default, de forma tal que se puede variar la cantidad de parámetros a utilizar en el cursor.
DECLARE
CURSOR c_line_item ( order_num NUMBER DEFAULT 100,
line_num NUMBER DEFAULT 1 ) IS ...
. . .
BEGIN
...
OPEN c_line_item ( 19 ); -- valores 19, 1
...
OPEN c_line_item ( 20, 4 ); -- valores 20, 4
...
OPEN c_line_item; -- valores 100, 1
...
END;
De esta forma se pueden pasar todos, uno o ningún parámetro a la hora de abrir el cursor.
Para un cursor
DECLARE CURSOR c_emp IS
SELECT e.ename , e.empid
FROM emp e;
...
My_employee c_emp%ROWTYPE;
BEGIN
My_employee.empid := 100;
...
OPEN c_emp;
FETCH c_emp INTO My_employee;
CLOSE c_emp;
IF My_employee.sal > 200 THEN
...
END;
Excepciones
El control de excepciones es el mecanismo del PL/SQL para manejar errores de tiempo de ejecución. El utilizar este mecanismo permite continuar la ejecución del programa, si el error no es muy grave, lo cual quedaría a decisión del programador.
Usted debe definir el manejador de la excepción dentro de la especificación del programa o bloque. Cuando un error de programa ocurre el control se pasa al bloque de manejo de excepciones, luego de lo cual se regresa el control al que invoca al programa o bien termina según lo defina el programador.
Excepciones definidas por el usuario
El PL/SQL da la posibilidad de que el usuario defina excepciones en área de especificaciones. Vea el ejemplo:
ot_failure EXCEPTION;
En este caso el nombre de la excepción es ot_failure. El código asociado que maneja la excepción es:
EXCEPTION
WHEN OT_FAILURE THEN
...
Excepciones del sistema
Estas son las excepciones predefinidas del sistema. Un ejemplo de ellas es el NO_DATA_FOUND, que se dispara cuando un SELECT-INTO no obtiene registros, veamos:
DECLARE
v_empid emp.empid%TYPE;
BEGIN
...
SELECT e.empid INTO v_empid
FROM emp e
WHERE e.ename = 'CHARLIE';
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE OT_FAILURE;
WHEN TOO_MANY_ROWS THEN
RAISE OT_FAILURE;
END;
En este caso cuando el SELECT no devuelve columnas o devuelve más de una se levanta una excepción que a su vez es atrapada para ser reenviada a una excepción definida por el usuario.
Vea a continuación la lista de excepciones del sistema;
Nombre Error Oracle
CURSOR_ALREADY_OPEN ORA-06511
DUP_VAL_ON_INDEX ORA-00001
INVALID_CURSOR ORA-01001
INVALID_NUMBER ORA-01722
LOGIN_DENIED ORA-01017
NO_DATA_FOUND ORA-01403
NOT_LOGGED_ON ORA-01012
PROGRAM_ERROR ORA-06501
STORAGE_ERROR ORA-06500
TIMEOUT_ON_RESOURCE ORA-00051
TOO_MANY_ROWS ORA-01422
TRANSACTION_BACKED_OUT ORA-00061
VALUE_ERROR ORA-06502
ZERO_DIVIDE ORA-01476
Adicional a las excepciones anteriores existe una más llamada OTHERS, que atrapa cualquier excepción que no haya sido establecida explícitamente.
WHEN OTHERS THEN
out_status_code := 'FAIL';
out_msg := g_out_msg || ' ' || SUBSTR(SQLERRM, 1, 60);
SQLERRM es válido cuando se invoca dentro de un manejador de excepción, en otro caso debe pasarse como parámetro el código del error.
Procesamiento de transacciones
Las opciones de procesamiento de transacciones son las mismas para SQL que para PL/SQL. Las operaciones para manejo de transacciones son:
SET TRANSACTION inicializa una transacción y define las características clave.
COMMIT Finaliza la transacción actual salvando los cambios en la base de datos e iniciando una
nueva transacción.
ROLLBACK Finaliza la transacción actual, descartando los cambios realizados en la base de datos.
SAVEPOINT Define un punto intermedio para que la transacción pueda realizar rollbacks parciales.
SET TRANSACTION
Este comando es utilizado para definir el inicio de una transacción. Alguno de los efectos que se puede lograr con el set transaction es que la transacción pueda ser definida de solo lectura (read-only). Ejemplos del uso del comando son:
SET TRANSACTION READ ONLY;
SET TRANSACTION READ WRITE;
COMMIT
Este comando representa el punto del tiempo donde el usuario ha realizado una serie de cambio lógicos que se han agrupado y que dado que no ha habido errores, el usuario está listo para salvar su trabajo. De forma implícita se inicia una nueva transacción luego del COMMIT.
Es importante saber que cuando el usuario sale de SQL*Plus se ejecuta un COMMIT automático, de igual forma cuando ejecuta un comando de definición de datos.
COMMIT;
COMMIT WORK;
ROLLBACK
Si el usuario se diera cuenta en cualquier punto de la transacción que cometió un error, puede descartar los cambios hechos en la base de datos utilizando el ROLLBACK. Luego del ROLLBACK, se inicia una nueva transacción. Siempre se ejecuta un rollback cuando ocurre un error en la ejecución o bien cuando el comando es finalizado con CTRL.+C.
ROLLBACK;
ROLLBACK WORK;
SAVEPOINT
En algunos casos tenemos transacciones muy grandes o que envuelven la modificación de muchos datos, y no se desea reversar la misma por haber tenido un pequeño error en la ejecución del último comando. Los savepoints permiten dividir el trabajo de la transacción diferentes segmentos. De esta forma el usuario puede ejecutar rollbacks para un savepoint solamente, dejando los cambios previos intactos. Veamos un ejemplo:
UPDATE spanky.products
SET quantity = 55
WHERE product# = 59495;
SAVEPOINT A1;
UPDATE spanky.products
SET quantity = 504;
ROLLBACK TO SAVEPOINT A1;
COMMIT;
En el anterior ejemplo los cambios realizado por el segundo UPDATE no son salvados cuando se realiza el COMMIT, dado que el ROLLBACK anterior a este los revierte.
Recuerde que la base de datos provee de los mecanismos de bloqueo para que solo un usuario pueda modificar a la vez un registro de la base de datos.
Otro aspecto importante, para el caso de PL/SQL, es que el inicio de un bloque no define el inicio de una transacción.
Procedimientos / Funciones
Para definir un procedimiento, es necesario definir el nombre y los parámetros que serán pasados.
PROCEDURE get_order_total ( in_order_num IN NUMBER,
out status_code OUT VARCHAR2,
out_msg OUT VARCHAR2,
out_merch_total OUT NUMBER,
out_shipping IN OUT NUMBER,
out_taxes IN OUT NUMBER,
out_grand_total OUT NUMBER
) IS
/* sección de declaración */
...
BEGIN
...
END;
Las funciones son parecidas y tan solo cambia el uso de la palabra reservada PROCEDURE por FUNCTION y la selección del tipo de datos devuelto;
FUNCTION calc_ship_charges ( in_merch_total IN NUMBER ) RETURN NUMBER IS
/* sección de declaración */
...
BEGIN
...
RETURN ( valor del tipo declarado de la función )
END;
Tipos de Modos para los Parámetros
Se pueden definir parámetros IN (el valor por defecto), IN OUT, o OUT, dependiendo de la naturaleza de información pasada.
IN parámetros solo de entrada (no pueden ser modificados). IN OUT entrada y salida (pueden ser cambiados). OUT solo de salida.
Especificaciones
PROCEDURE init_line_items IS
(local variables)
BEGIN
(subprogram logic)
EXCEPTION
(exception handling)
END init_line_items;
Esta es la estructura general para procedimientos, la cual es muy similar a la de las funciones.
Parámetros Default
Es posible definir valores por defecto para los parámetros de una función o procedimiento, para ello vea el siguiente ejemplo:
PROCEDURE calc_ship_charges( merch_total NUMBER DEFAULT 5.95 ) IS
...
Si el parámetro no es incluido cuando se invoca el procedimiento se toma el valor por defecto 5.95.
Paquetes
Los paquetes son utilizados para guardar subprogramas y otros objetos en la base de datos y en bibliotecas de las herramientas Oracle.
Elementos de un paquete
Un paquete se encuentra compuesto por dos elementos claramente definidos:
Especificación
En este se tienen las declaraciones públicas (accesible desde cualquier parte de la aplicación) de subprogramas, tipos, constantes, variables, cursores, excepciones, etc. Este actúa como una interfaz con otros programas.
Cuerpo
Contiene los detalles de implementación y declaraciones privadas accesibles sólo desde los objetos del paquete. Es una caja negra para el resto de programas.
Creación de un paquete
Para crear paquetes en la base de datos puede ser utilizado el SQL*PLUS mediante los comandos CREATE PACKAGE y CREATE PACKAGE BODY, cuyos formatos son los siguientes:
CREATE [OR REPLACE] PACKAGE <nombrepaquete> AS
<declaración de constantes, variables, cursores,
excepciones y otros objetos públicos>
<especificación de subprogramas>
END [<nombrepaquete>];
CREATE [OR REPLACE] PACKAGE BODY <nombrepaquete> AS
<declaración de constantes, variables, cursores,
excepciones y otros objetos privados>
<cuerpo de subprogramas>
[BEGIN
instrucciones de inicialización>;]
<END [<nombrepaquete>];
Ejemplo de declaración de un paquete:
CREATE PACKAGE emp_actions AS -- especificación
TYPE EmpRecTyp IS RECORD ( emp_id INTEGER,
salary REAL
);
CURSOR desc_salary RETURN EmpRecTyp;
PROCEDURE hire_employee ( ename VARCHAR2,
job VARCHAR2,
mgr NUMBER,
sal NUMBER,
comm NUMBER,
deptno NUMBER
);
PROCEDURE fire_employee ( emp_id NUMBER );
END emp_actions;
CREATE PACKAGE BODY emp_actions AS -- cuerpo
CURSOR desc_salary RETURN EmpRecTyp IS
SELECT empno, sal
FROM emp
ORDER BY sal DESC;
PROCEDURE hire_employee ( ename VARCHAR2,
job VARCHAR2,
mgr NUMBER,
sal NUMBER,
comm NUMBER,
deptno NUMBER
) IS
BEGIN
INSERT INTO emp VALUES (empno_seq.NEXTVAL, ename, job,
mgr, SYSDATE, sal, comm, deptno);
END hire_employee;
PROCEDURE fire_employee ( emp_id NUMBER ) IS
BEGIN
DELETE FROM emp
WHERE empno = emp_id;
END fire_employee;
END emp_actions;