Si bien Oracle Application Express nos ofrece muchos tipos de Informes para ser usados cuando estamos creando nuestras aplicaciones web, pero a veces no se ajusta a lo que necesitamos, por ejemplo puede darse el caso de que tengamos una aplicación construida con un módulo PL/SQL y queremos reutilizar ese módulo, entonces para ello necesitamos crear un informe de tipo PL/SQL dinámico.
En mi opinión, nunca está de más saber cómo podemos crear en Oracle Apex Informes para mostrar datos de una tabla en forma dinámica, usando código PL/SQL, pero, hay que ser conscientes, de que se requiere de mucho detalle y hay que plantearse si es conveniente o no utilizar este tipo de Informes, ya que con los asistentes de Apex podemos crear Informes de forma muy rápida y sencilla, sin tanto esfuerzo.
Vamos a trabajar con la tabla DEMO_CUSTOMERS, que pertenece a la aplicación demo “Sample Database Application” de Apex cuando se instala.
Para mostrar los datos de la tabla en un informe creado dinámicamente vamos a hacer uso del paquete APEX_ITEM que nos permite crear elementos dinámicamente basados en una consulta SQL.
En nuestra consulta SQL vamos a hacer uso de dos tipos de funciones:
- HIDDEN: Usamos esta función para generar dinámicamente elementos ocultos.
APEX_ITEM.HIDDEN( p_idx IN NUMBER, p_value IN VARCHAR2 DEFAULT p_attributes IN VARCHAR2 DEFAULT NULL, p_item_id IN VARCHAR2 DEFAULT NULL, p_item_label IN VARCHAR2 DEFAULT NULL ) RETURN VARCHAR2;
2. DISPLAY_AND_SAVE: Usamos esta función para mostrar un elemento como texto, pero guardamos su valor en el estado de sesión.
APEX_ITEM.DISPLAY_AND_SAVE( p_idx IN NUMBER, p_value IN VARCHAR2 DEFAULT NULL, p_item_id IN VARCHAR2 DEFAULT NULL, p_item_label IN VARCHAR2 DEFAULT NULL) RETURN VARCHAR2; p_idx: Indica el número de identificador de la variable htmldb_application_global. El rango de valores es de 1 a 50. Por ejemplo 1 crea F01 y 2 crea F02.
Además, para que se dibuje la información en la región vamos a hacer uso de dos paquetes: HTP o HTF
Paquete htp: (Procedimientos de hipertexto) – Son procedimientos que generan etiquetas HTML. Por ejemplo, el procedimiento htp.htmlopen genera la etiqueta de apertura <HTML>.
Paquete htf: Para cada procedimiento htp que genera una etiqueta HTML hay una función htf con idénticos parámetros. Las funciones no generan directamente la salida en una página web. En lugar de eso, pasan su salida como valores de retorno a los estados que le han sido invocados.
Crear Región de Contenido Dinámico PL/SQL
Creamos una aplicación de escritorio, luego creamos una página en blanco y en ella creamos una región de contenido dinámico PL/SQL que la llamaremos “Clientes”.
Lo más importante aquí es el código PL/SQL en esta región ya que es la que se encargará de armar el Informe en forma dinámica.
Ingresamos el código PL/SQL y hacemos clic en el botón Guardar.
declare cursor c_cus is select apex_item.hidden (1,cus.customer_id) id , apex_item.display_and_save (2, cus.cust_first_name) firstname , apex_item.display_and_save (3, cus.cust_last_name) lastname , apex_item.display_and_save (4, cus.cust_street_address1) address , apex_item.display_and_save (5, cus.cust_city) city , apex_item.display_and_save (6, cus.cust_state) state , apex_item.display_and_save (7, cus.cust_postal_code) postalcode , apex_item.display_and_save (8, cus.cust_email) email , apex_item.display_and_save (9, phone_number1) phonenumber , apex_item.display_and_save (10, credit_limit) creditlimit from demo_customers cus , demo_states sta where cus.cust_state = sta.st order by cus.customer_id; begin for r_cus in c_cus loop htp.p(r_cus.id); htp.p(r_cus.firstname); htp.p(r_cus.lastname); htp.p(r_cus.address); htp.p(r_cus.city); htp.p(r_cus.state); htp.p(r_cus.postalcode); htp.p(r_cus.email); htp.p(r_cus.phonenumber); htp.p(r_cus.creditlimit); end loop; end;
Si ejecutamos la página podremos ver el reporte sin ningún formato, además todos los registros se muestran uno a continuación del otro.
Crear tabla HTML desde el código PL/SQL
Para crear la tabla haremos uso del paquete HTP.
htp.tableopen -- genera la etiqueta <TABLE> htp.tablerowopen -- genera la etiqueta <TR> htp.tablerowclose -- genera la etiqueta </TR> htp.tableclose -- genera la etiqueta </TABLE>
Para ello vamos a cambiar la parte del código que está dentro del bloque begin-end, agregando la tabla y una fila para cada registro, por el hecho que está dentro del loop.
declare cursor c_cus is select apex_item.display_and_save(1, cus.customer_id) id , apex_item.display_and_save (2, cus.cust_first_name) firstname , apex_item.display_and_save (3, cus.cust_last_name) lastname , apex_item.display_and_save (4, cus.cust_street_address1) address , apex_item.display_and_save (5, cus.cust_city) city , apex_item.display_and_save (6, cus.cust_state) state , apex_item.display_and_save (7, cus.cust_postal_code) postalcode , apex_item.display_and_save (8, cus.cust_email) email , apex_item.display_and_save (9, phone_number1) phonenumber , apex_item.display_and_save (10, credit_limit) creditlimit from demo_customers cus , demo_states sta where cus.cust_state = sta.st order by cus.customer_id; begin htp.tableopen; -- genera la etiqueta <TABLE> for r_cus in c_cus loop htp.tablerowopen; -- genera la etiqueta <TR> htp.tabledata (r_cus.id); -- genera las etiquetas <TD> y </TD> htp.tabledata(r_cus.id); htp.tabledata(r_cus.firstname); htp.tabledata(r_cus.lastname); htp.tabledata(r_cus.address); htp.tabledata(r_cus.city); htp.tabledata(r_cus.state); htp.tabledata(r_cus.postalcode); htp.tabledata(r_cus.email); htp.tabledata(r_cus.phonenumber); htp.tabledata(r_cus.creditlimit); htp.tablerowclose; -- genera la etiqueta </TR> end loop; htp.tableclose; -- genera la etiqueta </TABLE> end;
Al ejecutar la página podemos ver que hemos armado la tabla HTML desde dentro del código PL/SQL y cada registro se muestra en una fila diferente.
Asignamos estilos CSS dentro del código PL/SQL
Para darle una mejor visualización a nuestro informe en nuestra aplicación Apex, vamos a asignar algunos estilos en la tabla, fila y celdas.
Sintaxis Procedimiento TABLEOPEN
HTP.TABLEOPEN( cborder IN VARCHAR2 DEFAULT NULL calign IN VARCHAR2 DEFAULT NULL, cnowrap IN VARCHAR2 DEFAULT NULL, cclear IN VARCHAR2 DEFAULT NULL cattributes IN VARCHAR2 DEFAULT NULL);
Por ejemplo, este procedimiento genera:
<TABLE "cborder" NOWRAP ALIGN="calign" CLEAR="cclear" cattributes>
En nuestro código PL/SQL asignamos a la tabla los siguientes atributos:
-
- Border: 2
- Width: 100%
- Cellpadding=10
- Text=#000000 (negro)
- bgcolor=#F3F3F3
htp.tableopen (cattributes => 'border=2 width=100% cellpadding=10 text=#000 bgcolor=#F3F3F3');
Reemplazamos el código PL/SQL en la región de contenido dinámico, por el siguiente código:
declare cursor c_cus is select apex_item.display_and_save(1, cus.customer_id) id , apex_item.display_and_save (2, cus.cust_first_name) firstname , apex_item.display_and_save (3, cus.cust_last_name) lastname , apex_item.display_and_save (4, cus.cust_street_address1) address , apex_item.display_and_save (5, cus.cust_city) city , apex_item.display_and_save (6, cus.cust_state) state , apex_item.display_and_save (7, cus.cust_postal_code) postalcode , apex_item.display_and_save (8, cus.cust_email) email , apex_item.display_and_save (9, phone_number1) phonenumber , apex_item.display_and_save (10, credit_limit) creditlimit from demo_customers cus , demo_states sta where cus.cust_state = sta.st order by cus.customer_id; begin htp.htmlopen; -- genera la etiqueta <HTML> htp.headopen; -- genera la etiqueta <THEAD> htp.title('Reporte de Clientes'); -- genera la etiqueta <TITLE> y </TITLE> htp.headclose; -- genera la etiqueta </HEAD> htp.bodyopen; -- genera la etiqueta <BODY> htp.header(1, 'Reporte de Clientes'); -- genera la etiqueta <H1> y </H1> htp.tableopen (cattributes => 'border=2 width=100% cellpadding=10 text=#000000 bgcolor=#F3F3F3'); -- genera la etiqueta <TABLE> htp.tablerowopen (cattributes => 'bgcolor="#216BB9"'); -- genera la etiqueta <TR> htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Cliente ID'); -- genera la etiqueta <TH> y </TH> htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Nombre'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Apellido'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Dirección'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Ciudad'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Estado'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Código Postal'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Email'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Teléfono'); htp.tableheader(cvalue => '<font face="ARIAL" size="2.25" color="WHITE">' || 'Límite de Crédito'); htp.tablerowclose; -- genera la etiqueta </TR> htp.tablerowopen; -- genera la etiqueta <TR> for r_cus in c_cus loop htp.tabledata(r_cus.id); htp.tabledata(r_cus.firstname, cattributes=>'align=left'); htp.tabledata(r_cus.lastname, cattributes=>'align=left'); htp.tabledata(r_cus.address, cattributes=>'align=left'); htp.tabledata(r_cus.city, cattributes=>'align=left'); htp.tabledata(r_cus.state, cattributes=>'align=left'); htp.tabledata(r_cus.postalcode, cattributes=>'align=center'); htp.tabledata(r_cus.email, cattributes=>'align=left'); htp.tabledata(r_cus.phonenumber, cattributes=>'align=left'); htp.tabledata(r_cus.creditlimit, cattributes=>'align=center'); htp.tablerowclose; end loop; htp.tablerowclose; -- genera la etiqueta </TR> htp.tableclose; -- genera la etiqueta </TABLE> htp.bodyclose; -- genera la etiqueta </BODY> htp.htmlclose; -- genera la etiqueta </HTML> end;
Podemos ejecutar la página y visualizar los cambios en la región de Informe, mostrando la tabla con algunos estilos CSS.
Conclusión
En este artículo hemos podido ver cómo podemos crear Informes generados dinámicamente a partir de un código PL/SQL, además de aprender a utilizar los paquetes HTP y HTF para estructurar la información dentro de la región en la página de Apex y finalmente aprendimos a asignar estilos CSS desde PL/SQL.