You are on page 1of 8

A Simple Method for Generating Excel Reports from

Oracle using the ExcelDocumentType


A couple of years ago, I created a user defined type called the ExcelDocumentType that
allows a developer to create a custom Excel (XM! document using "#$%& The user
defined type has 'een well received, 'ut a few fol(s have commented on how tedious the
coding can 'ecome when creating multiple reports (with a similar ta'ular layout!& I came
to the same conclusion recently, and have created a method that greatly simplifies the
process& The method ma(es use of a couple of new user defined types and a "#$%
pac(age (all provided for your use!& It ma(es creating a multi wor(sheet document (with
a different )uery for each wor(sheet! a 'ree*e and with very little ExcelDocumentType
coding involved&
The Basics
As mentioned a'ove, this new method for generating ExcelDocumentType reports uses a
few +racle user defined types and a small utility pac(age called ExcelDoc,tils& -efore I
get into the details of the "#$% pac(age and the supporting user defined types, let.s
loo( at a code sample that will generate an Excel document containing three wor(sheets&
/or this example I used the EM"+0EE$ ta'le from the +racle 12 demo schema&
32EATE +2 2E"A3E "2+3ED,2E employee2eport A$
v4s)l4salary 5A231A26(677! 89 :$EE3T last4name,first4name,salary /2+M hr&employees
+2DE2 -0 last4name,first4name:;
v4s)l4contact 5A231A26(677! 89 :$EE3T last4name,first4name,phone4num'er,email /2+M
hr&employees +2DE2 -0 last4name,first4name:;
v4s)l4hiredate 5A231A26(677! 89 :$EE3T
last4name,first4name,to4char(hire4date,::MM#DD#0000::! hire4date /2+M hr&employees +2DE2 -0
last4name,first4name:;
excelReport ExcelDocumentType := ExcelDocumentType();
v_worksheet_rec ExcelDocTypeUtils.T_!R"#$EET_D%T% := &U'';
v_worksheet_(rr(y ExcelDocTypeUtils.!R"#$EET_T%)'E :=
ExcelDocTypeUtils.!R"#$EET_T%)'E();
-E<I=
>> $alary
v4wor(sheet4rec&)uery 89 v4s)l4salary;
v4wor(sheet4rec&wor(sheet4name 89 :$alaries:;
v4wor(sheet4rec&col4count 89 ?;
v4wor(sheet4rec&col4width4list 89 :6@,67,A@:;
v4wor(sheet4rec&col4header4list 89 :astname,/irstname,$alary:;
v4wor(sheet4array&EXTE=D;
v4wor(sheet4array(v4wor(sheet4array&count! 89 v4wor(sheet4rec;
>> 3ontact
v4wor(sheet4rec&)uery 89 v4s)l4contact;
v4wor(sheet4rec&wor(sheet4name 89 :3ontact4Info:;
v4wor(sheet4rec&col4count 89 B;
v4wor(sheet4rec&col4width4list 89 :6@,67,67,6@:;
v4wor(sheet4rec&col4header4list 89 :astname,/irstname,"hone,Email:;
v4wor(sheet4array&EXTE=D;
v4wor(sheet4array(v4wor(sheet4array&count! 89 v4wor(sheet4rec;
>> 3ontact
v4wor(sheet4rec&)uery 89 v4s)l4hiredate;
v4wor(sheet4rec&wor(sheet4name 89 :1iredate:;
v4wor(sheet4rec&col4count 89 ?;
v4wor(sheet4rec&col4width4list 89 :6@,67,67:;
v4wor(sheet4rec&col4header4list 89 :astname,/irstname,1iredate:;
v4wor(sheet4array&EXTE=D;
v4wor(sheet4array(v4wor(sheet4array&count! 89 v4wor(sheet4rec;
excel2eport 89 ExcelDocType,tils&createExcelDocument(v4wor(sheet4array!;
excel2eport&displayDocument;
E=D;
#
The code a'ove generates the following Excel document8
$o, what are we loo(ing at hereC /irst, a drastic reduction in the amount of code it ta(es
to generate a 'asic Excel report& $econd, we see some interesting data structures that
allow us to accomplish that feat& The code a'ove centers around three structures and a
new "#$% pac(age called ExcelDocTypeUtils8
(A! A recor* type called T_WORKSHEET_DATA that holds8 the )uery string that
generates the wor(sheet data; the wor(sheet name; the num'er of columns
displayed in the sheet; a list containing the column width for each displayed
column; a list of column headers& This record is defined in the ExcelDocType,tils
pac(age&
(6! A collection o+,ect of T_WORKSHEET_DATA records called
WORKSHEET_TABLE& Each item in the collection represents one wor(sheet in
the Excel document&
(?! The ExcelDocumentType is that third structure& The WORKSHEET_TABLE
collection is passed to a function in the ExcelDocTypeUtils pac(age that returns a
fully populated ExcelDocumentType o'Dect&
(B! The ExcelDocTypeUtils pac(age contains a single pu'lic utility function called
createExcelDocument& This function creates and returns an ExcelDocumentType
o'Dect 'ased upon the WORKSHEET_TABLE input parameter&
The Code
I have provided a lin( in this 'log entry that will allow you to download the code and all
of the re)uired o'Dects& Download it and give it a try& I have 'een using at it at my place
of employment to generate scheduled reports for various departments and individuals& $o
far so goodE
/or those who Dust want to ta(e a loo( at the code, here is the code for the
ExcelDocType,tils pac(age8
32EATE +2 2E"A3E T0"E T42+F A$ TA-E +/ 5A231A26(@77!;
#
32EATE +2 2E"A3E T0"E T42+F4=,M-E2 A$ TA-E +/ =,M-E2(?!;
#
32EATE +2 2E"A3E T0"E 2E$,T4TA-E A$ TA-E +/ T42+F;
#
32EATE +2 2E"A3E "A3GA<E ExcelDocType,tils A$

T0"E t4refcursor I$ 2E/ 3,2$+2;
#H This record contains all of the components
re)uired to create an Excel 2eport wor(sheet& H#
T0"E T4F+2G$1EET4DATA I$ 2E3+2D(
)uery 5A231A26(B777!,
wor(sheet4name 5A231A26(67!,
col4count =,M-E2(?!,
col4width4list 5A231A26(@77!,
col4header4list 5A231A26(6777!
!;
#H An Array of T4F+2G$1EET4DATA allows us to create an excel document
with multiple wor(sheets 'ased on
different )ueries& H#
T0"E F+2G$1EET4TA-E I$ TA-E +/ T4F+2G$1EET4DATA;
/,=3TI+= createExcelDocument(p4wor(sheet4data F+2G$1EET4TA-E! 2ET,2= ExcelDocumentType;
E=D;
#
sho err;
#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH "A3GA<E -+D0 HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
#HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH#
32EATE +2 2E"A3E "A3GA<E -+D0 ExcelDocType,tils A$
#H
/unction that returns the element at the
re)uested position in a delimited string&
H#
/,=3TI+= get$tringElement(p4string 5A231A26,
p4element =,M-E2,
p4delimiter 5A231A26 89 :,:,
p4level =,M-E2 89 7! 2ET,2= 5A231A26
I$
v4string 5A231A26(6777! 89 =,;
v4element 5A231A26(6777! 89 =,;
v4next 5A231A26(6777! 89 =,;
v4level =,M-E2(B! 89 7;
-E<I=
v4level 89 p4level I A;
v4element 89 su'str(p4stringJJp4delimiter,A,
instr(p4stringJJp4delimiter,p4delimiter!>A!;
>> need to loo( ahead to ma(e sure we handle the null elements&
v4next 89 su'str(p4stringJJp4delimiter,
instr(p4stringJJp4delimiter,p4delimiter!,length(p4delimiter!!;
I/ ((v4level K9 p4element! +2
(v4element I$ =, A=D v4next E9 p4delimiter!! T1E=
2ET,2= v4element;
E$E
v4string 89 su'str(p4stringJJp4delimiter,
instr(p4stringJJp4delimiter,p4delimiter!IA,length(p4string!!;
2ET,2= get$tringElement(v4string,p4element,p4delimiter,v4level!;
E=D I/;
E=D;
#H999999999999999999999999999999999999999999999999999999999999999999999999999999H#
#H
This function executes the given )uery and returns the data
in a 2E$,T4TA-E 3ollection o'Dect&
H#
/,=3TI+= 'uildData$et(p4)uery4string 5A231A26 89 =,,
p4col4count =,M-E2 89 7! 2ET,2= 2E$,T4TA-E
I$
r4ta'le 2E$,T4TA-E 89 2E$,T4TA-E(!;
v4row4sym'ol 5A231A26(67! 89 :v4row:;
v4row4fetch 5A231A26(A777! 89 =,;
v4row4extend =,M-E2(?! 89 p4col4count;
v4anydata $0$&A=0DATA 89 =,;
v4func4result "$4I=TE<E2 89 7;
v4)uery 5A231A26(AL777! 89 p4)uery4string;
func2esultTa'le Anonymous/unction 89 Anonymous/unction(!;
v4result4func 5A231A26(?6777! 89 :/,=3TI+= get2ow$et 2ET,2= 2E$,T4TA-E :JJ
:I$ :JJ
: T0"E t4refcursor I$ 2E/ 3,2$+2; :JJ
: v4ta'le 2E$,T4TA-E 89 result4ta'le(!; :JJ
: v4row T42+F 89 T42+F(!; :JJ
: v4)uery 5A231A26(B777! 89 ::M)K::; :JJ
: v4refcur t4refcursor; :JJ
:-E<I= :JJ
: +"E= v4refcur /+2 v4)uery; :JJ
: ++" :JJ
: v4row&extend(MeK!; :JJ
: /ET31 v4refcur I=T+ MfK ;:JJ
: EXIT F1E= v4refcurN=+T/+,=D; :JJ
: v4ta'le&EXTE=D; :JJ
: v4ta'le(v4ta'le&3+,=T! 89 v4row; :JJ
: v4row&DEETE; :JJ
: E=D ++"; :JJ
: 2ET,2= v4ta'le; :JJ
:E=D; :;
-E<I=
/+2 x I= A && v4row4extend ++"
v4row4fetch 89 v4row4fetchJJv4row4sym'olJJ:(:JJxJJ:!,:;

E=D ++";
v4row4fetch 89 2T2IM(v4row4fetch,:,:!;
v4result4func 89 2E"A3E(v4result4func,:M)K:,2E"A3E(v4)uery,::::,::::::!!;
v4result4func 89 2E"A3E(v4result4func,:MeK:,to4char(v4row4extend!!;
v4result4func 89 2E"A3E(v4result4func,:MfK:,v4row4fetch!;
func2esultTa'le&define/unction(p4function4name9K:get2ow$et:,
p4function4text9Kv4result4func,
p4function4type9KD-M$4T0"E$&T0"E3+DE4TA-E!;

v4anydata 89 func2esultTa'le&execute/unction;
v4func4result 89 v4anydata&get3ollection(r4ta'le!;
2ET,2= r4ta'le;

E=D;
#H9999999999999999999999999999999999999999999999999999999999999999999999999H#
#H
This functiom constructs and returns an ExcelDocumentType
'ased upon the parameters passed in
'y the F+2G$1EET4TA-E type parameter&
H#
/,=3TI+= createExcelDocument(p4wor(sheet4data F+2G$1EET4TA-E! 2ET,2= ExcelDocumentType
I$
resultDocument ExcelDocumentType;
v4row T42+F 89 T42+F(!;
v4results 2E$,T4TA-E 89 2E$,T4TA-E(!;
v4default4col4width =,M-E2(?! 89 ?7;
v4col4width =,M-E2(?! 89 7;
-E<I=
-E<I=
3+MMIT;
$ET T2A=$A3TI+= ,$E 2+-A3G $E<ME=T 2-$4A2<E;
EX3E"TI+=
F1E= +T1E2$ T1E= =,;
E=D;

resultDocument 89 ExcelDocumentType(!;
>> +pen Document
resultDocument&document+pen;
>> Define 3ustoms $tyles
resultDocument&styles+pen;

resultDocument&default$tyle;
#H $tyle for 3olumn 1eader 2ow H#
resultDocument&create$tyle(p4style4id 9K:3olumn1eader:,
p4font 9K:Times =ew 2oman:,
p4ffamily 9K:2oman:,
p4fsi*e 9K:A7:,
p4'old 9K:0:,
p4underline 9K:$ingle:,
p4align4hori*ontal9K:3enter:,
p4align4vertical9K:-ottom:!;
resultDocument&styles3lose;
/+2 ws4index I= A && p4wor(sheet4data&3+,=T ++"
>> +pen For(sheets
resultDocument&wor(sheet+pen(p4wor(sheet4data(ws4index!&wor(sheet4name!;
/+2 colnum I= A && p4wor(sheet4data(ws4index!&col4count ++"
v4col4width 89 =5(T+4=,M-E2(get$tringElement(p4wor(sheet4data(ws4index!&col4width4list,colnum!!
,v4default4col4width!;

resultDocument&define3olumn(p4index9KT+431A2(colnum!,
p4width9Kv4col4width!;
E=D ++";
>> 1eading 2ow
resultDocument&row+pen;
/+2 colnum I= A && p4wor(sheet4data(ws4index!&col4count ++"
resultDocument&add3ell(p4style9K:3olumn1eader:,
p4data9Kget$tringElement(p4wor(sheet4data(ws4index!&col4header4list,colnum!!;
E=D ++";
resultDocument&row3lose;
v4results 89 'uildData$et(p4wor(sheet4data(ws4index!&)uery,
p4wor(sheet4data(ws4index!&col4count!;
/+2 r4index I= A && v4results&3+,=T ++"
resultDocument&row+pen;
v4row 89 v4results(r4index!;
/+2 c4index I= A && v4row&3+,=T ++"
resultDocument&add3ell(p4data9Kv4row(c4index!!;
E=D ++";
v4row&DEETE;
resultDocument&row3lose;
E=D ++";
v4results&DEETE;
resultDocument&wor(sheet3lose;
E=D ++";
resultDocument&document3lose;
2ET,2= resultDocument;
E=D;
#H9999999999999H#
#H E=D "A3GA<E H#
#H9999999999999H#
E=D;
#

rapping !t "p
As with all of the code I post in my 'log entries, please feel to use it and modify it as you
see fit& "lease feel free to contact me with any )uestionsE I hope this ma(es generating
Excel reports a little more easy and lot less tedious&

You might also like