Vous êtes sur la page 1sur 61

ProgramandoconPL/SQLenunaBasede DatosOracle

Instructor:Ing.FranciscoRiccio.
OCAOracleDatabaseAdministrator10g OCPOracleDatabaseAdministrator10g OCPOracleDatabaseAdministrator11g OCAOracleApplicationServer10g OracleDatabase10gRACAdministratorCertifiedExpert ManagingOracleonLinuxCertifiedExpert OracleDatabaseSQLCertifiedExpert OracleDatabase11gEssentialsForImplementors MCTSSQLServer2005

Email:francisco@friccio.com

Ing.FranciscoRiccio.

Pgina 1

Contenido
ConsideracionesenlainstalacindelOracleXEyconfiguracindelOracleSQLDeveloper ................ 3 IntroduccinaPL/SQL ....................................................................................................................... 7 Declaracindevariables.................................................................................................................... 9 ManejodeEstructurasdeControl(IF/CASE/LOOP/WHILE/FOR) ...................................................... 14 ManejodeEstructurasComplejas................................................................................................... 19 (Registros/IndexBy/NestedTable/VArray)...................................................................................... 19 ManejodeCursores ........................................................................................................................ 25 ManipulacindeExcepciones.......................................................................................................... 30 ManejodeArchivos......................................................................................................................... 33 CreacindeStoredProceduresyFunciones.................................................................................... 36 CreacinPaquetes........................................................................................................................... 40 CreacindeTriggers ........................................................................................................................ 44 ConsideracionesenelDiseodeCdigoPL/SQL .............................................................................. 51 ProgramacinOrientadaaObjetosenPL/SQL ................................................................................. 58

Ing.FranciscoRiccio.

Pgina 2

Consideracionesen lainstalacindelOracleXEy configuracindelOracleSQLDeveloper


Descargas OracleXE: http://www.oracle.com/technetwork/database/express edition/downloads/index.html OracleSQLDeveloper: http://www.oracle.com/technetwork/developertools/sql developer/downloads/index.html

Descargadoslosproductoseinstalados,seindicalospasosparapodergenerar unaconexinhaciaunabasededatosdesdeelOracleSQLDeveloper.

Ing.FranciscoRiccio.

Pgina 3

DondeenNombredeConexinsecolocaunnombredeidentificacindela conexinquepudierasercualquiernombre. Enusuarioycontraseadebeserunusuariovlidodelabasededatosconsu contrasea,enestecasoestamosutilizandoelusuarioSYSTEMqueexisteenla basededatos. EnloscamposdeNombredeHost,PuertoyNombredelServicio,sondatosque hacenreferenciaallistenerdelabasededatos.Ellisteneresuncomponentede labasededatosqueserresponsablederealizarlaconexinalabasededatos. Estosdatospuedenserextradosenelservidordebasededatospublicandoel comando:lsnrctlstatus,ejemplo:

Ing.FranciscoRiccio.

Pgina 4

Dondelomarcadoconrojosonlosdatosdellistenerquesoncolocadosenel OracleDeveloper.

LuegopodemosdarclickenProbarydebesalirEstado:Correctoy posteriormenteguardamoslosdatos.

Ing.FranciscoRiccio.

Pgina 5

Ing.FranciscoRiccio.

Pgina 6

IntroduccinaPL/SQL
PLSQLesunaextensindeprogramacinaSQL. Esellenguajedeprogramacinde4tageneracinparabasededatosOracle.

Respectoasuarquitectura TodocdigoPLSQLsecomponedecdigoPLSQL+sentenciasSQL. DondeelcdigoPLSQLesejecutadoenunenginellamadoPLSQLylassecciones quesonsentenciasSQLsonejecutadasenelSQLStatementExecutor(Oracle DatabaseServer). TodabasededatosOracletieneunPLSQLenginedeformainherente.Existe otrosproductosquecuentanconunPLSQLenginecomoelOracleApplication Serverensusproductos(OracleForms,OracleReports).

EnelcasodeaplicacionesconOracleFormsyReports,elPLSQLEnginese ejecutarenelladodelclienteylasseccionesconsentenciasSQLson ejecutadasenlabasededatos. AlgunosBeneficios Permitecrearprogramasmodulares. IntegracinconherramientasdeOracle. Portabilidad. Pgina 7

Ing.FranciscoRiccio.

ManejaExcepciones.

UncdigoenPLSQLpuedeserdedostipos:cdigoannimoysubprogramas. Uncdigoannimoesbsicamenteaquelqueelcdigofuenteresideenellado clienteyunsubprogramaresideelcdigofuenteenelservidor.Los subprogramaspuedenser:storedprocedures,funciones,triggersypaquetes.

Semuestralasdiferentesseccionesquecomponenlosdiferentestiposdecdigo PLSQL.

Ing.FranciscoRiccio.

Pgina 8

Declaracindevariables
LaseccindedeclaracindevariablessedefineenlaseccinDECLAREejemplo: DECLARE mivar<tipo_dato> LostiposdedatosenOracleDatabase11genPLSQL: CHAR,VARCHAR,NUMBER,BINARY_INTEGER:

PLSQL_INTEGER,BOOLEAN,BINARY_FLOAT,BINARY_DOUBLE

Ing.FranciscoRiccio.

Pgina 9

DATE,TIMESTAMP,TIMESTAMPWITHTIMEZONE.

TIMESTAMPWITHLOCALTIMEZONE,INTERVALYEARTOMONTH,INTERVAL DAYTOSECOND

Ing.FranciscoRiccio.

Pgina 10

Ejemplo#1: SETSERVEROUTPUTON DECLARE V_MIVARIABLEVARCHAR(20):='HOLAMUNDO' BEGIN DBMS_OUTPUT.PUT_LINE(V_MIVARIABLE) DBMS_OUTPUT.PUT_LINE('FINDELPROGRAMA') END /

Ejemplo#2 SETSERVEROUTPUTON DECLARE V_NUM1NUMBER(4,2):=10.2 V_NUM2NUMBER(4,2):=20.1 BEGIN DBMS_OUTPUT.PUT_LINE('LASUMAES:'||TO_CHAR(V_NUM1+V_NUM2)) END /

Ing.FranciscoRiccio.

Pgina 11

Castingentretiposdedatos:

Lasfuncionesdeconversinbsicason:TO_NUMBER,TO_CHARyTO_DATE. Ejemplo: Sideseamosconvertirdenmeroacaracter:TO_CHAR(20) Sideseamosconvertirdecaracteranmero:TO_NUMBER('20') Sideseamosconvertirdefechaacaracter:TO_CHAR(v_fecha, 'DDMMYYYY HH24:MI:SS')

Mapeandovariablesatiposdedatosdecolumnasdetablas Paraindicarqueeltipodedatodeunavariableserelquetieneunacolumna deunatablasehacemedianteeloperador%type. Ejemplo#3: SETSERVEROUTPUTON DECLARE V_FECHAV$DATABASE.CREATED%TYPE BEGIN SELECTCREATEDINTOV_FECHAFROMV$DATABASE DBMS_OUTPUT.PUT_LINE('LAFECHADECREACIONDELABASEDEDATOS FUE:'||TO_CHAR(V_FECHA,'DDMMYYYY')) END

Ing.FranciscoRiccio.

Pgina 12

Consideraciones Laasignacindeunvalorsobreunavariableserealizamedianteel operador:=ejemplo:v_mivariable:=20 TodainstruccindePLSQLfinalizaconpuntoycoma(). Siunquerydevuelveunasolafilayconuncampopuedeserasignadoa unavariable,ejemplo: SELECTCOUNT(*)INTOMI_VARIABLEFROMHR.EMPLOYEES Siunquerydevuelveunasolafilaycon2omscampostambinpuede serasignadoavariasvariables,ejemplo: SELECTNAME,CREATEDINTOMI_VAR1,MI_VAR2FROMV$DATABASE

Ing.FranciscoRiccio.

Pgina 13

ManejodeEstructurasdeControl (IF/CASE/LOOP/WHILE/FOR)
IF Sintaxis: IF(OPERACINLOGICA)THEN ELSIFTHEN ELSE ENDIF Ejemplo#4: SETSERVEROUTPUTON DECLARE V_FECHAV$DATABASE.CREATED%TYPE BEGIN SELECTCREATEDINTOV_FECHAFROMV$DATABASE IF(SYSDATEV_FECHA>30)THEN DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSFUECREADAHACEMSDE30 DIAS.') ELSE DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSFUECREADAHACEMENOSDE 30DIAS.') ENDIF END /

Ejemplo#5 SETSERVEROUTPUTON

Ing.FranciscoRiccio.

Pgina 14

DECLARE V_FECHAV$DATABASE.CREATED%TYPE BEGIN SELECTCREATEDINTOV_FECHAFROMV$DATABASE IF(SYSDATEV_FECHA>30)THEN DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSFUECREADAHACEMSDE30 DIAS.') ELSIF(SYSDATEV_FECHA>15)AND(SYSDATEV_FECHA<30)THEN DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSFUECREADAHACEMSDE15 DIASYMENOSDE30DIAS.') ELSE DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSFUECREADAHACEMENOSDE 15DIAS.') ENDIF END /

CASE Sintaxis: CASE WHENCONDICION1THEN WHENCONDICION2THEN ELSE ENDCASE

Ing.FranciscoRiccio.

Pgina 15

Ejemplo#6: SETSERVEROUTPUTON DECLARE V_TOTALNUMBER:=0 BEGIN SELECTCOUNT(*)INTOV_TOTALFROMDBA_OBJECTS CASE WHENV_TOTAL<2000THEN DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSTIENEMENOSDE2000 OBJETOS.') WHEN(V_TOTAL<4000)AND(V_TOTAL>2000)THEN DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSTIENEENTRE4000A2000 OBJETOS.') ELSE DBMS_OUTPUT.PUT_LINE('LABASEDEDATOSTIENEMASDE4000 OBJETOS.') ENDCASE END /

LOOP Permitegenerarbucles. Sintaxis: LOOP EXITWHENCONDICION_SALIDA ENDLOOP

Ing.FranciscoRiccio.

Pgina 16

Ejemplo#7: Imprimiendolosprimeros10nmeros: SETSERVEROUTPUTON DECLARE V_NUMNUMBER:=0 BEGIN LOOP V_NUM:=V_NUM+1 DBMS_OUTPUT.PUT_LINE('NUMERO:'||TO_CHAR(V_NUM)) EXITWHENV_NUM>=10 ENDLOOP END /

WHILE Sintaxis: WHILECONDICIONLOOP ENDLOOP

Ejemplo#8: SETSERVEROUTPUTON DECLARE V_NUMNUMBER:=1 BEGIN WHILEV_NUM<11LOOP DBMS_OUTPUT.PUT_LINE('NUMERO:'||TO_CHAR(V_NUM))

Ing.FranciscoRiccio.

Pgina 17

V_NUM:=V_NUM+1 ENDLOOP END /

FOR Sintaxis: FORVARIABLEININICIO..FINALLOOP ENDLOOP

Ejemplo#9: SETSERVEROUTPUTON BEGIN FORV_NUMIN1..10LOOP DBMS_OUTPUT.PUT_LINE('NUMERO:'||TO_CHAR(V_NUM)) ENDLOOP END /

Nota:LavariableutilizadacomocontadorenelFORnorequiereserespecificada enelDECLARE.

Ing.FranciscoRiccio.

Pgina 18

ManejodeEstructurasComplejas (Registros/IndexBy/NestedTable/VArray)
Registros Permitecrearestructurasquealberganunconjuntodetiposdedatos. Porejemplo,podemoscrearelregistroPERSONAconloscamposcdigo, nombreyedad,cadaunodeestoscamposcondiferentestiposdedatos. Sintaxis: TYPE<NOMBRE_REGISTRO>ISRECORD( CAMPO1TIPO_DATO, CAMPO2TIPO_DATO )

Ejemplo#10: SETSERVEROUTPUTON DECLARE TYPETPERSONAISRECORD( CODIGONUMBER, NOMBREVARCHAR(100), EDADNUMBER ) V_VAR1TPERSONA BEGIN V_VAR1.CODIGO:=1 V_VAR1.NOMBRE:='FRANCISCO'

Ing.FranciscoRiccio.

Pgina 19

V_VAR1.EDAD:=30 DBMS_OUTPUT.PUT_LINE('CODIGO:'||TO_CHAR(V_VAR1.CODIGO)||' PERSONA:'||V_VAR1.NOMBRE||'EDAD:'||TO_CHAR(V_VAR1.EDAD)||'.') END /

Adicional: Tambinpodemoscrearregistrosquemantenganlosmismoscamposytiposde datosqueunatabla. DECLARE MIVARIABLEDBA_OBJECTS%ROWTYPE

IndexBy IndexBypermitecreararreglosenPLSQL. Sintaxis: TYPE<NOMBRE_TIPO_LISTA>ISTABLEOF<TIPO_DATO_NODO>INDEXBY BINARY_INTEGER|PLS_INTEGER|VARCHAR2(#) Ejemplo#11: SETSERVEROUTPUTON DECLARE TYPET_LISTAISTABLEOFNUMBERINDEXBYBINARY_INTEGER V_LISTAT_LISTA BEGIN FORIIN1..10LOOP V_LISTA(I):=I ENDLOOP FORIIN1..10LOOP

Ing.FranciscoRiccio.

Pgina 20

DBMS_OUTPUT.PUT_LINE(I) ENDLOOP END /

ConsideracionesconlosINDEXBY: Nopuedenseruntipodedatodeunacolumnadeunatabla. NorequierenserinicializadoslasvariablesdetipoINDEXBY. Losnodosdelarreglonorequierenserinicializados.

NestedTable LosNestedTabletambinpermitecreararreglosenPLSQL. Sintaxis: TYPE<NOMBRE_TIPO_LISTA>ISTABLEOF<TIPO_DATO_NODO> Ejemplo#12: SETSERVEROUTPUTON DECLARE TYPET_LISTAISTABLEOFNUMBER V_LISTAT_LISTA:=T_LISTA() BEGIN FORIIN1..10LOOP V_LISTA.EXTEND V_LISTA(I):=I ENDLOOP FORIIN1..10LOOP DBMS_OUTPUT.PUT_LINE(I)

Ing.FranciscoRiccio.

Pgina 21

ENDLOOP END /

Ejemplo#13: CREATETYPET_TELEFONOSISTABLEOFCHAR(7) / CREATETABLEPERSONA(CODIGONUMBER,NOMBREVARCHAR(25),LISTA T_TELEFONOS) NESTEDTABLELISTASTOREASTAB_LISTA

INSERTINTOPERSONAVALUES (1,'FRANCISCO',T_TELEFONOS('1234567','7654321')) COMMIT

SELECT*FROMPERSONA

ConsideracionesconlosNESTEDTABLE: Puedeseruntipodedatodeunacolumnadeunatabla,peroseguarda enotrosegmento,esdecirnoseguardaenlamismatablafsicamente. RequiereserinicializadoslasvariablesdetipoNESTEDTABLE. Porcadanodonuevodelarreglodebepreviamenteelarregloauto extenderse.

VARRAY LosVARRAYtambinpermitencreararreglosenPLSQL,perotienenuntamao limitadodesdesuespecificacin. Sintaxis: TYPE<NOMBRE_TIPO_LISTA>ISVARRAY(#NODOS)OF<TIPO_DATO_NODO> Ing.FranciscoRiccio. Pgina 22

Ejemplo#14: SETSERVEROUTPUTON DECLARE TYPET_LISTAISVARRAY(10)OFNUMBER V_LISTAT_LISTA:=T_LISTA() BEGIN FORIIN1..10LOOP V_LISTA.EXTEND V_LISTA(I):=I ENDLOOP FORIIN1..10LOOP DBMS_OUTPUT.PUT_LINE(I) ENDLOOP END /

Ejemplo#15: CREATETYPET_TELEFONOSISVARRAY(2)OFCHAR(7) /

CREATETABLEPERSONA(CODIGONUMBER,NOMBREVARCHAR(25),LISTA T_TELEFONOS)

INSERTINTOPERSONAVALUES (1,'FRANCISCO',T_TELEFONOS('1234567','7654321')) COMMIT

Ing.FranciscoRiccio.

Pgina 23

SELECT*FROMPERSONA

ConsideracionesconlosVARRAY: Puedeseruntipodedatodeunacolumnadeunatablaysiesguardado enlamismatablafsicamente. RequiereserinicializadoslasvariablesdetipoVARRAY. Porcadanodonuevodelarreglodebepreviamenteelarregloauto extenderse.

Los3tiposdearreglostienenmtodosquepodemosutilizarennuestros cdigos. Selistaalgunodelosmtodos:

Ing.FranciscoRiccio.

Pgina 24

ManejodeCursores
CadasentenciaSQLqueesejecutadaenlabasededatossiempretiene asociadouncursor.LoscursoressondefinidosenelPGA(Memoriaprivadapor cadaserverprocess). LoscursorespuedenserdefinidiosporOracledeformaexplcitaoimplcita. ImplcitasignificaqueOracleDatabaseesresponsabledecrearelcursor,abrirlo recorrerloycerrarlo.Deformaexplcitanosotrossomosresponsablesdelas actividadesmencionadas. Elcontroldeuncursorsedefineenelsiguientegrfico:

Sintaxis: DECLARE CURSORMICURSORIS<QUERY> BEGIN OPENMICURSOR FETCHMICURSORINTOVARIABLES_PLSQL CLOSEMICURSOR END /

Ing.FranciscoRiccio.

Pgina 25

Ejemplo#16: SETSERVEROUTPUTON DECLARE CURSORMICURSORISSELECTFIRST_NAME,LAST_NAMEFROM HR.EMPLOYEES V_NOMBREHR.EMPLOYEES.FIRST_NAME%TYPE V_APELLIDOHR.EMPLOYEES.LAST_NAME%TYPE BEGIN OPENMICURSOR LOOP FETCHMICURSORINTOV_NOMBRE,V_APELLIDO EXITWHENMICURSOR%NOTFOUND DBMS_OUTPUT.PUT_LINE('NOMBRE:'||V_NOMBRE||',APELLIDO: '||V_APELLIDO) ENDLOOP CLOSEMICURSOR END /

Ejemplo#17: Otraformaderecorrerloscursors: SETSERVEROUTPUTON DECLARE CURSORMICURSORISSELECTFIRST_NAME,LAST_NAMEFROM HR.EMPLOYEES BEGIN FORCINMICURSORLOOP DBMS_OUTPUT.PUT_LINE('NOMBRE:'||C.FIRST_NAME||',APELLIDO: Ing.FranciscoRiccio. Pgina 26

'||C.LAST_NAME) ENDLOOP END / Enestecaso,elFORautomticamenteaperturaelcursorylocierra.

Loscursorestienenatributosquepuedenayudarnosenelcontroldelmismo.

Trabajandoconcursoresconparmetros: Permitecrearuncursorquepermitemanejarparmetros,demodoqueel mismocursorpodemosutilizarloenvariasocasionesreemplazandoelvalordel parmetro. Sintaxis:CURSOR<NOMBRE_CURSOR>(PARAMETROTIPO_DATO)IS <QUERY> Ejemplo#17: SETSERVEROUTPUTON DECLARE CURSORMICURSOR(COD_DEPNUMBER)ISSELECTFIRST_NAME,LAST_NAME FROMHR.EMPLOYEESWHEREDEPARTMENT_ID=COD_DEP BEGIN FORCINMICURSOR(100)LOOP DBMS_OUTPUT.PUT_LINE('NOMBRE:'||C.FIRST_NAME||',APELLIDO:

Ing.FranciscoRiccio.

Pgina 27

'||C.LAST_NAME) ENDLOOP END /

WHERECURRENTOF ElWHERECURRENTOFpermiteactualizarunafilaquelotenemosactualmente apuntandoennuestrocursor.Comocondicinelcursordebeteneruna sentenciaSELECTFORUPDATE. Ejemplo#18: SETSERVEROUTPUTON DECLARE CURSORMICURSOR(COD_DEPNUMBER)ISSELECTFIRST_NAME,LAST_NAME FROMHR.EMPLOYEESWHEREDEPARTMENT_ID=COD_DEPFORUPDATE BEGIN FORCINMICURSOR(100)LOOP DBMS_OUTPUT.PUT_LINE('NOMBRE:'||C.FIRST_NAME||',APELLIDO: '||C.LAST_NAME) UPDATEHR.EMPLOYEES SETSALARY=1 WHERECURRENTOFMICURSOR ENDLOOP COMMIT END /

Ing.FranciscoRiccio.

Pgina 28

ManejodecursoresGenricos Permitecrearuncursordondeentiempodeejecucinseasignarelqueryque elcursordebemanejar.


Sintaxis: TYPE<NOMBRE_TIPO>ISREFCURSOR VARIABLE<NOMBRE_TIPO>

Ejemplo#19: SETSERVEROUTPUTON DECLARE TYPET_CURSORISREFCURSOR MICURSORT_CURSOR V_APELLIDOHR.EMPLOYEES.LAST_NAME%TYPE BEGIN OPENMICURSORFOR'SELECTLAST_NAMEFROMHR.EMPLOYEES' LOOP FETCHMICURSORINTOV_APELLIDO EXITWHENMICURSOR%NOTFOUND DBMS_OUTPUT.PUT_LINE('APELLIDO='||V_APELLIDO) ENDLOOP CLOSEMICURSOR END /

Ing.FranciscoRiccio.

Pgina 29

ManipulacindeExcepciones
Frenteaerroresdeejecucinquenomanejadasautomticamentenuestro cdigoterminarconerror.Podemosmanejarloserroresyhaceruntrabajo respectivofrenteaunproblemaesperadoonoesperado. Sintaxis: EXCEPTION WHENERRORTHEN <ACCION> LostiposdeerroresyaexistenalgunospreestablecidosporOracleDatabase(20 aproximadamente)peronocubrentodoslosescenarios.Lomejoresdefinir nuestrospropioserrores. Sintaxis: DECLARE E1EXCEPTION PRAGMAEXCEPTION_INIT(E1,#_ERROR) BEGIN EXCEPTION WHENE1THEN <ACCION> END

Nota:ElPRAGMAEXCEPTIONpermiteasociarlavariableexceptionconun cdigodeerrordeOracleDatabase.

Ejemplo#20: SETSERVEROUTPUTON DECLARE

Ing.FranciscoRiccio.

Pgina 30

E1EXCEPTION PRAGMAEXCEPTION_INIT(E1,1422) V_NOMBREHR.EMPLOYEES.LAST_NAME%TYPE BEGIN SELECTLAST_NAMEINTOV_NOMBREFROMHR.EMPLOYEES EXCEPTION WHENE1THEN DBMS_OUTPUT.PUT_LINE('ELQUERYDEVUELVEMASDEUNAFILA') END /

Siqueremosasegurarnosquesiempremanejaremosunerrorapesarquenolo hayamosidentificadoeneldiseo,podemosusarlaconstanteOTHERS. Sintaxis: EXCEPTION WHENOTHERSTHEN <ACCION>

Sideseamosrecibirelmensajedeerrorquedisparlaexcepcinsepuede utilizarlasfunciones:SQLERRMySQLCODE.

Ing.FranciscoRiccio.

Pgina 31

RAISE_APPLICATION_ERROR: Permitedispararexcepcionespersonalizadosalasaplicaciones. Sintaxis: RAISE_APPLICATION_ERROR(#_ERROR,'MENSAJE',FALSE|TRUE) DondeOracleDatabasenosreservaloscdigosqueseencuentranenunrango de20000a20999. Eltercerparmetroqueesuntipodedatoboolean,pordefaultesFALSEelcual reemplazacualquiererrorquesevengaarrastrandoyesreemplazadoporel textoqueseindica.SiencasosecolocaTRUE,seimprimirlacoladeerrores arrastradosincluidoelmensajepersonalizado.

Ing.FranciscoRiccio.

Pgina 32

ManejodeArchivos
ConOracleDatabasetenemoslaposibilidaddecrearprogramasquecreen archivosyasimismoleerlos.Estolopodemosrealizargraciasalpaquete UTL_FILEquenosproporcionaOracle. Semuestrauncuadrogeneraldelflujodetrabajoconelmanejodearchivos.

Comorequisitoobligatoriodebemoscrearunobjetodirectorioelcualapuntara undirectoriodelsistemaoperativodondesealojarnuestroarchivo. Estolorealizamosconelcomando:CREATEORREPLACEDIRECTORY Ejemplo#21: Enesteejercicioseguardaralalistadetodoslosempleadosdelatabla HR.EMPLOYEES. CREATEORREPLACEDIRECTORYMIDIRECTORIOAS'C:\' SETSERVEROUTPUT ON DECLARE ARCHIVOUTL_FILE.FILE_TYPE CURSORMICURSORISSELECTLAST_NAMEFROMHR.EMPLOYEES Ing.FranciscoRiccio. Pgina 33

BEGIN ARCHIVO:=UTL_FILE.FOPEN('MIDIRECTORIO','MIARCHIVO.TXT','W') FORCINMICURSORLOOP UTL_FILE.PUT_LINE(ARCHIVO,C.LAST_NAME) UTL_FILE.NEW_LINE(ARCHIVO) ENDLOOP UTL_FILE.FCLOSE(ARCHIVO) END /

Ejemplo#22: Enesteejercicioleeremoselarchivoquehemoscreadoenelejercicioanterior. SETSERVEROUTPUTON DECLARE ARCHIVOUTL_FILE.FILE_TYPE V_LINEAVARCHAR(250) BEGIN ARCHIVO:=UTL_FILE.FOPEN('MIDIRECTORIO','MIARCHIVO.TXT','R') BEGIN LOOP UTL_FILE.GET_LINE(ARCHIVO,V_LINEA) IF(V_LINEAISNOTNULL)THEN DBMS_OUTPUT.PUT_LINE(V_LINEA) ENDIF ENDLOOP EXCEPTION

Ing.FranciscoRiccio.

Pgina 34

WHENNO_DATA_FOUNDTHEN DBMS_OUTPUT.PUT_LINE('FINDELARCHIVO') END UTL_FILE.FCLOSE(ARCHIVO) END /

Ing.FranciscoRiccio.

Pgina 35

CreacindeStoredProceduresyFunciones
Unstoredprocedureesunprocedimientocuyocdigoseguardaenlabasede datosytienecomoobjetorealizarunaaccinespecfica. Susintaxiseslasiguiente: CREATEORREPLACEPROCEDURE<NOMBRE_PROCEDURE>(PARAMETROS)IS <DEFINICION_VARIABLES> BEGIN <CODIGO_PLSQL> END

Ejemplo#23: SETSERVEROUTPUTON CREATEORREPLACEPROCEDURESPU_SUMAR(XINNUMBER,YINNUMBER) IS BEGIN DBMS_OUTPUT.PUT_LINE('LASUMAES:'||TO_CHAR(X+Y)) END / Probandoelstoredprocedure: EXECUTESPU_SUMAR(2,3)

Losparmetrosquepuederecibirunstoredprocedurepuedenserde3tipos: IN(Default):SiunparmetroesINnopuedesermodificadoenel transcursodelcdigoPLSQL. OUT:SiunparmetroesOUTsiemprellegaalcdigodelstoredprocedure conelvalordeNULLycuandoterminaelcdigodePLSQLelparmetro mantieneelvalordeformapersistente. Pgina 36

Ing.FranciscoRiccio.

INOUT:Esunacombinacindeambos.

Ejemplo#24: CREATEORREPLACEPROCEDURESPU_SUMAR(XINNUMBER,YINNUMBER,Z OUTNUMBER) IS BEGIN Z:=X+Y END / Probandoelstoredprocedure: SETSERVEROUTPUTON DECLARE V_SUMANUMBER:=0 BEGIN SPU_SUMAR(1,3,V_SUMA) DBMS_OUTPUT.PUT_LINE(V_SUMA) END /

Ejemplo#25: CREATEORREPLACEPROCEDURESPU_SUMAR(XINOUTNUMBER,YINOUT NUMBER,ZOUTNUMBER) IS BEGIN Z:=X+Y END

Ing.FranciscoRiccio.

Pgina 37

/ Probandoelstoredprocedure: SETSERVEROUTPUTON DECLARE V_SUMANUMBER:=0 V_XNUMBER:=10 V_YNUMBER:=20 BEGIN SPU_SUMAR(V_X,V_Y,V_SUMA) DBMS_OUTPUT.PUT_LINE(V_SUMA) END /

Unafuncinaligualquelosstoredprocedures,sucdigoseguardaenlabase dedatosytienecomofuncinrealizarunclculoydevolverunvalor. Sintaxis: CREATEORREPLACEFUNCTION<NOMBRE_FUNCTION>(PARAMETROS) RETURN<TIPO_DATO> IS <DEFINICION_VARIABLES> BEGIN <CODIGO_PLSQL> END

Ejemplo#26: CREATEORREPLACEFUNCTIONGET_TOTAL_OBJ RETURNNUMBER

Ing.FranciscoRiccio.

Pgina 38

IS V_TOTALNUMBER:=0 BEGIN SELECTCOUNT(*)INTOV_TOTALFROMDBA_OBJECTS RETURNV_TOTAL END / Probandolafuncin: SELECTGET_TOTAL_OBJFROMDUAL

Restricciones NopuedeserutilizadoenconstraintsdetipoCHECK. Nopuedeserutilizadocomodefaultdeunacolumna. EnsentenciasSQLquellamenafunciones,estasfuncionesestn restringidasalosiguiente: o EnsentenciasSELECT,lafuncinnopuedeejecutaruna sentenciaDML. o EnsentenciasDELETEoUPDATE,lafuncinnopuedeconsultar omodificarlatablaqueestteniendoelDELETEoelUPDATE. o EncualquiersentenciaSELECToDML,lafuncinnopueden ejecutarunCOMMIToROLLBACK,niunaoperacinDDLniDCL yaquegeneraunCOMMITimplcito.

Adicional,podemoscrearsubprogramas(funcionesystoredprocedures)que inicienyfinalicenunatransaccinautnoma. Sintaxis: CREATEORREPLACEPROCEDURE<NOMBRE_PROCEDURE> IS PRAGMAAUTONOMOUS_TRANSACTION Ing.FranciscoRiccio. Pgina 39

CreacinPaquetes
Unpaqueteesunaagrupacinlgicadevariables,funcionesystored procedures. Sedividelgicamenteen2partescomosedetallaenelsiguientegrfico:

EspecificacinyBody. Enlaespecificacinsedefinelasvariablesylossubprogramasquequeremos publicaralaspersonasquedeseenutilizarnuestrosprogramas. Enelbodyvalaimplementacindecadasubprogramadefinidoenla especificacinyadicionalotrossubprogramasquequizsnonecesitamosquese expongan. Debemostenermuchocuidadosidefinimosvariablesgeneralesenla especificacinoenbodyyaquesonpersistenteshastaquelasesinsalgadela basededatos. Unaventajadeutilizarpaquetesesquelaprimeravezqueunusuariollamaal paquetetodalainformacindelpaquetesubeenmemoriaylainformacinde losvaloresdelasvariablesqueutilizacadasesinseguardaenelUGAdecada sesin. Sintaxis: CREATEORREPLACEPACKAGE<NOMBRE_PAQUETE>IS<CODIGO>END CREATEORREPLACEPACKAGEBODY<NOMBRE_PAQUETE>IS<CODIGO> END Ing.FranciscoRiccio. Pgina 40

Ejemplo#27: Especificacin. CREATEORREPLACEPACKAGEMIPAQUETE IS V_VARNUMBER:=0 FUNCTIONGET_SUMA(XNUMBER,YNUMBER)RETURNNUMBER PROCEDURESPU_ACTUALIZA_STOCK END / Body. CREATEORREPLACEPACKAGEBODYMIPAQUETE IS

V_VARNUMBER:=0

FUNCTIONGET_SUMA(XNUMBER,YNUMBER)RETURNNUMBER IS BEGIN RETURNX+Y END

PROCEDURESPU_ACTUALIZA_STOCK IS BEGIN NULL END

Ing.FranciscoRiccio.

Pgina 41

END /

Paratrabajoslargosytemporalesdondeprobablementenorequerimostener durantetodoelciclodevidadelasesinelvalordeunavariablepodemos utilizarelPRAGMASERIALLY_REUSABLE.ConelPRAGMA,Oraclemudalas variablesglobalesalSGA(LargePool)ylosmantieneah.Cadallamadadeun subprogramaquedeseautilizarlavariable,Oraclerealizaunacopiadela variablequeencuentraenelSGAalUGAdelusuarioymantieneelvalorenla sesindelusuariohastaquesefinaliceelsubprogramaquellamalafuncin. UnPRAGMAesunadirectivadecompilacin. Ejemplo#28: CREATEORREPLACEPACKAGEMIPAQUETEIS PRAGMASERIALLY_REUSABLE V_NUMNUMBER:=0 PROCEDUREINICIALIZAR(PNNUMBER) PROCEDUREIMPRIMIR_VALOR END /

CREATEORREPLACEPACKAGEBODYMIPAQUETEIS PRAGMASERIALLY_REUSABLE

PROCEDUREINICIALIZAR(PNNUMBER)IS BEGIN MIPAQUETE.V_NUM:=PN DBMS_OUTPUT.PUT_LINE('NUMERO:'||TO_CHAR(MIPAQUETE.V_NUM)) END Ing.FranciscoRiccio. Pgina 42

PROCEDUREIMPRIMIR_VALORIS BEGIN DBMS_OUTPUT.PUT_LINE('NUMERO:'||TO_CHAR(MIPAQUETE.V_NUM)) END

END / Probando: SETSERVEROUTPUTON EXECUTEDBMS_OUTPUT.PUT_LINE('VALORVARIABLE: '||TO_CHAR(MIPAQUETE.V_NUM)) EXECUTEMIPAQUETE.INICIALIZAR(20) EXECUTEMIPAQUETE.IMPRIMIR_VALOR EXECUTEDBMS_OUTPUT.PUT_LINE('VALORVARIABLE: '||TO_CHAR(MIPAQUETE.V_NUM))

Ing.FranciscoRiccio.

Pgina 43

CreacindeTriggers
Lostriggerssonsubprogramasquesedisparanfrenteaeventosqueocurrenen labasededatos. Lostiposdetriggerson: SimpleDMLtriggers(BEFORE,AFTERyINSTEADOF). Compoundtriggers. NonDMLtriggers(DDL&Databaseevents).

Lostriggersdetiposimpledmlserexplicadoacontinuacin. Lostriggersdetiposimpledmlsonaquellosquesedisparancuandoocurreuna operacinDMLydependiendodelmomentoquedeseemosquesedispareantes odespusdelatransaccinoreemplazarlatransaccinporotrocdigo.

Sintaxis: CREATEORREPLACETRIGGER<NOMBRE_TRIGGER> INSTEADOF|BEFORE|AFTER INSERT|DELETE|UPDATEOF<COLUMNAS> ON<TABLA> FOREACHROW WHEN<CONDICION> DECLARE BEGIN <CODIGO> END

RespectoaFOREACHROW,significaqueeltriggersedispararporcadafila queestsiendoafectadoporlatransaccin.

Ing.FranciscoRiccio.

Pgina 44

SedetallaunacomparacinentretenerynotenerhabilitadoelFOREACHROW.

Ejemplo#29: SETSERVEROUTPUTON

CREATETABLETABLA_TG(CAMPO1NUMBER)

CREATEORREPLACETRIGGERTG_TABLA_01 BEFOREINSERTONTABLA_TG DECLARE BEGIN DBMS_OUTPUT.PUT_LINE('CODIGOLIBERADOANTESDELINSERT.') END /

CREATEORREPLACETRIGGERTG_TABLA_02 AFTERINSERTONTABLA_TG DECLARE BEGIN DBMS_OUTPUT.PUT_LINE('CODIGOLIBERADODESPUESDELINSERT.') END Ing.FranciscoRiccio. Pgina 45

INSERTINTOTABLA_TGVALUES(1)

Ejemplo#30: SETSERVEROUTPUTON

DELETEFROMTABLA_TG

ALTERTRIGGERTG_TABLA_01DISABLE ALTERTRIGGERTG_TABLA_02DISABLE

CREATEORREPLACETRIGGERTG_TABLA_03 BEFOREINSERTONTABLA_TG FOREACHROW DECLARE BEGIN DBMS_OUTPUT.PUT_LINE('VALORINGRESADOANTESDELINSERT: '||TO_CHAR(:NEW.CAMPO1)) :NEW.CAMPO1:=10 DBMS_OUTPUT.PUT_LINE('VALORMODIFICADOA10.') END /

CREATEORREPLACETRIGGERTG_TABLA_04 AFTERINSERTONTABLA_TG Ing.FranciscoRiccio. Pgina 46

FOREACHROW DECLARE BEGIN DBMS_OUTPUT.PUT_LINE('VALORINGRESADODESPUESDELINSERT: '||TO_CHAR(:NEW.CAMPO1)) END /

INSERTINTOTABLA_TGVALUES(1) SETSERVEROUTPUTON

DELETEFROMTABLA_TG

ALTERTRIGGERTG_TABLA_01DISABLE ALTERTRIGGERTG_TABLA_02DISABLE

CREATETABLETABLA_TG(CAMPO1NUMBER)

CREATEORREPLACETRIGGERTG_TABLA_03 BEFOREINSERTONTABLA_TG FOREACHROW DECLARE BEGIN DBMS_OUTPUT.PUT_LINE('VALORINGRESADOANTESDELINSERT: '||TO_CHAR(:NEW.CAMPO1)) :NEW.CAMPO1:=10

Ing.FranciscoRiccio.

Pgina 47

DBMS_OUTPUT.PUT_LINE('VALORMODIFICADOA10.') END /

CREATEORREPLACETRIGGERTG_TABLA_04 AFTERINSERTONTABLA_TG FOREACHROW DECLARE BEGIN DBMS_OUTPUT.PUT_LINE('VALORINGRESADODESPUESDELINSERT: '||TO_CHAR(:NEW.CAMPO1)) END /

INSERTINTOTABLA_TGVALUES(1)

Semuestraacontinuacinuncuadroquemuestracuandotenemosdisponibles lasvariables:NEWy:OLD.

Lostriggersdetipo:INSTEADOFnospermitereemplazarunatransaccinpor unaaccindiferente.

Ing.FranciscoRiccio.

Pgina 48

Ejemplo#31: SETSERVEROUTPUTON

DELETEFROMTABLA_TG

ALTERTRIGGERTG_TABLA_01DISABLE ALTERTRIGGERTG_TABLA_02DISABLE ALTERTRIGGERTG_TABLA_03DISABLE ALTERTRIGGERTG_TABLA_04DISABLE

CREATEVIEWVTABLA_TGASSELECTCOUNT(*)ASTOTALFROMTABLA_TG

CREATEORREPLACETRIGGERTG_TABLA_05 INSTEADOFINSERTONVTABLA_TG BEGIN DELETEFROMTABLA_TG

Ing.FranciscoRiccio.

Pgina 49

END /

INSERTINTOVTABLA_TGVALUES(1)

COMMIT

SELECT*FROMTABLA_TG

Restricciones LostriggersnopuedensercreadosenelesquemaSYS. Lostriggersnopuedenconfirmaroanularunatransaccin

Ing.FranciscoRiccio.

Pgina 50

ConsideracionesenelDiseo deCdigoPL/SQL
EjecucindeOperacionesDDLyDCL ConelcomandoEXECUTEIMMEDIATEpodemoscrearcdigodinmicoque genereunatrasaccinDDLyDCL. Sintaxis: EXECUTEIMMEDIATE('<CODIGO_DDL_DCL')

Ejemplo#32: SETSERVEROUTPUTON BEGIN EXECUTEIMMEDIATE('CREATETABLECODIGO_DDL(CAMPO1NUMBER)') END /

SELECT*FROMCODIGO_DDL

ConlamismainstruccinEXECUTEIMMEDIATEpodemosrealizarconsultasy operacionesDMLdeformadinmica. Sintaxis: EXECUTEIMMEDAITE('<QUERY>')INTOVARIABLEUSINGVALOR_PARAMETRO

Ejemplo#33: SETSERVEROUTPUTON DECLARE V_TOTALNUMBER:=0 BEGIN

Ing.FranciscoRiccio.

Pgina 51

EXECUTEIMMEDIATE('SELECTCOUNT(*)ASTOTALFROMHR.EMPLOYEES WHEREDEPARTMENT_ID=:CODIGO')INTOV_TOTALUSING100 DBMS_OUTPUT.PUT_LINE('TOTALDEEMPLEADOSENELDEPARTAMENTO100: '||TO_CHAR(V_TOTAL)) END /

NOCOPY PermitealcompiladorpasarparmetrosOUTyINOUTcomoreferenciaynopor parmetroporvalorqueeseldefaultestoreduceeloverloadeneltiempode copiadodelosparmetroscuandoseenvan.

Ejemplo#34: CREATEORREPLACEPROCEDURESPU_SUMAR(XINOUTNOCOPYNUMBER,Y INOUTNOCOPYNUMBER,ZOUTNOCOPYNUMBER) IS BEGIN Z:=X+Y END /

Notieneefectoenlossiguientesescenarios: ParmetrosquesonelementosdeunINDEXBY. SobreparmetrosdefinidoscomoNOTNULL. Sobreparmetrosquefuerondeclaradoscon%ROWTYPEo%TYPE. Sielparmetrorequiereunaconversinimplcita.

Ing.FranciscoRiccio.

Pgina 52

BULKCOLLECT ElBULKCOLLECTnospermitereducirenun50%eltiempodeaccesoalabase dedatos.Sebasaenminimizarlacantidaddeswitchcontextqueocurrenal utilizarcursores.UnswitchcontextesunviajedeidayvueltaentreelPLSQL EngineyelOracleDatabaseServer.

Ejemplo#35: Enesteejemplosehahechounsolocontextswitch,dondetodalainformacin delatablaempleadoshasidocargadaenunarregloyhallegadoalPLSQL Engine.SinohubiramosusadoBULKCOLLECTsehubierahechouncontext switchporcadafetchqueserealizaenelcursor.

SETSERVEROUTPUTON DECLARE CURSORMICURSORISSELECT*FROMHR.EMPLOYEES TYPETLISTAISTABLEOFHR.EMPLOYEES%ROWTYPE LISTATLISTA BEGIN OPENMICURSOR FETCHMICURSORBULKCOLLECTINTOLISTA CLOSEMICURSOR FORCIN1..LISTA.COUNTLOOP DBMS_OUTPUT.PUT_LINE(LISTA(C).LAST_NAME) ENDLOOP END /

Ing.FranciscoRiccio.

Pgina 53

Ejemplo#36: Enesteejemploseesttrayendoencadacontextswitch25filas,elcualesuna medidaoptimizasegnalgunosanlisisrealizados.Arribade25nodamayor beneficiodeperformance.

SETSERVEROUTPUTON DECLARE CURSORMICURSORISSELECT*FROMHR.EMPLOYEES TYPETLISTAISTABLEOFHR.EMPLOYEES%ROWTYPE LISTATLISTA BEGIN OPENMICURSOR LOOP FETCHMICURSORBULKCOLLECTINTOLISTALIMIT25 FORCIN1..LISTA.COUNTLOOP DBMS_OUTPUT.PUT_LINE(LISTA(C).LAST_NAME) ENDLOOP EXITWHENMICURSOR%NOTFOUND ENDLOOP CLOSEMICURSOR END /

Ing.FranciscoRiccio.

Pgina 54

FORALL ConsisteigualqueelBULKCOLLECT,peroahoraestdireccionadopara operacionesDMLqueseenvandesdeelPLSQLEnginehacialabasededatosen unamenorcantidaddecontextswitch.

Ejemplo#37: CREATETABLEEMPLEADO_BKASSELECT*FROMHR.EMPLOYEESWHERE1=2

SETSERVEROUTPUTON DECLARE CURSORMICURSORISSELECT*FROMHR.EMPLOYEES TYPETLISTAISTABLEOFHR.EMPLOYEES%ROWTYPE LISTATLISTA BEGIN OPENMICURSOR LOOP FETCHMICURSORBULKCOLLECTINTOLISTALIMIT25 FORALLIIN1..LISTA.COUNT INSERTINTOEMPLEADO_BKVALUESLISTA(I) EXITWHENMICURSOR%NOTFOUND ENDLOOP CLOSEMICURSOR END /

SELECT*FROMEMPLEADO_BK

Ing.FranciscoRiccio.

Pgina 55

Ejemplo#38:

SETSERVEROUTPUTON DECLARE CURSORMICURSORISSELECT*FROMHR.EMPLOYEES TYPETLISTAISTABLEOFHR.EMPLOYEES%ROWTYPE TYPETINDICEISTABLEOFNUMBERINDEXBYPLS_INTEGER LISTA1TLISTA LISTA2TINDICE BEGIN OPENMICURSOR LOOP FETCHMICURSORBULKCOLLECTINTOLISTA1LIMIT25 FORIIN1..LISTA1.COUNTLOOP LISTA2(I):=LISTA1(I).EMPLOYEE_ID ENDLOOP FORALLIIN1..LISTA1.COUNT UPDATEHR.EMPLOYEESSETSALARY=1000WHEREEMPLOYEE_ID= LISTA2(I) EXITWHENMICURSOR%NOTFOUND ENDLOOP CLOSEMICURSOR END /

SELECTLAST_NAME,SALARYFROMHR.EMPLOYEES

Ing.FranciscoRiccio.

Pgina 56

DERECHOSDEEJECUCIN Cuandocreamosunsubprogramaeldueodelsubprogramaenelmomentode sucreacinyejecucinelusuariopierdesusrolesysoloquedanpresentesus privilegiosdeobjetoydesistema.

Asimismocuandocreamosunsubprogramapuedeserejecutadoconlos derechosdelcreadoroporelejecutador. Pordefaultseejecutaconlosderechosdelcreador. Paracrearunsubprogramaqueseejecuteconlospermisosdelejecutadorse debetenerpresentelasiguientesintaxis:

CREATEORREPLACEPROCEDURE<NOMBRE_PROCEDURE>(<PARAMETROS>) AUTHIDCURRENT_USERIS <CODIGO>

Asimismotenerpresentealmomentodecrearunsubprogramaconlaopcinde AUTHIDCURRENT_USER: OperacionesDMLyprivilegiosdeobjetosobretablassonresueltaspor losprivilegiosdelinvocadordelsubprograma. Otrassentenciascomollamadasafunciones,procedures,paquetes sonresueltosconlosderechosdelcreador.

Ing.FranciscoRiccio.

Pgina 57

ProgramacinOrientadaaObjetosenPL/SQL
PLSQLpermitetrabajarconprogramacinorientadaaobjetos,demodoque podamosinclusoguardarobjetosentablasypoderloextraerconatributosy mtodos.

Sintaxis:

Ejemplo#39: CREATEORREPLACETYPEPERSONAASOBJECT ( CODIGONUMBER, NOMBREVARCHAR(20), APELLIDOVARCHAR(25), MEMBERFUNCTIONGET_NOMBRECOMPLETORETURNVARCHAR )NOTFINAL /

CREATEORREPLACETYPEBODYPERSONAIS

Ing.FranciscoRiccio.

Pgina 58

MEMBERFUNCTIONGET_NOMBRECOMPLETORETURNVARCHAR IS BEGIN RETURNNOMBRE||''||APELLIDO END

END /

PordefaultlasclasessonFINAL,locualindicaquenopermiteusarseen herencias. Asimismopodemostrabajarconherencia. Ejemplo#40: EstamoscreandolaclaseEMPLEADOheredandoatributosymtodosdelaclase PERSONA. CREATEORREPLACETYPEEMPLEADOUNDERPERSONA ( SUELDONUMBER, OVERRIDINGMEMBERFUNCTIONGET_NOMBRECOMPLETORETURNVARCHAR, MEMBERPROCEDURESPU_ACTUALIZAR_SUELDO(PSUELDONUMBER) )NOTFINAL /

CREATEORREPLACETYPEBODYEMPLEADOIS

OVERRIDINGMEMBERFUNCTIONGET_NOMBRECOMPLETORETURNVARCHAR

Ing.FranciscoRiccio.

Pgina 59

IS BEGIN RETURNLOWER(NOMBRE||''||APELLIDO) END

MEMBERPROCEDURESPU_ACTUALIZAR_SUELDO(PSUELDONUMBER)IS BEGIN SUELDO:=PSUELDO END

END /

Overridingpermitelasobreescrituradeunsubprogramadelpadre.

Tambinestpermitidopolimorfismo. Enlossiguientespasoscrearemosunatablabasadaennuestroobjeto EMPLEADOylomanipularemos.

Ejemplo#41: CREATETABLETEMPLEADOOFEMPLEADO

INSERTINTOTEMPLEADOVALUES(EMPLEADO(1,'FRANCISCO','RICCIO',8000))

SELECT*FROMTEMPLEADO

SELECTE.GET_NOMBRECOMPLETO(),E.*FROMTEMPLEADOE Ing.FranciscoRiccio. Pgina 60

SETSERVEROUTPUTON DECLARE V_OBJETOEMPLEADO BEGIN SELECTVALUE(E)INTOV_OBJETOFROMTEMPLEADOE V_OBJETO.SPU_ACTUALIZAR_SUELDO(1000) DBMS_OUTPUT.PUT_LINE('EMPLEADO: '||V_OBJETO.GET_NOMBRECOMPLETO()||'SUELDO= '||TO_CHAR(V_OBJETO.SUELDO)) END / SihubiramoscreadolavariableV_OBJETOcomoPERSONA,estaramos trabajandoconpolimorfismo,demodoquelavariablesedeclaradeunaclase baseysecreaconclasesderivadas.

Ing.FranciscoRiccio.

Pgina 61