Upload
gersonhincapiediuza
View
37
Download
1
Tags:
Embed Size (px)
DESCRIPTION
introduccion a oracle y pl/sql
Citation preview
Introducción a Oracle SQL y PL/SQL
Introducción Se transforma requerimientos del negocio dentro de una base de datos operacional.
Estrategia y análisis Diseño Construcción y documentación Transición
Producción
Una BD es una colección de información organizada, hay 4 tipos jerárquica, red,
relacional y relacional de objetos
Concepto de BD relacional
Colección de objetos o relaciones
Un grupo de operadores pueden actuar en las relaciones para producir otras relaciones
Integridad de los datos para exactitud y consistencia
Definición de una BD relacional
Es una colección de relaciones o tablas en dos dimensiones
Modelos de datos
Son la piedra angular del diseño ayudan a entender lo que quiere el cliente.
Modelos ER
Los datos son divididos dentro de categorías discretas o entidades, un modelo de
relación entre entidades es una ilustración de varias entidades en el negocio y la
relación entre estas, los modelos separan la información requerida por los negocios de
las actividades de estos.
Componentes
Entidad : Objeto que representa la información que se necesita
Atributo : Describe o califica la entidad
Relación : Asociación entre entidades mostrando opcionalidad y grado(cardinalidad).
Identificadores únicos
Son una combinación de atributos o relaciones o ambos, este hace que cada
ocurrencia de una entidad sea única Símbolo #, secundario (#)
Relacionando múltiples tablas
Cada tabla contiene datos que describen exactamente una entidad, las categorías de
los datos son listados en los atributos y los casos individuales en las filas.
Las llaves foráneas son basadas en valores de datos y son puramente lógicos, no
físicos, apuntadores.
Propiedades de una BD relacional
Puede ser accedida y modificada con sentencias structured query language (SQL) el
cual permite comunicarse con el servidor
Contiene una colección de tablas
Usa un grupo de operadores
Sistema de BD relacional
Se puede almacenar y administrar datos con todas las ventajas de la estructura
relacional PL/SQL
Oracle 8 : Sistema de administración de BD relacionales de objetos
Provee una nueva máquina que trae programación orientada a objetos, tipos de datos
complejos, objetos de negocio complejos y total compatibilidad con el mundo
relacional.
Usuario define tipos de datos y objetos
Soporta objetos grandes y multimedía
2
Oracle 8i : BD en plataforma internet
Contiene herramientas avanzadas para administrar todos los tipos de datos en web
sites.
iFS Internet File System combina el poder de Oracle 8i con el fácil uso de un FS, los
usuarios pueden fácilmente acceder a los archivos y folders en un iFS usando una
variedad de protocolos como HTML, FTP, IMAP4 .
Oracle 8i incluye una robusta, integrada y escalable máquina virtual de java dentro
del servidor Jserver
O8i provee full integración con Microsoft Transaction Server (MTS)
Plataforma de internet Oracle
Para e-commerce y data warehousing es construida en 3 piezas principales
1. Clientes Browser based para procesar presentación
2. Servidores de aplicación para ejecutar lógica de los negocios y lógica de la
presentación para clientes browser-based
3. Bases de datos para ejecutar lógica de negocios intensiva y servicio de datos
Sentencias SQL
SELECT Recuperación de datos
INSERT DML
UPDATE
DELETE
CREATE DDL
ALTER
DROP
RENAME
TRUNCATE
COMMIT Control transaccional
ROLLBACK
SAVEPOINT
GRANT Lenguaje de control de datos (DCL)
REVOKE
Hacerca de PL/SQL Es una extención de SQL , la manipulación de datos y las
sentencias de consulta de SQL son incluidas dentro de unidades de código
procedimentales
Ambiente PL/SQL Un bloque PL/SQL es procesado por la máquina PL/SQL la cual
puede residir dentro de la herramienta o dentro del servidor.
Cuando se invoca PL/SQL desde un programa, SQL *Plus o server manager, lo
procesa el servidor , este separa las sentencias SQL y las envia individualmente al
ejecutor de sentencias SQL
PL/SQL
BLOCK Ejecutor de sentencias
procedimentales
EJECUTOR DE SENTENCIAS SQL
Máquina PL/SQL
Servidor Oracle
PL/SQL
BLOCK
3
Capítulo 1 escribiendo sentencias SQL básicas
Capacidades de las sentencias SQL
Se recupera información usando SELECT haciendo.
Selección : Para elegir filas de una tabla
Proyección : Elegir columnas
Join : Trae datos almacenados en diferentes tablas
SELECT [DISTINCT] (*, column [alias])
FROM table;
Escribiendo sentencias SQL
Sentencia SQL pueden ser entradas en una o más líneas
Las palabras clave no pueden ser divididas a través de líneas
Dentro de SQL*Plus una sentencia SQL es entrada en el prompt, y las líneas
siguientes son numeradas , esto se llama SQL buffer
Para seleccionar todas las filas con * o enunciándolas todas en el SELECT.
Encabezados por default de las columnas
Justificación : Fecha y carácteres a la izquierda, Números a la derecha
Default : Mayúsculas
Expresiones aritméticas Pueden contener operadores aritméticos + - / *
Nota : SQL*Plus ignora espacios en blanco antes y después del operador
Precedencia de operadores * / + - , operadores de la misma precedencia son
evaluados de izquierda a derecha, los paréntesis alteran la precedencia.
Definiendo valores NULL Es diferente de cero (número ) espacio (carácter) , es
unavailable, unassigned, unknow, en expresiones aritméticas toda se vuelve NULL.
Definiendo alias Renombra el encabezado de la columna, sigue al nombre de la
columna AS es opcional, se requiere comillas dobles si tiene espacios o carácteres
especiales, Para que el alias no salga en mayúsculas encerrarlo en comillas dobles.
Operador de concatenación | | Se combinan las columnas para que haya una sola
salida.
SELECT ename||job AS “Employes”
FROM emp;
Strings de carácteres literales Un literal es un carácter, número o fecha incluido en
el SELECT.
Deben ser encerrados en comillas simples
Cada literal sale una vez por cada fila retornada
SELECT ename | | ‘ is a ‘ | | job AS “Emplye Details”
FROM emp;
Eliminar filas duplicadas DISTINCT , UNIQUE
Interacción de SQL y SQL*Plus
SQL es un lenguaje de comandos para comunicarse con el servidor, cuando se entra
una sentencia, esta se almacena como parte de la memoria llama SQL buffer y ahí se
mantiene mientras no se entre otra sentencia.
SQL*Plus Es una herramienta que reconoce y ejecuta sentencias SQL, acepta
entradas SQL de archivos, provee un editor para modificar sentencias SQL, controla
el ambiente.
4
SQL SQL*Plus
Lenguaje Reconoce sentencias SQL
Es ANSI Interfaz propietaria de
Oracle para ejecutar sentencias SQL
Manipula datos y definiciones de tablas No manipula valores en la BD
Queda en un buffer SQL Es entrado líneas a líneas al tiempo, no
es
Almacenado en el SQL buffer
No tiene carácter de continuación Si tiene (-)
No puede ser abreviado Si puede ser abreviado
Usa carácter de terminación Se ejecuta inmedíatamente
Usa funciones para formatear datos Usa comandos para formatear
SQL*Plus
Categoría Propósito
Environment Afecta en general todas las sentencias SQL para la sesión
Format Formatea resultados de la consulta
File Manipulatión Saves, Loads y corre archivos de scripts
Executión Envia sentencias SQL del buffer al servidor
Edit Modifica sentencias SQL en el buffer
Interacción Permite que se pase y se cree variables para sentencias SQL
Miscellaneous Contiene varios comandos para conectarse a la BD, manipular
el ambiente y desplegar definiciones de columnas
DESC[RIBE] tablename
Comandos de edición de SQL*Plus
Comando Descripción
A[PPEND] text Adiciona texto al final de la líneas corriente
C[HANGUE] text/old/new Cambia texto viejo por nuevo en la líneas corrienta
C[HANGUE] /text/ Borra texto de la líneas corriente
CL[EAR] BUFF[ER] Borra todas las líneas del SQL buffer
DEL Borra la líneas corriente
I[NPUT] Inserta un número indefinido de líneas
I[NPUT] text Inserta una líneas con el texto
L[IST] Lista todas las líneas en el SQL buffer
L[IST] n Lista la líneas n
L[IST] m n Lista las líneas entre m y n
N Especifica la líneas a ser la líneas corriente
n text Reemplaza la líneas n con el texto
0 text Inserta una líneas antes de la líneas 1
Command Descripción
SAV[E] filename [.ext] Salva las líneas corrientes del SQL buffer a un archivo
[REP[LACE]APP[END]]
GET filename[.ext] Trae un archivo salvado al SQL buffer
STA[RT] filename[.ext]
@filename
ED[IT] Invoca al editor y salva el buffer corriente en afiedt.buf
EDIT [Filename[.ext]]
SPO[OL] [filaname[.ext]]
OFF|OUT
EXIT
5
Capítulo 2 Restringiendo y ordenando datos
Se usa la clausula WHERE para restringir datos, Comparando valores de columnas,
literales, expresiones aritméticas y funciones.
Fechas y cadenas de carácteres
Son encerrados en columnas simples, los carácteres son sensitivos, el formato por
default de las fechas es DD-MON-YYYY
SELECT ename
FROM emp
WHERE ename = ‘JAMES’;
BETWEEN : Desplegar un rango de valores
IN : Para comparar con una lista
LIKE : Comparar con un patrón de carácteres, usar comodines %, _ , se pueden
combinar los comodines. Se puede usar la opción de ESCAPE.
SELECT * FROM dept WHERE dname LIKE ‘%\_%’ ESCAPE ‘ \ ‘ ;
IS NULL : Para encontrar valores NULL, no se pueden encontrar con =
Operadores lógicos
AND : NULL and FALSE = FALSE
OR : NULL and TRUE = TRUE
NOT : NULL and TRUE = NULL
Reglas de precedencia
1 todos los operadores de comparación, 2 NOT , 3 AND y 4 OR, se alteran con
paréntesis.
ORDER BY : Para ordenar ASC, DESC, si no se usa el orden es indefinido, se
pueden organizar resultados por más de una columna.
6
Capítulo 3 Funciones de una sola fila
Aceptan argumentos y siempre retornan valores.
Hay 2 tipos
1. De una sola fila : Operan en una sola fila y retornan un solo valor por fila
Carácter : Aceptan carácteres y retornan valores de carácteres o números
Numéricas : Aceptan números y retornan números
Fechas : Aceptan fechas retornan fechas excepto MONTHS_BETWEEN
Conversión : Convierten un valor de un tipo a otro
General : NVL, DECODE
2. De multiples filas : Manipulan un grupo de filas y dan un resultado por cada
grupo
Manipulan items de datos, los argumentos pueden ser Constantes, Variables,
Columnas, Expresiones. Actuan en cada fila del query, pueden retornar valores de un
tipo diferente al referenciado
Function_name (column | expression, [arg1, arg2...])
Funciones de carácter
Hay 2 tipos : De conversión, De manipulación de caracteres
LOWER (column | expresión ) course
UPPER (column | expresión) COURSE
INITCAP (column | expresión) Course
CONCAT (column | expresión, column | expresión ...)
SUBSTR (column | expresión,m,n)
LENGHT (column | expresión ) : Retorna el número de carácteres
INSTR (column | expresión,m) : Retorna la posición numérica del carácter enunciado
LPAD (column | expresión , n ,’string’) : Pega en n posicones un carácter
justificando a la derecha
TRIM (leading | trailing | both, trim_character FROM trim_source )
TRIM (‘S’ FROM ‘SSMITH’) = MITH
Funciones numéricas
ROUND (column | expresión , n ) : Redondea el valor a n lugares decimales
TRUNC (column | expresión , n ) : Trunca la columna a n valores decimales, si n es
omitido quita los decimales ( Si es negativo los números a la izquierda del decimal
son convertidos a cero (0) )
MOD (m , n ) : Retorna el residuo de la división de m entre n
ROUND (45.923 , 2 ) = 45.92
ROUND (45.923 , 0 ) = 46
ROUND (45.923 , -1 ) = 50
TRUNC (45.923 , 2 ) = 45.92
TRUNC (45.923 , 0 ) = 45
TRUNC (45.923 , -1 ) = 40
ROUND y TRUNC pueden ser usadas con funciones de fechas
Trabajando con fechas
Oracle almacena las fechas en un formato interno numérico, siglo, año, mes, día,
horas, minutos, segundos
El formato default es DD – MON – YY
SYSDATE función que retorna la fecha y el tiempo corrientes
DUAL es una tabla de SYS para cumplir con la sintaxis debido a que el SELECT y el
FROM son obligatorios.
7
Aritmética con fechas
Operación Result Descripción
Date + number Date Adiciona un número de días
Date – date Número días Sustrae una fecha e otra
Date + number/24 Date Adiciona número de horas
Funciones de fecha
MONTHS_BETWEEN(date1,date2) : Meses entre las dos fechas negativo o positivo
(’01-SEPT-95’,’11-JAN-94’) = 19.6774194
ADD_MONTHS(date,n): n positivo o negativo
(’11-JAN-94’,6) = ’11-JUL-94’
NEXT_DAY(date, ‘char’) : Encuentra la fecha de el próximo día especificado de la
semana.
(‘01-SEPT-95’,’FRIDAY’) = ’08-SEPT-95’
LAST_DAY(date) : Encuentra el ultimo día del mes
(’01-SEPT-95’) = ’30-SEPT-95’
ROUND(date[,fmt]) : Retorna la fecha en la unidad especificada en el format model,
si el format model es omitido la fecha es redondeada al día mas cercano.
ROUND(’25-JUL-95’,’MONTH’) 01-AUG-95
ROUND(’25-JUL-95’,’YEAR’) 01-JAN-96
TRUNC(date[,fmt]) : Retorna la fecha con el tiempo de la porción del día truncada
TRUNC(’25-JUL-95’,’MONTH’) = 01-JUL-95
TRUNC(’25-JUL-95’,’YEAR’) = 01-JAN-95
Conversión de tipos de datos implícita
Para evaluación de expresiones
VARCHAR2 o CHAR NUMBER
VARCHAR2 o CHAR DATE
----
NUMBER VARCHAR2
DATE VARCHAR2
Conversión explicita
TO_CHAR(number | date,[fmt],[nlsparams]) : nlsparams especifica carácter decimal,
separador de grupo, símbolo de moneda local, símbolo de moneda internacional o las
abreviaciones para el día el mes , tiene un elemento fm para remover blancos o
suprimir ceros
TO_NUMBER(char,[fmt],[nlsparams]) : Convierte un string de caracteres que
contienen dígitos a un número en el formato especificado.
TO_DATE(char,[fmt],[nlsparams]) : Si fmt es omitido se usa el default DD-MON-
YY
Elementos del modelo del formato de fecha
YYY
YEAR
MM Mes en dos dígitos
MONTH Nombre completo del mes
DY Abreviación de tres letras para el día de la semana
DAY
SCC o CC Siglos S prefijo BC con –
IYYY,IYY,IY,I 4, 3 ,2 1 digito del año basado en el estándar ISO
RM mes en números romanos
WW o W semana del año o del mes
DDD o DD o D día del año, mes o semana
J día juliano
HH24:MI:SS AM 15:45:32 PM
DD “ of ” MONTH 12 of OCTOBER
8
Número de sufijos para números
Ddspth fourteenth
AM o PM Indicador de meridiano
A.M o P.M Indicador de meridiano con periodos
HH o HH12 o HH24 Hora del día u hora (1-12) u hora (0-23)
MI Minuto de 0-59
SS Segundo de 0-59
SSSS Segundos pasados la media noche (0-86399)
/. , Puntuación es reproducida en el resultado
TH Número ordinario (Ej DDTH para 4TH)
SP Ej DDSP para FOUR
SPTH o THSP Ej DDSPTH para FOURTH
Usando función TO_CHAR con fechas
SELECT ename, TO_CHAR(hiredate, ‘fmDD Month YYYY’)
FROM emp
KING 17 November 1981
Usando función TO_CHAR con números
TO_CHAR(number,’fmt’)
9 Determina longitud del número 9999 1234
0 Despliega ceros 0999 001234
$ Signo flotante de dólar $999 $1234
L Símbolo de moneda local flotante L999 FF1234
. 9.999 1.234
, 9,999 9,999
MI Signo menos a la derecha 99MI 1234-
PR Paréntesis para números negativos 99PR <1234>
EEEE Notación científica 99.999EEEE 1.234E+03
V Multiplicar por 10 n veces
(n número de 9s después de la V) 9V99 100
B Desplegar valores de ceros como
Blancos, no 0 B9999.99 1234.00
SELECT TO_CHAR(sal , ‘$99,999’ )
FROM emp
$3,000
Formato de fecha RR
YY y RR son inversos
Ultimos dos dígitos
RR YY
0-49 Si año corriente superior después El siglo corriente
50-99 Si año corriente superior siglo antes El siglo corriente
Función NVL
NVL (expr1, expr2 ) convierte a números, fechas y char o varchar2
Función DECODE
Fácilita el trabajo condicional como el CASE
DECODE (col/expresión , search1 , result1
[ , search2 , result2 , ..... ,]
[ , default ]
Si el default es omitido retorna NULL si la cadena no coincide con ninguna condición
9
SELECT job, sal,
DECODE( job, ‘ANALYST’ , SAL*1.1,
‘CLERK’ , SAL*1.15,
SAL )
FROM emp;
Funciones anidadas
Funciones de una sola fila pueden ser anidadas a cualquier nivel , y son evaluadas
desde la más profunda a la menos profunda. o sea de adentro hacia fuera
10
Capítulo 4 desplegando datos de múltiples tablas Se trabaja haciendo JOIN entre las tablas, generalmente si se tienen n tablas se
necesitan n-1 joins para la consulta, esto no es cierto todo el tiempo Ej. Si la llave
primaria es compuesta.
Producto cartesiano
Se da cuando una condición de JOIN es omitida, es invalida, todas las filas de la
primera tabla son cruzadas con todas las filas de la segunda tabla emp 14 dept 4 = 56
Tipos de joins
Equijoin : La columna debe ser igual en las dos tablas
Se utiliza el nombre de la tabla como prefjo table.columna, esto mejora performance,
y evita ambigüedad si hay columnas con el mismo nombre en tablas diferentes. Se
usan en SELECT, WHERE y ORDER BY.
Para condiciones adicionales se utiliza los operadores como AND.
Usando alias para las tablas
Máximo 30 carácteres
Non-equijoin : Cuando la columna de una tabla no corresponde directamente a la
columna de otra Ej. BETWEEN, <=, >=
Outer-join : Se coloca a un lado de la expresión, no en los dos, se coloca al lado
donde no hay información (+), no puede usar el operador IN.
Self-join : Cruzar una tabla consigo misma
11
Capítulo 5 Agregando datos usando funciones de grupo
Funciones de grupo operan en juegos de filas para dar un resultado por grupo, estas
filas pueden ser toda la tabla o divididas por grupos.
Tipos de funciones de grupo
AVG(DISTINCT | ALL | n ) Promedio de n ignorando valores NULL, números
COUNT({* | [ DISTINCT | ALL ] expr} ) Incluye nulos
MAX( [ DISTINCT | ALL ] expr ) Ignora nulos, todos los tipos de datos
MIN ([ DISTINCT | ALL ] expr ) Ignora nulos, todos los tipos de datos
STDDEV ( [ DISTINCT | ALL ]x) Desviación standar de n ignora nulos, números
SUM ( [DISTINCT | ALL ] n )
VARIANCE ( [DISTINCT | ALL ]x ) Varianza de n, ignora nulos
El servidor Oracle implícitamente ordena los resultados ascendentemente cuando usa
GROUP BY, para cambiar el orden usar ORDER BY.
Funciones de grupo y valores NULL
Todas las funciones de grupo ignoran valores NULL en la columna excepto COUNT.
Para incluir valores NULL se usa NVL.
SELECT (AVG(NVL(comm,0)))
FROM emp;
Para crear grupo GROUP BY
SELECT column , group_function(column)
FROM table
[WHERE condition ]
[GROUP BY group_by_expression ]
[ORDER BY column ]
Clausula GROUP BY
No se puede usar los alias de las columnas
Todas las columnas que no estan en una función de grupo deben estar en la clausula
GROUP BY.
Las columnas del GROUP BY pueden no estar en la lista del select.
Se puede agrupar por mas de una columna, grupos dentro de los grupos.
No se puede usar WHERE para restringir grupos para esto se usa HAVING, filas son
agrupadas, se aplica funcion de grupo, se despliega las que coincidan con HAVING.
Las funciones de grupo pueden ser anidadas a una profundidad de 2.
12
Capítulo 6 subqueries
Se pueden colocar en : WHERE , HAVING, FROM
SELECT select_list
FROM table
WHERE exp operator
( SELECT select list
FROM table);
Los operadores de comparación caen en dos clases una sola fila ( <, >,=,< >,<=,>= ) y
multiples filas (IN, ALL, ANY )
El sub query se ejecuta primero y su salida completa el query total.
No adicionar una clausula ORDER BY a un subquery.
Tipos de subqueries : De una sola fila, multiples filas, multiples columnas
Se pueden usar funciones de grupo en los subqueries
SELECT ename, job
FROM emp
WHERE sal = ( SELECT MIN(sal) FROM emp );
SELECT deptno , MIN(sal)
FROM emp
GROUP BY deptno
HAVING MIN(sal) > (SELECT MIN(sal) FROM emp WHERE deptno = 20);
Subqueries de multiples filas
Operador Significado
IN Igual a cualquier miembro de la lista
ANY Compara el valor con cada valor retornado de la lista
ALL Compara el valor con todos los valores de la lista
SELECT empno
FROM emp
WHERE sal < ANY ( SELECT sal FROM emp WHERE job= ‘CLERK’)
AND job <> ‘CLERK’;
SELECT empno
FROM emp
WHERE sal > ALL ( SELECT AVG(sal) FROM emp GROUP BY deptno);
El operador NOT puede ser usado con ANY, IN , ALL
13
Capítulo 7 Subqueries de multiples columnas
SELECT column, ...
FROM table
WHERE (column, column, ... ) IN ( SELECT column, column, ...
FROM table
WHERE condition );
Las comparaciones pueden ser pairwise o nonpairwise
SELECT column, ...
FROM table
WHERE column1 IN ( SELECT column FROM table WHERE condition )
AND column2 IN ( SELECT column FROM table WHERE condition );
El SELECT no retorna filas si se utiliza NOT IN y en el subquery hay un NULL
debido a que NOT IN es eqwuivalente a ¡=ALL.
IN es equivalente =ANY
Usando un subquery en la clausula FROM
SELECT a.ename, a.sal, b.salvg
FROM emp a, (SELECT deptno, avg(sal) salvg FROM emp GROUP BY deptno )
WHERE a.deptno = b.deptno
14
Capítulo 8 Produciendo salidas legibles con SQL * Plus
Con & se almacenan valores temporalmente.
&user_variable Indica una variable en una sentencia SQL, si la variable no existe
SQL*Plus se la pide al usuario
SET VERIFY ON|OFF Se usa para confirmar los cambios en la sentencia SQL , este
forza a SQL*Plus a desplegar texto antes y despues de reemplazar las variables con
los valores.
Las variables de fecha o carácter deben ser encerradas entre comillas simples.
Se puede especificar variables para columnas, como condición en el ORDER BY , en
el from.
La variable &&
Para utilizar la reusar la variable sin tener que preguntar, SQL*Plus almacena el valor
usándole comando DEFINE, una vez el valor es colocado se necesita UNDEFINE
para resetear la variable.
Para definir variables se utiliza
DEFINE variable = value el cual crea una variable char y asigna el valor a esta.
DEFINE variable muestra la variable su valor y su tipo de dato
DEFINE despliega todas las variables del usuario
ACCEPT variable [datatype] [FORMAT format] [PROMPT text ] [HIDE]
Lee la líneas de la entrada por el usuario y almacena esto en una variable en donde
Datatype : es NUMBER, CHAR o DATE (CHAR tiene una longitud máxima de 240
bytes
Format : Especifica el formato Ej. A10 o 9.999
Hide : esconde la entrada del usuario por seguridad
En el comando ACCEPT no se le coloca & a la variable
Tips
DEFINE y ACCEPT crrean la variable si esta no existe
Se debe definir explícitamente un NUMBER o FECHA para variables de este tipo
DEFINE y UNDEFINE
Las variables permanecen mientras no se les de UNDEFINE o se salga de SQL*Plus,
se puede verificar los cambios con DEFINE, para definir variables para cada sessión,
se debe modificar el archivo login.sql asi las variables son creadas en el startup
Personalizando EL ambiente de SQL*Plus
Con comandos SET
SET system_variable value
Para verificar los valores seteados se usa SHOW
SQL>SET ECHO ON
SQL>SHOW ECHO
Echo ON
Para ver todas las variables
SHOW ALL
ARRAY [SIZE] {20 | n }El tamaño para el fetch de los datos
COLSEP {_ | text }Setea el texto a ser impreso entre columnas default es el espacio
FEDD[BACK] {6 | n | OFF | ON } Despliega el número de registros devueltos por
una consulta cuando selecciona por los menos n registros
HEA[DING] {ON | OFF } Determina el encabezado
LIN[SIZE] {80 | n} El número de carácteres por líneas
LONG {80 | n} Setea el máximo para desplegar valores LONG
PAGES[IZE] {24 | n} Número de líneas por pagina
PAU[SE] {OFF | ON | text} controla el scroll de la terminal
15
TERM[OUT] {OFF | ON } Determina si la salida es desplegada enla pantalla
El archivo login.sql contiene los SET estandar y otros comandos SQL*Plus que se
implementan en el login.
COL[UMN] [column option ] Controla el formato de las columnas
TTI[TLE] [text |OFF | ON ] Especifica el encabezado de cada pagina
BTI[TLE] [text |OFF | ON ] Especifica el pie de cada pagina
BRE[AK] [ON report_element ]
Si se da un alias a la columna este debe ser especificado, no el nombre de la columna
El comando COLUMN
COL[UMN] [ {column | alias } [ option ] ]
CLE[AR] limpia cualquier formato de columna
FOR[MAT] format Cambia el despliegue de una columna usando el formato
HEA[DING] text Setea el encabezado de la columna ( una barra vertical (|) forza un
line feed )
JUS[TIFY] {aling} Justifica el encabezado de la columna derecha, izq o centro
NOPRI[NT] no imprime la columna
NUL[L] text Especifica el texto a ser desplegado para valores NULL
PRI[NT] muestra la columna
TRU[NCATED] Trunca el string al final de la primera líneas desplegada
WRA[PPED]
COLUMN ename HEADING ‘Employee|name’ FORMAT A15
COLUMN sal JUSTIFY LEFT FORMAT $99,999.00
COLUMN mgr FORMAT 9999999 NULL ‘no manager’
COL[UMN] ename Despliega los valores corrientes para una columna
COL[UMN] ename CLE[AR] Limpia los valores seteados para la columna
CLE[AR] COL[UMN] Limpia los valores seteados para todas las columnas
Si se tiene un comando muy largo se puede continuar colocando (-)
Modelos de formato de columnas
An despliega un ancho n
9 Solo digitos 9999 1234
0 Fuerza al cero lider 099999 01234
$ Símbolo de dólar $9999 $1234
L Moneda local L9999 L1234
.
,
El servidor Oracle despliega (#) si el número excede el tamaño dado en el formato,
tambien si el valor e alfanumerico mientras el actual es numerico
BREAK ON ename ON job Suprime duplicados para asegurar que trabaja
correctamente usar ORDER BY.
BREAK ON ename SKIP 4 ON job SKIP 2
BREAK on column [ |alias|row ] [skip n | dup | page ] on .. [on report ]
Donde
page Tira una nueva pagina cuando el valor del break cambia
skip n Salta un número de líneas cuando el valor cambia
break se activa con columna, fila , pagina, reporte
duplicate despliega valores duplicados
Para limpiar todos los juegos de BREAK usar CLEAR
CLEAR BREAK
16
Capítulo 9 Manipulando datos Una transacción consiste en un grupo de sentencias DML que forman una unidad
lógica de trabajo.
Para insertar nulos implícitamente omitir la columna, explícitamente colocar ‘NULL’
y ‘ ‘ Para carácteres y fechas.
Para insertar valores especiales como fechas el formato ‘DD-MON-YYYY’ debe ser
usado de lo contrario se cambia con la funcion TO_DATE. Y el tiempo default es
00:00:00. Si se setea el formato RR el siglo puede no ser el corriente.
Se puede insertar valores usando variables de sustitución.
INSERT INTO dept (deptno, dname )
VALUES ( &department, &name );
Estos le serán pedidos al usuario al momento de ejecutar la sentencia. Se puede usar
ACCEPT.
Se puede hacer INSERT en una tabla de datos de otra con un subquerie.
Para actualizar datos con UPDATE.
Para actualizar datos con subqueries de multiples columnas.
UPDATE emp
SET (job, deptno ) = ( SELECT job, deptno FROM emp WHERE empno = 7988 )
WHERE empno = 7698;
Se puede borrar filas de una tabla basado en valores de otra.
DELETE FROM employ
WHERE deptno = ( SELECT deptno FROM dept WHERE dname = ‘SALES’);
Transacciones de BD
Consiste de .
Grupo de DMLs
Un DDL
Un DCL
Las transacciones dan mas flexibilidad y control y aseguran consistencia en el caso de
que el proceso el sistema fallen.
Controlando transacciones
COMMIT, SAVEPOINT name, ROLLBACK [TO SAVEPOINT name]
Procesamiento implicito de transacciones
Un COMMIT se da cuando hay DDL, DCL o se sale normalmente de SQL*Plus.
Un ROLLBACK se da cuando hay una salida anormal de SQL*Plus o falla el sistema
Existe el comando AUTOCOMMIT OFF|ON.
Antes de COMMIT o ROLLBACK, las filas afectadas son bloqueadas para que no
sean cambiadas.
Después del COMMIT las filas bloqueadas son liberadas, todos los savepoints son
borrados.
Se puede hacer marcas SAVEPOINT para el ROLLBACK. Si se crea un segundo
SAVEPOINT con el mismo nombre el primero es desacrtado.
El servidor Oracle implementa un SAVEPOINT implícito.
17
Si un DDL falla, el usuario no puede volver a los datos anteriores porque este tiene
autocommit.
Consistencia de lectura
Garantiza una vista consistente de los datos todo el tiempo.
Cambios hechos por un usuario no tienen conflicto con los cambios hechospor otro
usuario.
El propósito es asegurar que cada usuario mire los datos como estaban con el ultimo
COMMIT, antes de que la operación DML arrancara.
El LOCKING es efectivo debido a que previene acciones destructivas entre
operaciones concurrentes.
No requiere acción de l usuario
Usa el nivel mas bajo de restricción.
Permanece por el tiempo que dure la transacción.
Tiene dos modos Exclusive : Previene que un recurso sea compartido la primera
transacción bloquea el recurso exclusivamente y Shared
18
Capítulo 10 Creando y administrando tablas Tabla Unidad básica de almacenamiento
Vista Representan un subgrupo de datos de una o mas tablas
Secuencia Genera valores para PK
Index Mejora performance
Sinónimo Da nombres alternativos a los objetos
El tamaño de una tabla es definido por la cantidad de espacio asignado. El nombre
debe comenzar por una letra, 1-30 carácteres , A-Z, a-z, 0-9, _,$ y #
Create table
Se debe tener el privilegio CREATE TABLE, es un DDL estos tienen un efecto
inmedíato en la BD y graban información en el diccionario de datos.
CREATE [ GLOBAL TEMPORARY ] TABLE [schema.]table
(column datatype [DEFAULT expr ] [, .... ]);
GLOBAL TEMPORARY : La tabla es temporal y su definición es visible para todas
las sesiones, los datos de esta son visibles solo para la sesión que inserta datos.
DEFAULT expr : Especifica el valor por default si este es omitido en el INSERT,
expr puede ser un valor literal, expresión o una función SQL.
Hiredate DATE DEFAULT SYSDATE, ....
Un esquema es una colección de objetos, los objetos son estructuras lógicas que se
refieren directamente a datos en la BD, si la tabla no pertenece al usuario debe llevar
el prefijo del dueño.
Tablas en la BD Oracle
USER_
ALL_
DBA_
V$_ Vistas de performance dinamicas
Para las tablas del usuario USER_TABLES, objetos USER_OBJECTS, tablas, vistas,
sinónimos y secuencias USER_CATALOG CAT
Tipos de datos
LONG Longitud variable máximo 2G
CLOB Carácter single-byte maximo 4G
RAW y LONG RAW Datos binarios raw max 2000B
BLOB Datos binarios maximo 4G
BFILE Datos binarios max 4G
CREATE TABLE [ ( column1, column2, ... ) ]
AS subquery
Cuando se utilize una expresión se da un alias a la columna.
ALTER TABLE ADD|MODDIFY|DROP (column datatype [DEFAULT expr], ... )
Solo una columna puede ser borrada al tiempo.
ALTER TABLE table SET UNUSUED (column);
O
ALTER TABLE table SET UNUSUED column, column;
ALTER TABLE table DROP UNUSUED COLUMNS;
19
DROP TABLE table;
Los sinonimos permanecen pero son invalidos, cualquier transacción pendiente es
commited, lo puede hacer el dueño o usuarios con grant DROP ANY TABLE.
Para cambiar el nombre de una tabla, vista, secuencia o sinónimo.
RENAME old_name TO new_name;
Truncando una tabla
Libera el espacio de almacenamiento usado por la tabla, DELETE no. No se puede
hacer ROLLBACK, lo hace el dueño o un usuario con el grant DELETE TABLE.
Adicionando comentarios
COMMENT ON TABLE table | COLUMN IS ‘xxxxxxx’; para consultar
ALL_COL_COMMENTS, USER_COL_COMMENTS, ALL_TAB_COMMENTS,
USER_TAB_COMMENTS.
20
Capítulo 11 Incluyendo constraints Forzan las reglas a nivel de tabla
Previenen el borrado de una tabla con dependencias
NOT NULL :
UNIQUE : Especifica una columna o columnas cuyo valor debe ser unico
PRIMARY KEY
FOREIGN KEY
CHECK : Especifica una condición que debe ser verdadera.
El nombre del constraint es por default SYS_Cn, se puede crear con la tabla o
después, se hace a nivel de tabla o columna, son almacenados en diccionario de datos,
USER_CONSTRAINTS.
CREATE TABLE [schema.]table
(column datatype [DEFAULT expr]
[column constraint ],
....
[ table_constraint ] [, ... ]);
column_name datatype CONSTRAINT const_name NOT NULL...
UNIQUE KEY permite nulos a menos que se le especifique NOT NULL se puede
definir a nivel de tabla o columna, Oracle crea un indice unico
CREATE TABLE deptno ( deptno NUMBER(2),
Dname VARCHAR2(14),
CONSTRAINT dept_name_uk UNIQUE (dname));
CREATE TABLE deptno ( deptno NUMBER(2),
Dname VARCHAR2(14),
CONSTRAINT dept_name_pk PRIMARY KEY (deptno));
CREATE TABKE emp
(....
deptno NUMBER (2) CONSTRAINT emp_deptno_fk FOREIGN KEY (deptno )
REFERENCES dept(deptno),
.....
);
ON DELETE CASCADE permite el borrado en la tabla padre y las filas dependientes
en las tablas hijas.
CHECK no se puede usar CURRVAL, NEXTVAL, LEVEL y ROWNUM ni
llamadas a SYSDATE, UID, USER y USERENV, se pueden definir mas de uno por
columna a nivel de columna o de tabla.
ALTER TABLE table ADD [ CONSTRAINT constraint ] type (column );
Para adicionar constraint NOT NULL con MODIFY.
ALTER TABLE table DROP PRIMARY KEY | UNIQUE (column) |
CONSTRAINT constraint [CASCADE];
ALTER TABLE table DISABLE CONSTRAINT constraint [CASCADE];
Se puede deshabilitar un constraint en la creación de una tabla o con un ALTER.
ALTER TABLE table ENABLE CONSTRAINT constraint;
21
Se se habilita UNIQUE o PRIMARY KEY un indice se crea automaticamente, un
constraint se puede habilitar en la creación de la tabla o con ALTER.
CASCADE CONSTRAINTS
Se usa con DROP COLUMN, borra todos los constraints dependientes, borra
constraints multicolumnas.
USER_CONSTRAINTS, USER_CONS_COLUMNS.
22
Capítulo 12 Creando vistas
Es una tabla lógica basada en una tabla o en otra vista, no contiene datos , se usan
para restringir acceso a los datos, para hacer consultas complejas fáciles.
Hay 2 clasificaciones de vistas simples y complejas.
CREATE VIEW [OR REPLACE] [FORCE | NOFORCE] VIEW view
[ (alias, ....) ]
AS subquery
[WITH CHECK OPTION [CONSTRAINT constraint]]
[WITH READ ONLY ];
El subquery puede ser complejo, no puede contener ORDER BY.
FORCE crea la vista indiferentemente si existe o no la tabla.
WITH CHECK OPTION Especifica que solo filas accequibles por la tabla pueden ser
actualizadas o insertadas.
Se pueden usar alias en el subquery.
En USER_VIEWS , la sentencia SELECT esta en una columna LONG.
Se puede hacer operaciones DML en vistas simples, no se puede remover una fila si
contiene : funciones de grupo, GROUP BY , DISTINCT, ROWNUM.
No se puede modificar una vistas si cumple con lo anterior, columnas definidas por
expresiones.
No se puede adicionar si cumple con lo anterior, hay columnas NOT NULL en las
tablas base que no son seleccionadas por la vista.
Usando WITH CHECK OPTION
Asegura que los DML en la vista permanezcan dentro del dominio de la vista
Se puede forzar constraints a nivel de BD.
DROP VIEW view;
Solo el dueño o quien tenga DROP ANY VIEW.
Inline views
Es una subconsulta con un alias que se pued usar dentro de la sentencia SQL, no es
un objeto del esquema.
SELECT a.ename, b.maxsal
FROM emp a,(SELECT deptno, max(sal) maxsal FROM emp GROUP BY deptno) b
WHERE a.deptno = b.deptno
Analisis TOP-N
SELECT [column_list], ROWNUM
FROM (SELECT [column_list] FROM table ORDER BY top_N_column)
WHERE ROWNUM<= N;
ROWNUM asigna un valor a cada columna iniciando con 1.
En la clausula WHERE la cual especifica n filas a ser retornadas, debe usar < o <=.
23
Capítulo 13 Otros objetos de BD
Que es una secuencia
Automáticamente genera números unicos, es compartida, se usa generalmente para
crear valores de llave primaria, reemplaza código de la aplicación, veloz acceso
cuando esta en cache.
CREATE SÉQUENCE séquence
[INCREMENT BY n ]
[START WITH n ]
[{MAXVALUE n | NOMAXVALUE}]
[{MINVALUE n | NOMINVALUE} ]
[{CYCLE | NOCYCLE}]
[{CACHE n | NOCACHE}]
CACHE n | NOCACHE : Especifica cuantos valores serán preasignados y colocados
en memoria (Por default 20 valores ).
USER_SECUENCES, la columna LAST_NUMBER despliega el proximo número
disponible de la secuencia.
Sequence.NEXTVAL : Retorna el proximo número disponible, retorna un unico valor
cada vez que es llamado, sequence.CURRVAL :Retorna el vlor corriente de la
secuencia NEXTVAL debe ser usado antes de que CURRVAL contenga un valor.
Pueden ser usados :
En la lista de un SELECT que no es parte de un subquery
En la lista de un SELECT de un subquery de un INSERT
En la clausula VALUES
En la cláusula SET de un UPDATE
No se pueden usar :
Una lista de un SELECT de un vista
Un SELECT con DISTINCT
Un SELECT con GROUP BY, HAVING o ORDER BY
Un subquery de un SELECT, DELETE o UPDATE
Una expresión por default en CREATE TABLE o ALTER TABLE
Saltos en la secuencia se pueden dar cuando hay ROLLBACK, falla del sistema la
secuencia es usada en otra tabla.
Se puede ver el proximo valor disponible de la secuencia en USER_SEQUENCES si
fue creada NOCACHE.
Modificando una secuencia
Se puede cambiar el valor de incremento, máximo, minimo, ciclo y cache.
ALTER SEQUENCE séquense
[INCREMENT BY n]
[{MAXVALUE n | NOMAXVALUE}]
[{MINVALUE n | NOMINVALUE}]
[{CYCLE | NOCYCLE}]
[{CACHE n | NOCACHE}]
Se debe ser el dueño o tener el GRANT ALTER ANY SEQUENCE.
DROP SEQUENCE sequence; El dueño o tener DROP ANY SEQUENCE.
24
Que es un indice
Es un objeto, acelera la recuperación de filas, reduce I/O utilizando un metodo de
acceso de camino rapido, es independiente de la tabla, es mantenido por el servidor.
Automáticos : PK, UNIQUE
Manuales : no unicos creados por el usuario
CREATE INDEX index ON table (column,[column,...]);
Se crea cuando la columna es frecuentemente usada en el WHERE, la columna
cintiene un amplio rango de valores, contiene un gran número de valores NULL, la
tabla es grande y la mayoria de los querys esperan del 2-4% de las filas.
No se deben usar cuando la tabla es actualizada frecuentemente y las inversas de lo
anterior.
USER_INDEXES, USER_IND_COLUMNS.
Indices basados en función.
Es un indice basado en expresiones, la expresión se construye con columnas,
constantes, funciones SQL y funciones definidas por el usuario.
CREATE INDEX index ON table (expr)
Para asegurarse de que se usa el indice debe aasegurarse que el valor de la función es
NOT NULL.
SELECT * FROM emp WHERE UPPER(ename) IS NOT NULL;
DROP INDEX; El dueño o tener DROP ANY INDEX;
Sinonimos
Simplifica el acceso a los objetos, el objeto no puede estar contenido en un paquete.
CREATE SYNONYM [PUBLIC] FOR object;
DROP SYNONYM synonym;
Solo el DBA borra sinonimos publicos.
25
Capítulo 14 Controlando acceso a los usuarios
Se tiene seguridad del sistema y seguridad de los datos.
Los privilegios del sistema dan acceso a la BD. Hay mas de 80.
CREATE USER, DROP USER, DROP ANY TABLE, BACKUP ANY TABLE.
CREATE USER user IDENTIFIED BY password;
GRANT privilege [, privilege, ... ] TO user;
Un desarrollador puede tener CREATE SESSION para conectarse, CREATE
TABLE, CREATE SEQUENCE, CREATE VIEW, CREATE PROCEDURE.
Role
Grupo de privilegios relativos que pueden ser concedidos al usuario.
CREATE ROLE role;
ALTER USER user IDENTIFIED BY new_pwd; Se debe tener el privilegio ALTER
USER.
Un grant para el sinonimo es convertido en un grant para la tabla base referenciada
por el sinonimo.
GRANT object_priv [(columns)] ON object TO [USER | role | PUBLIC]
[WITH GRANT OPTION];
WITH GRANT OPTION se revoca en cascada
ROLE_SYS_PRIVS Privilegios del sistema concedidos a los roles
ROLE_TAB_PRIVS Privilegios de las tablas concedidos a los roles
USER_ROLE_PRIVS Roles accesibles por el usuario
USER_TAB_PRIVS_MADE Privilegios de objeto concedidos a los objetos del
usuario
USER_TAB_PRIVS_RECD Privilegios de objeto concedidos al usuario
USER_COL_PRIVS_MADE Privilegios de objeto concedido a las columna de los
objetos del usuario
USER_COL_PRIVS_RECD Privilegios de objeto concedidos al usuario en columnas
especificas
REVOKE {privilege [, privilege ...] | ALL} ON object FROM {user [,user...] | role |
PUBLIC} [ CASCADE CONSTRAINTS ];
CASCADE CONSTRAINTS : Remueve cualquier constraint de integridad
referencial hechos al objeto por medio de REFERENCES
26
Capítulo 16 Declarando variables
PL/SQL es una extensión de SQL con carácterísticas de lenguaje de programación,
brinda integración, mejora performance, PL/SQL puede ser usado como un grupo de
sentencias SQL dentro de un solo bloque y lo envian al servidor en una sola llamada,
reduciendo tambien trafico en la red.
PL/SQL puede cooperar con herramientas de desarrollo como Developer, Forms y
Reports, adicionando procesamiento procedimental.
Estructura de bloque PL/SQL que es estructurado por bloques.
DECLARE
xxxxxxxxxxxxxxxxx
BEGÍN
xxxxxxxxxxxxxxxxx
EXCEPTION
xxxxxxxxxxxxxxxxx
END;
Tipos de bloques
Anónimos : no tienen nombre, se puede envolver un bloque anónimo dentro de un
programa precompilado y dentro de SQL*Plus o server manager. Triggers en Oracle
Developer.
Subprogramas : Procedimientos y funciones, toman parametros y pueden ser
invocados
Función o procedimiento de aplicación : Bloque PL/SQL con nombre almacenado
en una aplicación desarrollada por Oracle o en una librería compartida que puede
aceptar parámetros y puede ser invocada repetidamente.
Uso de variables : Para almacenamiento temporal, manipulación de valores,
reusabilidad y fácil mantenimiento %ROWTYPE, %TYPE
Las variables se declaran en la sección declarativa, se asignan en la sección
ejecutable, se pueden pasar a los procedimientos como IN, OUT, IN OUT
Tipos de variables :
Scalar : Sostienen un solo valor
Tipos de datos compuestos : Registros
Tipos de datos de referencia
Lob
Variables de tipo no PL/SQL incluyen variables del host declaradas en programas
precompilados. Campos de pantalla en formas y variables del host en SQL*Plus.
Identifier [CONSTANT] datatype [NOT NULL] [ := | DEFAULT expr]
Una constante debe ser inicializada en su declaración.
Las variables no deben llevar el mismo nombre de las columnas de un tabla.
SELECT empno
INTO empno
FROM emp;
Las variables se asiganan con := , INTO o FETCH
G_mgr NUMBER(4) DEFAULT 1334;
27
V_location VARCHAR2(13) NOT NULL := ‘CHICAGO’;
Tipos de datos escalares
Tienen un solo valor y no tienen componentes internos, pueden ser clasificados en 4
categorias número (integer, positive), carácter, boolean y date
Varchar2 32,767B
Date 4712 B.C 9999 A.D
Long Carácter
Long Raw Datos binarios no es interpretada por PL/SQL
Binary_integer
%TYPE declara la variable de acuerdo a una columna u otra variable previamente
declarada. Es fácil de mantener si se hacen cambios a nivel de BD.
V_ename emp.ename%TYPE;
V_balan NUMBER(7,2);
V_min v_balan%TYPE;
NOT NULL no aplica a variables declaradas con %TYPE.
Eb variables booleanas expresiones aritméticas pueden ser usadas para retornar un
valor booleano.
V_com BOOLEAN := (v_sal1 < v_sal2);
Tipos de datos compuestos : TABLE referencia y manipula colecciones de datos
como un objeto, RECORD trata tipos de datos relacionados pero disimilares como
una unidad lógica, NESTED TABLE y VARRAY
LOB : Almacena bloques de datos sin estructura 4GB
CLOB almacena grandes bloques de carácteres single-byte
BLOB objetos binarios on-line/off-line
BFILE
NCLOB single-byte o fixed-width multibyte in line o out of line.
Variables BIND
Se declara en el ambiente del host y se usa para pasar valores runtime, para ser
pasadas a uno o mas programas PL/SQL a menos que sean procedimientos, funciones
o paquetes, esto incluye variables decalradas en programas precompilados , campos
de pantalla
Para declararlas en el ambiente SQL*Plus
VARIABLE ret NUMBER
VARIABLE ret VARCHAR2(30)
Para desplegarlas
PRINT ret (no pude ser usado en un bloque PL/SQL)
Para referenciarlas
Con (:) como prefijo asi.
VARIABLE g_mon NUMBER
DECLARE
BEGÍN
:g_mon := 12;
END;
28
DBMS_OUTPUT.PUT_LINE alternativa para desplegar datos en un bloque
PL/SQL, se debe habilitar SQL*Plus con SET SERVER OUTPUT ON
Ámbito y visibilidad de variables
La variable será local para el bloque en el que ha sido declarada y global para los
bloque hijos de éste, mientras que las variables declaradas en los bloque hijos no son
globales a los bloques padre.
Subtipos definidos por el usuario
Un subtipo es un tipo PL/SQL que se basa en otro tipo existente. Los subtipos pueden
emplearse para dar nombres alternativos a un tipo. La sintaxis es:
SUBTYPE nuevo_tipo IS tipo_original;
donde nuevo_tipo es el nombre del nuevo subtipo y tipo_original designa el tipo
base. Éste puede ser un tipo predefinido o un subtipo o una referencia %TYPE. Por
ejemplo:
DECLARE
SUBTYPE t_LoopCounter IS NUMBER; -- Define el nuevo subtipo
v_LoopCounter t_LoopCounter; -- Declara una variable del
subtipo
SUBTYPE t_NameType IS students, first_name%TYPE;
La definición del subtipo no puede ser restringida de modo directo. El siguiente
bloque sería ilegal:
DECLARE
SUBTYPE t_LoopCounter IS NUMBER(4); -- Restricción incorrecta
Sin embargo, hay una forma de evitar esta limitación, declarando una variable ficticia
del tipo deseado (con la restricción) y utilizando %TYPE en la definición del subtipo:
DECLARE
v_DummyVar NUMBER(4); --Variable ficticia que no se usa
SUBTYPE t_LoopCounter IS v_DummyVar%TYPE; -- Devuelve
NUMBER(4)
v_Counter t_LoopCounter; -- Declara una variable del subtipo
<<l_Outer>>
DECLARE
v_AvailableFlag BOOLEAN;
v_SSN NUMBER(9);
BEGIN
DECLARE
v_SSN CHAR(11);
v_StartDate DATE;
BEGIN
END;
END;
v_AvailableFlag y
v_SSN son visibles 1
2
3 v_AvailableFlag y
v_SSN son visibles
v_AvailableFlag, v_SSN CHAR(11) y
V_StartDate son visibles. Si queremos
acceder a v_SSN NUMBER(9) debemos
usar l_Outer.v_SSN.
29
Las declaraciones de variables de un subtipo no restringido también pueden
restringir el tipo:
DECLARE
SUBTYPE t_Numeric IS NUMBER; -- Define un subtipo no
restringido
v_Counter is t_Numeric(5); -- y una variable restringida
Los subtipos se consideran de la misma familia que el tipo base.
30
Capítulo 17 Escribiendo sentencias ejecutables
Las unidades léxicas pueden estar separados por Espacios, delimitadores (+,-,=..),
identificadores, literales y comentarios.
Identificadores
Pueden contener 30 letras, deben comenzar con una letra, no palabaras reservadas a
menos que se encierren entre comillas, no puede tener el mismo nombre de una
columna de una tabka de la BD.
Literales Es un número, carácter, cadena o valor booleano no representado por un
identificador
Carácteres y fechas deben ir encerrados entre comillas
Números pueden ir solos o en notación científica (2E5)
Un bloque PL/SQL termina con /
Para comentar una sola líneas ( - -) varias líneas (/* */)
Funciones SQL en PL/SQL
Numéricas de una sola fila
De carácter de una sola fila
Conversión
Date
PL/SQL funciones
Reporte de errores
miscellaneous
No disponibles DECODE o funciones de grupo (SUM,MAX,MIN ....)
CHR(10) Convierte el código ASCII a su correspondiente carácter
Bloques anidados
Sentencias pueden estar anidadas donde quiera que una sentencia es permitida
Un bloque anidado comienza con una sentencia
La sección de excepciones puede contener bloques anidados
El alcancé de un objeto es la región donde puede ser referenciado, aplica a todos los
objetos declarados incluyendo variables, cursores, excepciones definidas por el
usuario y constantes.
Operadores en PL/SQL
Las operaciones se hacen en orden de acuerdo a la precedencia tenemos operadores
Lógicos
Aritméticos
Concatenación
Paréntesis
Operador exponencial (**)
Guias de programación
Identar código
Documentar con comentarios
Convenciones de nombres para identificadores y otros objetos
31
Capítulo 18 Interactuando con el servidor Oracle
Sentencias SQL en PL/SQL
Usando SELECT solo un grupo de valores puede ser retornado, se hace cambios en
las filas con DML, control de transacciones con COMMIT, ROLLBACK o
SAVEPOINT.
PL/SQL no es una unidad transaccional, no soporta DDL, DCL tal como GRANT o
REVOKE.
SELECT select_list
INTO {variable_name [ , variable_name, ...]
| record_name }
FROM table
WHERE condition;
INTO es obligatoria para variables de PL/SQL o del host.
Funciones de grupo no pueden ser usadas en PL/SQL solo en SQL.
Para manipular datos con DML en PL/SQL con DELETE, INSERT, UPDATE,
COMMIT o ROLLBACK.
Insertando datos no hay posibilidad de ambigüedad con los identificadores y los
nombres de las columnas, cualquier identificador en el INSERT debe ser un nombre
de una columna de la BD.
La asignación en PL/SQL siempre con := en SQL =.
Para evitar ambigüedad en el WHERE columnas e la BD e identificadores deben
tener nombres diferentes, los errores de sintaxis pueden darse debido a que PL/SQL
chequea primero la BD para ver si es una columna.
No hay posibilidad de ambigüedad en el SELECT ni en el FROM.
COMMIT y ROLLBACK
La transacción inicia con el primer comando DML después de un COMMIT o un
ROLLBACK.
COMMIT o ROLLBACK se usan para terminar explícitamente la transacción.
COMMIT [WORK];
SAVEPOINT savepoint_name;
ROLLBACK [WORK];
ROLLBACK [WORK] TO [SAVEPOINT] savepoint_name;
Cursores SQL : Es un área privada de memoria hay 2 tipos implícitos utilizados por
el servidor para parsear y ejecutar SQL y explícitos creados por el programador.
Usando atributos de cursor SQL , se puede verificar la salida.
SQL%ROWCOUNT Número de filas afectadas
SQL%FOUND atributo booleano especifica que fueron afectadas filas
SQL%NOTFOUND
SQL%HISOPEEN siempre es falso debido a que PL/SQL cierra los cursores
implícitos inmedíatamente después de haber sido ejecutados.
Ejecutando SQL dentro de bloques PL/SQL
PL/SQL es un lenguaje de programación de base de datos. Casi todos los programas
que escribiremos en PL/SQL leerán desde, o escribirán en, una base de datos Oracle
utilizando SQL. Aunque estas series asumen que se conoce SQL, debemos estar
conscientes de la forma en que llamamos a las sentencias desde un bloque PL/SQL.
32
Y aquí hay algunas buenas noticias: Oracle hace que sea muy fácil escribir y
ejecutar sentencias SQL en PL/SQL. La mayor parte de las veces, simplemente
escribiremos las sentencias SQL directamente en nuestro bloque PL/SQL y después
agregaremos el código necesario para la interfaz entre las sentencias SQL y el código
PL/SQL.
Supongamos, por ejemplo, que tenemos una tabla llamada empleados, con una
columna clave primaria id_empleado, y una columna apellido. Podemos ver el
apellido del empleado con ID 138, como sigue:
SELECT apellido
FROM empleados
WHERE id_empleado = 138
Ahora querríamos ejecutar esta misma consulta dentro de nuestro bloque PL/SQL y
desplegar el nombre. Para hacer esto, necesitaremos “copiar” el apellido desde la
tabla a una variable local, lo cual podemos hacer con la cláusula INTO:
DECLARE
v_apellido empleados.apellido%TYPE;
BEGIN
SELECT apellido
INTO v_apellido
FROM empleados
WHERE id_empleado = 138;
DBMS_OUTPUT.put_line(v_apellido);
END;
Primero declaramos una variable local, y haciendo esto introducimos otra
carácterística elegante de PL/SQL: la capacidad de fijar el tipo de datos de nuestra
variable en función del tipo de datos de una columna en una tabla (esto será
profundizado más adelante en esta serie)
Después ejecutamos una consulta contra la base, obteniendo el apellido del empleado
y asignándolo directamente en la variable v_apellido.
Por supuesto, querremos hacer más que ejecutar sentencias SELECT en PL/SQL,
también querremos insertar, modificar y eliminar datos desde PL/SQL. Aquí hay
ejemplos de cada uno de esos tipos de sentencias DML:
• Eliminamos todos los empleados en el departamento 10 y mostramos cuántas tuplas
fueron eliminadas:
DECLARE
v_id_departamento empleados.id_departamento%TYPE := 10;
BEGIN
DELETE FROM empleados
WHERE id_departamento = v_id_departamento;
DBMS_OUTPUT.put_line(SQL%ROWCOUNT);
END;
Referenciamos la variable PL/SQL directamente dentro de la sentencia DELETE.
Cuando el bloque se ejecuta, la variable se reemplaza con el valor actual, 10, y el
DELETE es ejecutado por el motor de SQL. SQL%ROWCOUNT es un atributo
especial de cursor que retorna el número de tuplas modificadas por la última
sentencia DML ejecutada en nuestra sesión.
• Modificar todos los empleados en el departamento 10 con un 20% de incremento
salarial.
DECLARE
33 v_id_departamento empleados.id_departamento%TYPE := 10;
BEGIN
UPDATE empleados
SET salario = salario * 1.2
WHERE id_departamento = v_id_departamento;
DBMS_OUTPUT.put_line(SQL%ROWCOUNT);
END;
Insertar un nuevo empleado en la tabla.
BEGIN
INSERT INTO empleados (id_empleado
, apellido
, id_departamento
, salario)
VALUES (100
, 'Feuerstein'
, 10
, 200000);
DBMS_OUTPUT.put_line(SQL%ROWCOUNT);
END;
En este bloque, proveímos los valores de las columnas como literales, en lugar de
variables, directamente dentro de la sentencia SQL.
34
Capítulo 19 Escribiendo estructuras de control
Se puede controlar el flujo lógico de las sentencias usando condicionales IF y LOOP
IF –THEN –END IF
IF –THEN –ELSE –END IF
IF –THEN –ELSIF –END IF
IF condición THEN
Sentencias;
[ELSIF condición THEN
sentencias;]
[ELSE
sentencias;]
END IF;
Condición : Es una variable o expresión booleana.
THEN : Asocia la condición con la secuencia de sentencias que la siguen
Si la condición es falsa o NULL no se ejecutan las sentencias.
En IF anidados, estos deben terminar con su correspondiente END IF;
Es preferible usar ELSIF que IF anidados.
Se puede manejar valores NULL con IS NULL
Una expresión aritmética que contenga nulos se vuelve nula.
En la concatenación el null es tratado como un espacio vacio.
NULL AND FALSE = FALSE
NULL OR TRUE = TRUE
NOT NULL = NULL
Sentencias LOOP
LOOP basico
For loop : control iterativo basado en un contador
While loop : control iterativo basado en una condición
Exit : Termina un loop
LOOP
Sentencias;
EXIT [WHEN condición];
END LOOP;
LOOP FOR
FOR contador in [REVERSE]
Lower_bound..upper_bound LOOP
Ssentencias;
END LOOP;
El rango pueden ser literales, variables, expresiones.
Se referencia el contador dentro del loop solo si es indefinido fuera de este.
WHILE LOOP
WHILE condición LOOP
Sentencias;
END LOOP;
Se repite mientras la condición sea TRUE. Si la condición es NULL el loopes pasado.
35
Los loops se pueden anidar , se puede usar labels para distiguir entre loops
(<<label>>) se colocan antes de LOOP, se puede salir del loop con EXIT
referenciando el label, el label se puede incluir en el END LOOP por claridad
BEGIN
<<outer_loop>>
LOOP
EXIT WHEN v_count > 10
<<inner_loop>>
LOOP
EXIT outer_loop WHEN total = ‘YES’
EXIT inner_loop WHEN inner_done = ‘YES’
END LOOP inner_loop;
END LOOP outer_loop;
END;
36
Capítulo 20 Trabajando con tipos de datos compuestos
Registros PL/SQL
Tablas PL/SQL
Nested tables
Varray
Contienen componentes internos son reusables, es utiliza el RECORD para tratar
datos dissimilares como una unidad lógica, se usa TABLE para referenciar y
manipular colecciones de datos como un objeto.
Un registro es un grupo de datos relacionados almacenados en campos, que tienen su
nombre y su tipo de datos, una tabla contiene columnas y su llave primaria.
Son convenientes para sacar filas de datos de una tabla para procesamiento.
A los registros se les pueden asignar valores iniciales o definirlos como NOT NULL,
hay registros anidados.
TYPE type_name IS RECORD
{ field_declaration [,field_declaration...]};
Field_declaration field_name { field_type | variable%TYPE | table.column%TYPE |
table%ROWTYPE }
[ [NOT NULL] {:= DEFAULT } expr ]
Para referenciar los campos de un registro: record_name.field_name, su alcanze es
en el bloque o subprograma donde fue definido.
El atributo %ROWTYPE
Declara una variable de acuerdo a una colección de columnas en una tabla o vista de
la BD
DECLARE
Emp_record emp%ROWTYPE;
Ventajas de usar ROWTYPE
Desconocimiento de los campos de una tabla
Los campos cambian runtime
DECLARE
emp_rec emp%ROWTYPE;
BEGIN
SELECT * INTO emp_rec
FROM emp;
END;
Tablas PL/SQL
Tienen dos componentes * PK de tipo de datos BINARY_INTEGER, * columnas
escalaras o tipo de dato de registro.
Se incrementa dinámicamente. Son similares a un arreglo
TYPE type_name IS TABLE OF
{column_type | variable%TYPE | table.column%TYPE} [NOT NULL]
[INDEX BY BINARY_INTEGER]
TYPE ename_table_type IS TABLE OF emp.ename%TYPE
INDEX BY BINARY_INTEGER;
Ename_table ename_table_type;
No pueden ser incializadas en su declaración. Se referencian
pl_sql_table_name(primary_key_values), la PK puede ser negativa
37
Usando metodos de tablas PL/SQL
Table_name.method_name[(parameters)]
EXISTS(n) Retorna TRUE si el elemento en la posición existe
COUNT Número de elementos de una tabla PL/SQL
FIRST Retorna el primero y el ultimo número de indice, NULL si esta
LAST vacia
PRIOR(n) Retorna número de indice que precede al indice n
NEXT(n) Retorna número de indice que sucede al indice n
EXTEND(n,i) * Incrementa el tamaño de la tabla
EXTEND agrega un elemento nulo
EXTEND(n) agrega n elementos nulos
EXTEND(n,i) agrega n copias de el elemento i
TRIM * remueve un elemento del final
TRIM(n) remueve n elementos del final
DELETE Remueve todos los elementos de la tabla
DELETE(n) remueve el elemento n
DELETE(m,n) Remueve elemenetos en el rango m..n
Para referirse a los elementos de una tabla
Table(index).campo
38
Capítulo 21 Escribiendo cursores explícitos
El servidor implícitamente abre un cursor para procesar sentencias SELECT no
asociadas con un cursor explícito.
Cursores Implícitos
Los cursores implícitos se utilizan para realizar consultas SELECT que devuelven
un único registro.
Deben tenerse en cuenta los siguientes puntos cuando se utilizan cursores
implícitos:
Con cada cursor implícito debe existir la palabra clave INTO.
Las variables que reciben los datos devueltos por el cursor tienen que contener
el mismo tipo de dato que las columnas de la tabla.
Los cursores implícitos solo pueden devolver una única fila. En caso de que se
devuelva más de una fila (o ninguna fila) se producirá una excepción. No se
preocupe si aún no sabe que es una excepción, le valdrá conocer que es el
medio por el que PL/SQL gestiona los errores.
El siguiente ejemplo muestra un cursor implícito:
declare
vdescripcion VARCHAR2(50);
begin
SELECT DESCRIPCION
INTO vdescripcion
from PAISES
WHERE CO_PAIS = 'ESP';
dbms_output.put_line('La lectura del cursor es: ' ||
vdescripcion);
end;
La salida del programa generaría la siguiente línea:
La lectura del cursor es: ESPAÑA
Excepciones asociadas a los cursores implícitos.
Los cursores implícitos sólo pueden devolver una fila, por lo que pueden producirse
determinadas excepciones. Las más comunes que se pueden encontrar son
no_data_found y too_many_rows. La siguiente tabla explica brevemente estas
excepciones.
Excepción Explicación
NO_DATA_FOUND Se produce cuando una sentencia SELECT intenta recuperar datos
pero ninguna fila satisface sus condiciones. Es decir, cuando "no hay
datos"
TOO_MANY_ROWS Dado que cada cursor implícito sólo es capaz de recuperar una fila ,
esta excepción detecta la existencia de más de una fila.
Cursores explícitos
Procesa cada fila retornada por un SELECT de multiples filas. El grupo de filas
retornado es llamdo grupo activo, se guarda un rastro de cual es la fila corriente, el
programador lo controla manualmente.
Se usa OPEN ejcuta el query asociado, identifica el grupo activo y la posición del
cursor , FETCH recupera la fila corriente y avanza el cursor a la proxima fila,
CLOSE deshabilita el cursor y libera lass filas.
CURSOR cursor_name IS
Select_statement;
39
Abriendo el cursor
OPEN cursor_name;
Dinamicamente asigna memoria para el área de contexto, Parsea el SELECT, obtiene
posiciones de memoria de las variables de entrada, identifica el grupo activo,
posiciona el puntero justamente antes de la primera fila.
Si no retorna filas no se da una excepción , perso se puede probar la salida con los
atributos del cursor.
Para cursores declarados FOR UPDATE, se bloquean las filas.
FETCH cursor_name INTO [variable1, ... | record_name ];
Recupera la fila corriente dentro de variables, incluye el mismo número de variables,
se debe probar el curosr para ver si contiene filas.
...
Open defined_cursor;
LOOP
FETCH defined_cursor INTO defined_variables;
EXIT WHEN ....;
END LOOP;
...
CLOSE cursor_name;
Se debe cerrar para liberar recursos, esta ligado con el parámetro OPEN_CURSORS.
Atributos : %ISOPEN , %NOTFOUND, %FOUND, %ROWCOUNT número de
filas que trae el cursor.
Toman los valores TRUE, FALSE o NULL dependiendo de la situación:
Atributo Antes de abrir Al
abrir
Durante la
recuperación
Al finalizar la
recuperación
Después de
cerrar
%NOTFOUND ORA-1001 NULL FALSE TRUE ORA-1001
%FOUND ORA-1001 NULL TRUE FALSE ORA-1001
%ISOPEN FALSE TRUE TRUE TRUE FALSE
%ROWCOUNT ORA-1001 0 * ** ORA-1001
* Número de registros que ha recuperado hasta el momento
** Número de total de registros
Para procesar diferentes filas de un cursor de usa un LOOP.
FETCH emp_cursor INTO v_empno;
EXIT WHEN emp_cursor%NOTFOUND OR emp_cursor%NOTFOUND IS NULL;
IS NULL es para asegurarse asi si el FETCH nunca se ejecuta no habra problemas.
Se puede crear registros basados en las filas de un cursor.
DECLARE
CURSOR em IS
SELECT empno, ename
FROM emp;
Emp_record em%ROWTYPE;
BEGIN
OPEN em;
FETCH em INTO emp_record;
END;
Cursor para LOOPS
FOR record_name IN cursor_name LOOP
Sentencias;
END LOOP;
40
Hay implicitamente OPEN, FECTH y CLOSE. y el cursor es implícitamente
declarado.
Cursores en LOOPS que usan subqueries
No se necesita declarar el cursor, y no puede usar los atributos de cursor.
BEGIN
FOR em IN ( SELECT empno FROM emp )
LOOP
Sentencias;
END LOOP;
END;
El siguiente ejemplo ilustra el trabajo con un cursor explícito. Hay que tener en
cuenta que al leer los datos del cursor debemos hacerlo sobre variables del mismo
tipo de datos de la tabla (o tablas) que trata el cursor.
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
CLOSE cpaises;
END;
Podemos simplificar el ejemplo utilizando el atributo de tipo %ROWTYPE sobre
el cursor.
DECLARE
CURSOR cpaises
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES;
registro cpaises%ROWTYPE;
BEGIN
OPEN cpaises;
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
El mismo ejemplo, pero utilizando parámetros:
DECLARE
CURSOR cpaises (p_continente VARCHAR2)
IS
SELECT CO_PAIS, DESCRIPCION, CONTINENTE
FROM PAISES
WHERE CONTINENTE = p_continente;
registro cpaises%ROWTYPE;
BEGIN
OPEN cpaises('EUROPA');
FETCH cpaises INTO registro;
CLOSE cpaises;
END;
Cuando trabajamos con cursores debemos considerar:
Cuando un cursor está cerrado, no se puede leer.
Cuando leemos un cursor debemos comprobar el resultado de la lectura
utilizando los atributos de los cursores.
41
Cuando se cierra el cursor, es ilegal tratar de usarlo.
Es ilegal tratar de cerrar un cursor que ya está cerrado o no ha sido abierto
Cursores de actualización
Los cursores de actualización se declaran igual que los cursores explícitos,
añadiendo FOR UPDATE al final de la sentencia select.
CURSOR nombre_cursor IS
instrucción_SELECT
FOR UPDATE
Para actualizar los datos del cursor hay que ejecutar una sentencia UPDATE
especificando la cláusula WHERE CURRENT OF <cursor_name>.
UPDATE <nombre_tabla> SET
<campo_1> = <valor_1>
[,<campo_2> = <valor_2>]
WHERE CURRENT OF <cursor_name>
El siguiente ejemplo muestra el uso de un cursor de actualización:
DECLARE
CURSOR cpaises IS
select CO_PAIS, DESCRIPCION, CONTINENTE
from paises
FOR UPDATE;
co_pais VARCHAR2(3);
descripcion VARCHAR2(50);
continente VARCHAR2(25);
BEGIN
OPEN cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
WHILE cpaises%found
LOOP
UPDATE PAISES
SET CONTINENTE = CONTINENTE || '.'
WHERE CURRENT OF cpaises;
FETCH cpaises INTO co_pais,descripcion,continente;
END LOOP;
CLOSE cpaises;
COMMIT;
END;
Cuando trabajamos con cursores de actualización debemos tener en cuenta las
siguientes consideraciones:
Los cursores de actualización generan bloqueos en la base de datos.
42
Capítulo 23 Manejando excepciones
Manejando excepciones con PL/SQL
Una excepción es un identificador que se alcanza durante la ejecución cuando ocurre
un error Oracle o cuando se alcanza explícitamente terminando asi las acciones en el
cuerpo principal, se puede manejar atrapándola en un manejador realizando las
acciones finales o propagandola al ambiente llamado.
Se puede alcanzar la excepción explícitamente usando RAISE.
Al atrapar una excepción el procesamiento pasa al manejador de excepciones, si se
maneja exitosamente la excepción, entonces la excepción no se propaga y el bloque
PL/SQL termina con éxito. Si no el bloque PL/SQL falla y la excepción es propagada
al ambiente que fue llamada.
Tipos de excepciones
Predefinidas por Oracle : Aproximadamente 20 errores
No predefinidas por Oracle : Cualquier otro error estandar de Oracle
Definidas por el usuario : Condición que el desarrollador define como anormal
Atrapando excepciones
EXCEPTION
WHEN exception1 [OR exception2 ... ] THEN
Sentencias;
[ WHEN exception3 [ OR exception4 ... ] THEN
sentencias;
]
[ WHEN OTHERS THEN
sentencias;
]
Se puede atrapar cualquier error incluyendo la rutina correspondiente en el
manejador de excepciones, cada manejador consiste de una clausula WHEN.
OTHERS atrapa las excepciones no definidas y por esto es la ultima excepción
definida en el manejador. Solo un manejador es procesado antes de salir del bloque.
Atrapando errores predefinidos
Referenciar el nombre estándar en la rutina de manejo de excepciones.
La siguiente es la lista de las excepciones predeterminadas por PL/SQL y una breve
descripción de cuándo son accionadas:
Excepcion Se ejecuta ... SQLCODE
ACCESS_INTO_NULL El programa intentó asignar valores a los
atributos de un objeto no inicializado -6530
COLLECTION_IS_NULL El programa intentó asignar valores a una
tabla anidada aún no inicializada -6531
CURSOR_ALREADY_OPEN
El programa intentó abrir un cursor que ya se
encontraba abierto. Recuerde que un cursor de
ciclo FOR automáticamente lo abre y ello no
se debe especificar con la sentencia OPEN
-6511
DUP_VAL_ON_INDEX
El programa intentó almacenar valores
duplicados en una columna que se mantiene
con restricción de integridad de un índice
único (unique index)
-1
INVALID_CURSOR El programa intentó efectuar una operación
no válida sobre un cursor -1001
INVALID_NUMBER
En una sentencia SQL, la conversión de una
cadena de carácteres hacia un número falla
cuando esa cadena no representa un número
-1722
43
válido
LOGIN_DENIED El programa intentó conectarse a Oracle con
un nombre de usuario o password inválido -1017
NO_DATA_FOUND
Una sentencia SELECT INTO no devolvió
valores o el programa referenció un elemento
no inicializado en una tabla indexada
100
NOT_LOGGED_ON El programa efectuó una llamada a Oracle sin
estar conectado -1012
PROGRAM_ERROR PL/SQL tiene un problema interno -6501
ROWTYPE_MISMATCH
Los elementos de una asignación (el valor a
asignar y la variable que lo contendrá) tienen
tipos incompatibles. También se presenta este
error cuando un parámetro pasado a un
subprograma no es del tipo esperado
-6504
SELF_IS_NULL El parámetro SELF (el primero que es pasado
a un método MEMBER) es nulo -30625
STORAGE_ERROR La memoria se terminó o está corrupta -6500
SUBSCRIPT_BEYOND_COUNT
El programa está tratando de referenciar un
elemento de un arreglo indexado que se
encuentra en una posición más grande que el
número real de elementos de la colección
-6533
SUBSCRIPT_OUTSIDE_LIMIT
El programa está referenciando un elemento
de un arreglo utilizando un número fuera del
rango permitido (por ejemplo, el elemento “-
1”)
-6532
SYS_INVALID_ROWID
La conversión de una cadena de carácteres
hacia un tipo rowid falló porque la cadena no
representa un número
-1410
TIMEOUT_ON_RESOURCE Se excedió el tiempo máximo de espera por
un recurso en Oracle -51
TOO_MANY_ROWS Una sentencia SELECT INTO devuelve más
de una fila -1422
VALUE_ERROR
Ocurrió un error aritmético, de conversión o
truncamiento. Por ejemplo, sucede cuando se
intenta calzar un valor muy grande dentro de
una variable más pequeña
-6502
ZERO_DIVIDE El programa intentó efectuar una división por
cero -1476
Atrapando excepciones no predefinidas por el servidor
Se la declara, o usando OTHERS, en pl/sql pragma EXCEPTION_INIT llama al
compilador asociando el nombre de la excepción con un número de error Oracle.
PRAGMA significa que la sentencia es una directiva de compilador.
DECLARE
E_emps EXCEPTION;
PRAGMA EXCEPTION INIT ( e_emps, -2292);
BEGÍN
....
EXCEPTION
WHEN e_emps THEN
....
END;
Funciones para atrapar excepciones
44
SQLCODE retorna el valor numerico del error 0 no hay excepción, 1 excepción
definida por el usuario, +100 NO_DATA_FOUND, número negativo otro error
Oracle
SQLERRM retorna el mensaje asociado
DECLARE
V_error_code NUMBER;
V_error_message VARCHAR2(255);
BEGÍN
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
V_error_code := SQLCODE;
V_error_message := SQLERRM;
END;
DECLARE
err_num NUMBER;
err_msg VARCHAR2(255);
result NUMBER;
BEGIN
SELECT 1/0 INTO result
FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
err_num := SQLCODE;
err_msg := SQLERRM;
DBMS_OUTPUT.put_line('Error:'||TO_CHAR(err_num));
DBMS_OUTPUT.put_line(err_msg);
END;
También es posible entregarle a la función SQLERRM un número negativo que represente un error
de Oracle y ésta devolverá el mensaje asociado.
DECLARE
msg VARCHAR2(255);
BEGIN
msg := SQLERRM(-1403);
DBMS_OUTPUT.put_line(MSG);
END;
Atrapando excepciones definidas por el usuario
DECLARE
RAISE
REFERENCE
DECLARE
E_invalid EXCEPTION;
BEGÍN
UPDATE product
SET descrip = “nnnnn “
WHERE prodid = 5;
IF SQL%NOTFFOUND THEN
RAISE e_invalid;
END IF;
EXCEPTION
WHEN e_invalid THEN
ROLLBACK;
END;
45
DECLARE
-- Declaramos una excepcion identificada por VALOR_NEGATIVO
VALOR_NEGATIVO EXCEPTION;
valor NUMBER;
BEGIN
-- Ejecucion
valor := -1;
IF valor < 0 THEN
RAISE VALOR_NEGATIVO;
END IF;
EXCEPTION
-- Excepcion
WHEN VALOR_NEGATIVO THEN
dbms_output.put_line('El valor no puede ser negativo');
END;
RAISE_APPLICATION_ERROR
En ocasiones queremos enviar un mensaje de error personalizado al producirse una
excepción PL/SQL.
Para ello es necesario utilizar la instruccion RAISE_APPLICATION_ERROR;
La sintaxis general es la siguiente:
RAISE_APPLICATION_ERROR(<error_num>,<mensaje>);
Siendo:
error_num es un entero negativo comprendido entre -20001 y -20999
mensaje la descripcion del error
DECLARE
v_div NUMBER;
BEGIN
SELECT 1/0 INTO v_div FROM DUAL;
EXCEPTION
WHEN OTHERS THEN
RAISE_APPLICATION_ERROR(-20001,'No se puede dividir por cero');
END;
Ambientes llamados
SQL*Plus Despliega el número del error y el mensaje en la pantalla
Procedure builder “ “ “
Oracle Developer Forms utiliza ERROR_CODE y ERROR_TEXT
Aplicación precompilada accede al número de la excepción atravez de SQLCA
Bloque PL/SQL atrapa la excepción en el manejador de excepciones
RAISE_APPLICATION_ERROR (error_number, message[ , {TRUE | FALSE}]);
Permite usar mensajes de error definidos por el usuario
Error_number –20000 a –20999
TRUE | FALSE si TRUE los errores en la pila de los errores previos, FALSE el error
default reemplaza los errores previos. Se puede usar en la sección ejecutable y la
sección de excepciones.
DECLARE
fecha DATE;
FUNCTION fn_fecha RETURN DATE
IS
fecha DATE;
BEGIN
SELECT SYSDATE INTO fecha
FROM DUAL
WHERE 1=2;
RETURN fecha;
EXCEPTION
46 WHEN ZERO_DIVIDE THEN
dbms_output.put_line('EXCEPCION ZERO_DIVIDE CAPTURADA
EN fn_fecha');
END;
BEGIN
fecha := fn_fecha();
dbms_output.put_line('La fecha es '||TO_CHAR(fecha,
'DD/MM/YYYY'));
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('EXCEPCION NO_DATA_FOUND CAPTURADA EN
EL BLOQUE PRINCIPAL');
END;
47
Capítulo 24 Ejemplos de PL/SQL Básico
PL/SQL básico
El clásico “¡Hola Mundo!” es un bloque con una sección ejecutable que llama al
procedimiento DBMS_OUTPUT.PUT_LINE para mostrar texto en pantalla:
BEGIN
DBMS_OUTPUT.put_line('¡Hola Mundo!');
END;
Las funciones y procedimientos —tipos de bloques con un nombre— son discutidos
con mayor detalle más adelante en este artículo, así como los paquetes. En pocas
palabras, sin embargo, un paquete es un contenedor de múltiples funciones y
procedimientos. Oracle extiende PL/SQL con muchos paquetes incorporados en el
lenguaje.
El siguiente bloque declara una variable de tipo VARCHAR2 (un string) con un largo
máximo de 100 bytes para contener el string ‘¡Hola Mundo!’. Después, el
procedimiento DBMS_OUTPUT.PUT_LINE acepta la variable, en lugar del literal,
para desplegarlo:
DECLARE
l_mensaje VARCHAR2(100) := '¡Hola Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
END;
Note que he llamado a la variable l_mensaje. Normalmente uso el prefijo l_ para
variables locales —variables definidas dentro del código de un bloque— y el prefijo
g_ para variables globales definidas en un paquete.
El siguiente ejemplo de bloque agrega una sección de manejo de excepciones que
atrapa cualquier excepción (WHEN OTHERS) que pueda ser lanzada y muestra el
mensaje de error, que es retornado por la función SQLERRM (provista por Oracle).
DECLARE
l_mensaje VARCHAR2(100) := '¡Hola Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line(SQLERRM);
END;
El siguiente ejemplo de bloque demuestra la habilidad de PL/SQL de anidar bloques
dentro de bloques así como el uso del operador de concatenación (||) para unir
múltiples strings.
DECLARE
l_mensaje VARCHAR2(100) := '¡Hola';
BEGIN
DECLARE
l_mensaje2 VARCHAR2(100) := l_mensaje || ' Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje2);
END;
EXCEPTION
WHEN OTHERS
THEN
48 DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
END;
Se ejecuta la función “pExeSuiComercial” del paquete
“olbgenerainfosuicomer_48765”. Se envía un mensaje de terminación correcta y de
no ser así se envía el código y mensaje de error respectivo.
BEGIN
olbgenerainfosuicomer_48765.pExeSuiComercial(7,
To_Date('01-04-2013','DD-MM-YYYY'),
To_Date('30-04-2013','DD-MM-YYYY'));
Dbms_Output.put_line('Proceso Ok');
EXCEPTION
WHEN Others THEN
Dbms_Output.put_line(SQLCODE || ':' || SQLERRM);
END;
Ejecutando el PL/SQL
Una vez que hemos escrito un bloque de código PL/SQL éste se puede ejecutar.
Existen muchas herramientas para ejecutar código PL/SQL. La más básica es
SQL*Plus, una interfaz de línea de comandos para ejecutar sentencias SQL así como
bloques PL/SQL. La Figura 1 muestra un ejemplo de ejecución del más simple de los
bloques de ejemplo de nuestro “¡Hola Mundo!” en SQL*Plus.
Figura 1: Ejecutando “¡Hola Mundo!” en SQL*Plus
La primera cosa que hacemos después de conectarnos a la base medíante SQL*Plus
es habilitar la salida del servidor, por lo que las llamadas a
DBMS_OUTPUT.PUT_LINE resultarán en la visualización de texto en la pantalla.
Luego escribimos el código que constituye nuestro bloque. Finalmente, ingresamos
una barra (/) para decirle a SQL*Plus que ejecute ese código.
SQL*Plus entonces ejecuta el bloque y muestra el “¡Hola Mundo!” en la pantalla.
SQL*Plus es provisto por Oracle como una especie de línea base de entorno donde se
pueden ejecutar sentencias SQL y bloques PL/SQL. Mientras que algunos
desarrolladores siguen utilizando únicamente SQL*Plus, la mayoría utiliza un
entorno de desarrollo integrado (IDE). Entre los más populares de estos entornos de
desarrollo (basado en encuestas informales que he tomado en mis sesiones de
entrenamiento) son
SQL Tools
Oracle SQL Developer, de Oracle
Toad y SQL Navigator, de Quest Software
PL/SQL Developer, de Allround Automations
49
Cada herramienta ofrece, con algunas diferencias, ventanas y pasos para crear,
guardar, y ejecutar bloques PL/SQL, así como habilitar y deshabilitar la salida del
servidor.
Otra opción de ejecución es SQL Tools:
Figura 1: Ejecutando “pExeSuiComercial” en SQL Tools
50
Capítulo 25 Subprogramas: procedimientos y funciones
¡Póngale nombre a los bloques!
Todos los bloques que hemos visto hasta el momento son “anónimos”, no tienen
nombres. Si los bloques anónimos fueran la única manera de organizar el código,
sería muy difícil usar PL/SQL para crear una aplicación grande y compleja. Por esto,
PL/SQL soporta la definición de bloques nombrados (named blocks), también
conocidos como subprogramas. Los subprogramas pueden ser procedimientos o
funciones. Generalmente, un procedimiento se utiliza para realizar una acción y una
función se utiliza para calcular y devolver un valor. Voy a tratar sobre subprogramas
con mucho más detalle en un próximo artículo de esta serie. Por ahora, vamos a
asegurarnos de que se comprendan los conceptos básicos detrás de la creación del
subprograma.
Supongamos que necesitamos mostrar "¡Hola Mundo!" desde múltiples lugares en
nuestra aplicación. Queremos evitar la repetición de la misma lógica en todos esos
lugares. Por ejemplo, ¿qué pasa cuando tenemos que cambiar el mensaje, tal vez para
"¡Hola Universo!"? Vamos a tener que encontrar todos los lugares en nuestro código
donde esta lógica aparece.
En su lugar, vamos a crear un procedimiento denominado hola_mundo medíante la
ejecución de la siguiente sentencia DDL (Data Definition Language):
CREATE OR REPLACE PROCEDURE hola_mundo IS
l_mensaje VARCHAR2(100) := '¡Hola Mundo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
END hola_mundo;
Con esto hemos extendido PL/SQL. Además de llamar a los programas creados por
Oracle e instalados en la base de datos (como DBMS_OUTPUT.PUT_LINE),
podemos llamar a nuestro propio subprograma dentro de un bloque PL/SQL:
BEGIN
hola_mundo;
END;
Hemos escondido todos los detalles de cómo decir hola al mundo dentro del cuerpo
(body), o implementación, de nuestro procedimiento. Ahora podemos llamar a este
procedimiento hola_mundo y mostrar el mensaje deseado sin tener que escribir la
llamada a DBMS_OUTPUT.PUT_LINE o averiguar la forma correcta de darle
formato al texto. Podemos llamar a este procedimiento desde cualquier lugar en
nuestra aplicación. Así que si alguna vez necesitamos cambiar ese texto, lo vamos a
hacer en un solo lugar, el único punto de definición de ese texto.
El procedimiento hola_mundo es muy simple. Tus procedimientos tendrán mucho
más código, y casi siempre también tendrán parámetros. Los parámetros pasan
información a los subprogramas, cuando éstos son llamados, y es lo que permite crear
subprogramas más flexibles y genéricos. Se pueden usar en muchos contextos
diferentes.
He mencionado antes que algún día puede ser que desee mostrar "¡Hola Universo!"
en lugar de "¡Hola Mundo!". Podría hacer una copia de nuestro procedimiento
hola_mundo y cambiar el texto que se muestra:
CREATE OR REPLACE PROCEDURE hola_universo IS
l_mensaje VARCHAR2(100) := '¡Hola Universo!';
BEGIN
DBMS_OUTPUT.put_line(l_mensaje);
END hola_universo;
51
Podríamos, sin embargo, terminar con las decenas de variantes del “mismo”
procedimiento hola, que haría muy difícil mantener nuestra aplicación. Un enfoque
mucho mejor es analizar el procedimiento e identificar qué partes se mantienen
incambiadas (son estáticas) cuando el mensaje tiene que cambiar y qué partes
cambian. Luego podemos pasar las partes que cambian como parámetros y tener un
procedimiento único que se puede utilizar en diferentes circunstancias.
Así que vamos a cambiar hola_mundo (y hola_universo) a un nuevo procedimiento,
hola_lugar:
CREATE OR REPLACE PROCEDURE hola_lugar (lugar_in IN VARCHAR2) IS
l_mensaje VARCHAR2(100);
BEGIN
l_mensaje := '¡Hola ' || place_in;
DBMS_OUTPUT.put_line(l_mensaje);
END hola_lugar;
Justo después del nombre del procedimiento, añadimos entre paréntesis de apertura y
cierre, un único parámetro. Podemos tener varios parámetros, pero cada parámetro de
la misma forma básica:
nombre_de_parametro modo_de_parametro tipo_de_datos
En otras palabras, debemos proveer un nombre para el parámetro, el modo o forma en
que éste será usado (IN = sólo lectura), y el tipo de dato que será pasado al
subprograma a través de este parámetro.
En este caso, vamos a pasar un texto de sólo lectura al procedimiento hola_lugar.
Y ahora podemos saludar a nuestro mundo y a nuestro universo como sigue:
BEGIN
hola_lugar('Mundo!');
hola_lugar('Universo!');
END;
Más adelante en esta serie vamos a explorar el concepto de reutilización y la manera
de evitar la repetición, pero debes ser capaz de ver en este ejemplo, el poder de
ocultar la lógica detrás de un bloque con nombre.
Ahora supongamos que no sólo queremos mostrar nuestros mensajes "Hola". A veces
tenemos que mantener los mensajes en una tabla en la base de datos; en otras
ocasiones, tenemos que pasar el texto de nuevo al entorno del cliente para su
visualización en un navegador Web. En otras palabras, necesitamos separar la forma
en que se construyó el mensaje "Hola" de la forma en que se utiliza (se visualiza, se
guarda, se envía otro programa, etc). Podemos alcanzar este nivel deseado de
flexibilidad moviendo el código que construye el mensaje a su propia función:
CREATE OR REPLACE FUNCTION
hola_mensaje(lugar_in IN VARCHAR2) RETURN VARCHAR2 IS
BEGIN
RETURN '¡Hola ' || place_in;
END hola_mensaje;
Este subprograma se diferencia del procedimiento original en lo siguiente:
• El tipo de programa es ahora FUNCTION y no PROCEDURE.
• El nombre del subprograma ahora describe los datos que se devuelven, no las
acciones tomadas.
• El cuerpo o la implementación del subprograma contiene ahora una cláusula
RETURN que construye el mensaje y lo devuelve al bloque llamador.
• La cláusula RETURN después de la lista de parámetros establece el tipo de datos
devuelto por la función.
52
Teniendo el código necesario para construir el mensaje dentro de la función
hola_mensaje, podemos utilizar este mensaje de múltiples maneras. Podemos, por
ejemplo, llamar a la función para obtener el mensaje y asignárselo a una variable:
DECLARE
l_mensaje VARCHAR2(100);
BEGIN
l_mensaje := hola_mensaje('Universo');
END;
Nota que llamamos a la función hola_mensaje como parte de una sentencia PL/SQL
(en este caso, la asignación de un texto a una variable). La función hola_mensaje
devuelve un string, por lo que se puede utilizar en lugar de un string en cualquier
sentencia ejecutable.
También podemos volver a nuestro procedimiento hola_lugar y reemplazar el código
utilizado para crear el string con una llamada a la función:
CREATE OR REPLACE PROCEDURE
hola_lugar(place_in IN VARCHAR2) IS
BEGIN
DBMS_OUTPUT.put_line(hola_mensaje(place_in));
END hola_lugar;
También podemos llamar la función desde una sentencia SQL. En el siguiente
bloque, insertamos el mensaje en una tabla de la base:
BEGIN
INSERT INTO tabla_mensaje(fecha_mensaje, texto_mensaje)
VALUES (SYSDATE, hola_mensaje('Montevideo'));
END;
Aunque la lógica del “mensaje hola” es muy simple, demuestra el poder de asignar
nombres a una o más sentencias ejecutables (un algoritmo) y luego referenciar el
algoritmo simplemente especificando el nombre y los parámetros requeridos.
Los bloques PL/SQL con nombre, permiten construir aplicaciones complejas que
pueden ser comprendidas y mantenidas con relativa fácilidad.
Sobre los nombres en una base Oracle
Ahora que ya se aprecia la importancia de asignar nombres a la lógica, es tiempo de
hablar sobre las reglas para los nombres (o, para ser más precisos, identificadores)
tanto en PL/SQL como, de forma más general, en una base Oracle.
Estas son las reglas para construir identificadores válidos en una base Oracle:
• El largo máximo es de 30 carácteres.
• El primer carácter debe ser una letra, pero cada carácter después del primero puede
ser una letra, un número (0 a 9), un signo de pesos ($), un guión bajo (_), o un
numeral (#). Todos los siguientes son identificadores válidos:
hola_mundo
hola$mundo
hola#mundo
pero estos son inválidos:
1hola_mundo
hola%mundo
• PL/SQL es case-insensitive (no es sensitivo a mayúsculas y minúsculas) con
respecto a los identificadores. PL/SQL trata todos los siguientes como el mismo
53
identificador:
hola_mundo
Hola_Mundo
HOLA_MUNDO
Para ofrecer más flexibilidad, Oracle permite evitar las restricciones de la segunda y
tercera regla, encerrando al identificador entre comillas dobles. Un quoted identifier
(identificador encerrado entre comillas) puede contener cualquier secuencia de
carácteres imprimibles excluyendo las comillas dobles; las diferencias entre
mayúsculas y minúsculas serán además preservadas. Así, todos los siguientes
identificadores son válidos y distintos:
"Abc"
"ABC"
"a b c"
Es muy raro encontrar identificadores entre comillas en código PL/SQL; algunos
grupos de desarrollo los usan para conformar con sus convenciones de nombres o
porque encuentran que una mezcla de mayúsculas y minúsculas resulta más fácil de
leer.
Estas mismas reglas aplican a los nombres de los objetos de base de datos como
tablas, vistas y procedimientos, con una regla adicional: a menos que se encierren
entre comillas los nombres de estos objetos, Oracle los mantendrá en mayúsculas.
Así que cuando creamos un procedimiento como el que sigue:
CREATE OR REPLACE PROCEDURE hola_mundo IS
BEGIN
DBMS_OUTPUT.put_line('¡Hola Mundo!');
END hola_mundo;
la base de datos Oracle lo mantendrá con el nombre HOLA_MUNDO.
En el bloque siguiente, llamaremos este procedimiento tres veces, y aunque el
nombre luzca diferente cada vez, siempre se ejecutará el mismo procedimiento:
BEGIN
hola_mundo;
HOLA_MUNDO;
"HOLA_MUNDO";
END;
Por otro lado, la base Oracle no será capaz de ejecutar el procedimiento si lo
llamamos como sigue:
BEGIN
"hola_mundo";
END;
Esto buscará dentro de la base un procedimiento llamado hola_mundo en lugar de
HOLA_MUNDO.
Si no se quiere que los nombres de los subprogramas se mantengan en mayúsculas,
los nombres se deben encerrar entre comillas cuando se crea el subprograma:
CREATE OR REPLACE PROCEDURE "Hola_Mundo" IS
BEGIN
DBMS_OUTPUT.put_line('¡Hola Mundo!');
END "Hola_Mundo";
54
Capítulo 26 Procedimientos
Procedimientos almacenados
Un procedimiento es un subprograma que ejecuta una acción específica y que no
devuelve ningún valor. Un procedimiento tiene un nombre, un conjunto de
parámetros (opcional) y un bloque de código.
La sintaxis de un procedimiento almacenado es la siguiente:
CREATE [OR REPLACE]
PROCEDURE <procedure_name> [(<param1> [IN|OUT|IN OUT] <type>,
<param2> [IN|OUT|IN OUT] <type>, ...)]
IS
-- Declaracion de variables locales
BEGIN
-- Sentencias
[EXCEPTION]
-- Sentencias control de excepcion
END [<procedure_name>];
El uso de OR REPLACE permite sobreescribir un procedimiento existente. Si se
omite, y el procedimiento existe, se producirá, un error.
La sintaxis es muy parecida a la de un bloque anónimo, salvo porque se reemplaza
la seccion DECLARE por la secuencia PROCEDURE ... IS en la especificación del
procedimiento.
Debemos especificar el tipo de datos de cada parámetro. Al especificar el tipo de
dato del parámetro no debemos especificar la longitud del tipo.
Los parámetros pueden ser de entrada (IN), de salida (OUT) o de entrada salida
(IN OUT). El valor por defecto es IN, y se toma ese valor en caso de que no
especifiquemos nada.
CREATE OR REPLACE
PROCEDURE Actualiza_Saldo(cuenta NUMBER,
new_saldo NUMBER)
IS
-- Declaracion de variables locales
BEGIN
-- Sentencias
UPDATE SALDOS_CUENTAS
SET SALDO = new_saldo,
FX_ACTUALIZACION = SYSDATE
WHERE CO_CUENTA = cuenta;
END Actualiza_Saldo;
También podemos asignar un valor por defecto a los parámetros, utilizando la
clausula DEFAULT o el operador de asiganción (:=). Si un parámetro tiene un valor
predeterminado, no tiene por qué ser pasado desde el entorno que realiza la llamada.
CREATE OR REPLACE
PROCEDURE Actualiza_Saldo(cuenta NUMBER,
new_saldo NUMBER DEFAULT 10 )
IS
-- Declaracion de variables locales
BEGIN
-- Sentencias
UPDATE SALDOS_CUENTAS
SET SALDO = new_saldo,
FX_ACTUALIZACION = SYSDATE
WHERE CO_CUENTA = cuenta;
END Actualiza_Saldo;
55
Una vez creado y compilado el procedimiento almacenado podemos
ejecutarlo. Si el sistema nos indica que el procedimiento se ha creado con errores de
compilación podemos ver estos errores de compilacion con la orden SHOW
ERRORS en SQL *Plus.
Existen dos formas de pasar argumentos a un procedimiento almacenado a la hora
de ejecutarlo (en realidad es válido para cualquier subprograma). Estas son:
Notación posicional: Se pasan los valores de los parámetros en el mismo
orden en que el procedure los define.
BEGIN
Actualiza_Saldo(200501,2500);
COMMIT;
END;
Notación nominal:Se pasan los valores en cualquier orden nombrando
explicitamente el parámetro.
BEGIN
Actualiza_Saldo(cuenta => 200501,new_saldo => 2500);
COMMIT;
END;
Opcionalmente se produce el mismo resultado.
BEGIN
Actualiza_Saldo(new_saldo => 2500,cuenta => 200501);
COMMIT;
END;
Para eliminar un procedimiento usamos:
DROP PRODEDUE nombre_prodecimiento;
Para dar privilegios de ejecución sobre un procedimiento o función usamos:
GRANT EXECUTE ON nombre_prodecimiento TO UsuarioB;
56
Capítulo 27 Funciones
Funciones en PL/SQL
Una función es un subprograma que devuelve un valor.
La sintaxis para construir funciones es la siguiente:
CREATE [OR REPLACE]
FUNCTION <fn_name>[(<param1> IN <type>, <param2> IN <type>, ...)]
RETURN <return_type>
IS
result <return_type>;
BEGIN
return(result);
[EXCEPTION]
-- Sentencias control de excepcion
END [<fn_name>];
El uso de OR REPLACE permite sobreescribir una función existente. Si se omite, y
la función existe, se producirá, un error.
La sintaxis de los parámetros es la misma que en los procedimientos almacenado,
exceptuando que solo pueden ser de entrada.
Ejemplo:
CREATE OR REPLACE
FUNCTION fn_Obtener_Precio(p_producto VARCHAR2)
RETURN NUMBER
IS
result NUMBER;
BEGIN
SELECT PRECIO INTO result
FROM PRECIOS_PRODUCTOS
WHERE CO_PRODUCTO = p_producto;
return(result);
EXCEPTION
WHEN NO_DATA_FOUND THEN
return 0;
END ;
Si el sistema nos indica que el la función se ha creado con errores de compilación
podemos ver estos errores de compilacion con la orden SHOW ERRORS en SQL
*Plus.
Una vez creada y compilada la función podemos ejecutarla de la siguiente forma:
DECLARE
Valor NUMBER;
BEGIN Valor := fn_Obtener_Precio('000100');
END;
Las funciones pueden utilizarse en sentencias SQL de manipulación de datos
(SELECT, UPDATE, INSERT y DELETE):
SELECT CO_PRODUCTO,
DESCRIPCION,
fn_Obtener_Precio(CO_PRODUCTO)
FROM PRODUCTOS;
57
Para eliminar una funcion usamos:
DROP FUNCTION nombre_funcion;
Para dar privilegios de ejecución sobre un procedimiento o función usamos:
GRANT EXECUTE ON nombre_funcion TO UsuarioB;
58
Capítulo 26 Procedimientos
¿Por qué anidar bloques?
Podemos poner BEGIN antes de cualquier conjunto de una o más sentencias
ejecutables seguidas de un END, creando un bloque anidado con esas sentencias. Hay
dos ventajas principales para hacer esto: (1) posponer la asignación de memoria para
variables que se necesitan únicamente en el bloque anidado, y (2) limitar la
propagación de una excepción lanzada por una de las sentencias del bloque anidado.
Consideremos el siguiente bloque:
DECLARE
l_mensaje1 VARCHAR2(100) := 'Hola';
l_mensaje2 VARCHAR2(100) := ' Mundo!';
BEGIN
IF SYSDATE >= TO_DATE('01-JAN-2012')
THEN
l_mensaje2 := l_mensaje1 || l_mensaje2;
DBMS_OUTPUT.put_line(l_mensaje2);
ELSE
DBMS_OUTPUT.put_line(l_mensaje1);
END IF;
END;
El bloque despliega “¡Hola Mundo!” cuando la fecha de hoy (retornada por
SYSDATE) es por lo menos el primer día de 2012; en otro caso, únicamente
despliega el mensaje “Hola”. Aunque este bloque se ejecute en 2011, asigna memoria
para la variable l_mensaje2.
Si reestructuramos este bloque, la memoria para l_mensaje2 será asignada
únicamente después del 2011:
DECLARE
l_mensaje1 VARCHAR2(100) := 'Hola';
BEGIN
IF SYSDATE > TO_DATE('01-JAN-2011')
THEN
DECLARE
l_mensaje2 VARCHAR2(100) := ' Mundo!';
BEGIN
l_mensaje2 := l_mensaje1 || l_mensaje2;
DBMS_OUTPUT.put_line(l_mensaje2);
END;
ELSE
DBMS_OUTPUT.put_line(l_mensaje1);
END IF;
END;
De forma similar, podemos agregar una sección de excepciones a este bloque
anidado, atrapando errores y permitiendo que el bloque exterior continúe con su
ejecución:
DECLARE
l_mensaje1 VARCHAR2(100) := 'Hola';
BEGIN
DECLARE
l_mensaje2 VARCHAR2(5);
BEGIN
l_mensaje2 := ' Mundo!';
DBMS_OUTPUT.put_line(l_mensaje1 || l_mensaje2);
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line(DBMS_UTILITY.format_error_stack);
59 END;
DBMS_OUTPUT.put_line(l_mensaje1);
END;
En este caso, el bloque anidado lanzará una excepción VALUE_ERROR, porque la
variable l_mensaje2 es muy pequeña (máximo de 5 bytes) para el texto “ Mundo!”.La
sección de excepciones del bloque anidado atrapará y desplegará el error. El bloque
exterior continuará su ejecución.
Un posterior artículo en estas series se enfocará en cómo funciona el manejo de
excepciones en PL/SQL.
Más adelante en esta serie de artículos, mostraré cómo controlar el flujo de ejecución
en nuestros bloques: lógica condicional con IF y CASE; lógica iterativa con FOR,
WHILE y LOOP; así como lanzar y manejar excepciones.