Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Within a PL/SQL procedure, wrap a query or refcursor in HTML table

Tags:

oracle

plsql

It seems really easy if you are using SQL*Plus to use

SQL> set markup html on;

and get some lovely results to the SQL*Plus window. we have an oracle job that runs overnight and sends an email of results to a number of people. I would like to wrap a sql statement in an HTML table to be in that message. What is the best way of doing that?

like image 301
Lloyd Avatar asked Oct 12 '11 15:10

Lloyd


2 Answers

From posting over On the DBA site I got close to the answer that I was looking for. Tom Kyte has a great blog post with a function that does exactly what I was hoping for. In short here is what I implemented:

I created a function that took a sys_refcursor as a variable:

CREATE OR REPLACE FUNCTION fncRefCursor2HTML(rf SYS_REFCURSOR)  RETURN CLOB
IS
    lRetVal      CLOB;
    lHTMLOutput  XMLType; 
    lXSL         CLOB;
    lXMLData     XMLType;

    lContext     DBMS_XMLGEN.CTXHANDLE;
BEGIN
    -- get a handle on the ref cursor --
    lContext := DBMS_XMLGEN.NEWCONTEXT(rf);
    -- setNullHandling to 1 (or 2) to allow null columns to be displayed --
    DBMS_XMLGEN.setNullHandling(lContext,1);
    -- create XML from ref cursor --
    lXMLData := DBMS_XMLGEN.GETXMLTYPE(lContext,DBMS_XMLGEN.NONE);

    -- this is a generic XSL for Oracle's default XML row and rowset tags --
    -- " " is a non-breaking space --
    lXSL := lXSL || q'[<?xml version="1.0" encoding="ISO-8859-1"?>]';
    lXSL := lXSL || q'[<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">]';
    lXSL := lXSL || q'[ <xsl:output method="html"/>]';
    lXSL := lXSL || q'[ <xsl:template match="/">]';
    lXSL := lXSL || q'[ <html>]';
    lXSL := lXSL || q'[  <body>]';
    lXSL := lXSL || q'[   <table border="1">]';
    lXSL := lXSL || q'[     <tr bgcolor="cyan">]';
    lXSL := lXSL || q'[      <xsl:for-each select="/ROWSET/ROW[1]/*">]';
    lXSL := lXSL || q'[       <th><xsl:value-of select="name()"/></th>]';
    lXSL := lXSL || q'[      </xsl:for-each>]';
    lXSL := lXSL || q'[     </tr>]';
    lXSL := lXSL || q'[     <xsl:for-each select="/ROWSET/*">]';
    lXSL := lXSL || q'[      <tr>]';    
    lXSL := lXSL || q'[       <xsl:for-each select="./*">]';
    lXSL := lXSL || q'[        <td><xsl:value-of select="text()"/> </td>]';
    lXSL := lXSL || q'[       </xsl:for-each>]';
    lXSL := lXSL || q'[      </tr>]';
    lXSL := lXSL || q'[     </xsl:for-each>]';
    lXSL := lXSL || q'[   </table>]';
    lXSL := lXSL || q'[  </body>]';
    lXSL := lXSL || q'[ </html>]';
    lXSL := lXSL || q'[ </xsl:template>]';
    lXSL := lXSL || q'[</xsl:stylesheet>]';

    -- XSL transformation to convert XML to HTML --
    lHTMLOutput := lXMLData.transform(XMLType(lXSL));
    -- convert XMLType to Clob --
    lRetVal := lHTMLOutput.getClobVal();

    RETURN lRetVal;
END;

Then to test it in a Test window in PL/SQL Developer

declare 
  l_cursor sys_refcursor;
begin
  open l_cursor for select * from employees;
  :x:= fncRefCursor2HTML(l_cursor);
  close l_cursor;  
end;

This is something that I have been hoping to find for a long time. THANKS Tom Kyte!

like image 65
Lloyd Avatar answered Oct 12 '22 11:10

Lloyd


One option is to use hypertext functions HTF:

set define off

create table so14t (id number, data varchar2(25));

insert all
into so14t values(101, 'one hundred & one')
into so14t values(202, 'two hundred & two')
into so14t values(303, 'three hundred & three')
select 1 from dual;

declare
  v_html varchar2(32767);
begin
  v_html := htf.tableopen;

  for i in (select * from so14t) loop
    v_html := v_html || htf.tablerowopen;
    v_html := v_html || htf.tabledata(i.id);
    v_html := v_html || htf.tabledata(htf.escape_sc(i.data));
    v_html := v_html || htf.tablerowclose;
  end loop;

  v_html := v_html || htf.tableclose;

  dbms_output.put_line(v_html);
end;
/

Prints (formatted for readability):

<TABLE ><TR><TD>101</TD><TD>one hundred &amp; one</TD></TR>
        <TR><TD>202</TD><TD>two hundred &amp; two</TD></TR>
        <TR><TD>303</TD><TD>three hundred &amp; three</TD></TR></TABLE>
like image 45
user272735 Avatar answered Oct 12 '22 11:10

user272735