Cross-Platform Batch Reports VUGM 2001 Saturday, April 21

advertisement
Cross-Platform Batch Reports
VUGM 2001
Saturday, April 21
Part of
Session 40,
Customized Reporting Options
Presented by:
Roy Zimmer
Programmer/Analyst
Office of Information Technology
Western Michigan University
Cross-Platform Batch Reports – Presentation Outline
VUGM 2001
Presented by Roy Zimmer, Programmer Analyst,
Office of Information Technology, Western Michigan University
Why We Did This
initially no access to Access with the ODBC stuff, didn’t know about it, couldn’t get any
help
got more familiar with Unix, Endeavor supplied some training, figured out where
SQL*PLUS was
started exploring SQL
created several reports, the library liked them; had to run them manually, and got tired of:
remembering to run them, ftp them to a PC, format them in Word, print them, and
deliver them to various locations
we also felt they should be printed using library resources
An overview of the automated process immediately follows this outline.
When to Choose SQL, PL/SQL, or Perl
SQL
can be invoked from within SQL*PLUS
it’s sufficient to create most reports that we’ve needed
allows easy and painless control of page size, line size, and page formatting
it takes control and does a lot of the work for you
output can be to screen or to a file
PL/SQL
can be invoked from within SQL*PLUS or can be embedded in or combined with
SQL
it’s SQL with programming constructs added, so you’ve got a lot more power and
control
functionality is between that of SQL and Perl
output can only be to screen; Oracle allows for file output, but the Voyager
installation does not have this enabled
you can capture the screen output to a file, but you’re limited to a maximum of a
million bytes per “capture” session
Perl
invoked from the operating system level, but you could call it from within SQL if
you needed to
you have control over everything, which means:
you can do just about anything you want
you have to do all the work
output is to screen or file, of course
2
The Batch PC
set up a machine dedicated to this task
can be an older machine, we’re using a 133 MHz Pentium
this machine has 32 meg RAM, and the 1.5 gig hard disk is more than adequate
for O.S., we’re running Windows 95
the WinBatch software is what enables the batch aspect, see www.windowsware.com for
more information
The Batch Software
when you install the WinBatch software, it sets itself so that it has a process running in
the background and leaves an icon on the task bar
WinBatch scripts typically have a .WBT extension
double click on a script to run it
it will either run right away or appear on the task bar, awaiting its time
you’ll want to set up scripts so that their trigger and run times do not overlap
despite referring to application windows by their names, as evidenced in their title bars,
WinBatch appears to get confused and sometimes sends keystrokes to the wrong
window
don’t break up long lines in your scripts – WinBatch expects them to be contiguous
Brief Presenter Bio
working at WMU for 16 years
started out working with VAX for many years
spent several years struggling with IBM mainframe and NOTIS
supporting Voyager for the last 3 years
picked up some Oracle, SQL, PL/SQL, Perl, and Unix along the way
For more information, contact Roy Zimmer at 616.387.3885 or zimmer@wmich.edu
3
4
[This site is available to the world, so code that was part of
this document for the presentation has been removed here. This
code involved details on Voyager’s proprietary schema.]
5
-- example of accessing the blob; bib records in this case
-- setup to only show first 240 characters of a tag's data for example brevity
-- (dbms_output.put_line has several limits,
-- one of which is 255 characters per call)
-- remember to: set serveroutput on size 1000000
-- (yes, I know, this code could be written better...)
declare
cursor marcrec is
select bib_id,
seqnum,
record_segment
from bib_data
where bib_id = 985555
order by bib_id asc, seqnum desc;
m_bibid number(22);
m_seqnum number(22);
m_recseg char(990);
marc
marclen
baseaddr
strptr
tagid
taglen
offset
tagaddr
tagdata
idx
strlen
mchar
subfldchar
marceof
fmt4
fmt5
tempstr
varchar2(17000);
integer(5);
integer(5);
integer(5);
varchar2(3);
integer(4);
integer(5);
integer(5);
varchar2(9999);
integer(5);
integer(5);
char(1);
char(1):= '|';
boolean:= false;
varchar2(4);
varchar2(5);
varchar2(5);
begin
open marcrec;
loop
marc:= '';
fetch marcrec into m_bibid, m_seqnum, m_recseg;
exit when marcrec%notfound;
-- assemble blob into 1 piece
while m_seqnum <> 1
loop
marc:= m_recseg || marc;
fetch marcrec into m_bibid, m_seqnum, m_recseg;
if marcrec%notfound then
marceof:= true;
exit;
end if;
end loop;
exit when marceof;
-- get segment #1
marc:= m_recseg || marc;
-- determine info from header
marclen:= substr(marc, 1, 5);
baseaddr:= substr(marc, 13, 5) + 1;
-- loop through tag directory, get tag parameters, then tag's data
strptr:= 25;
6
while strptr < baseaddr-1
loop
tagid:= substr(marc, strptr, 3);
taglen:= substr(marc, strptr+3, 4);
offset:= substr(marc, strptr+7, 5);
tagaddr:= baseaddr + offset;
tagdata:= substr(marc, baseaddr+offset, taglen-1);
-- set up to pretty print subfield indicators
tagdata:= translate(tagdata, chr(31), subfldchar);
idx:= 2;
strlen:= length(tagdata);
while idx < strlen
loop
mchar:= substr(tagdata, idx, 1);
if mchar = subfldchar then
tagdata:= substr(tagdata, 1,
idx-1) || ' ' ||
substr(tagdata, idx, 2
) || ' ' ||
substr(tagdata, idx+2
);
idx:= idx + 2;
strlen:= length(tagdata);
end if;
idx:= idx + 1;
end loop;
-- set up to pretty print tag parameters
tempstr:= to_char(taglen);
fmt4:= lpad(tempstr, 4, '0');
tempstr:= to_char(tagaddr);
fmt5:= lpad(tempstr, 5, '0');
dbms_output.put_line(tagid || ':' || fmt4 || ':' || fmt5 || ':' ||
substr(tagdata,1,240));
strptr:= strptr + 12;
end loop;
end loop;
close marcrec;
end;
/
7
#!/usr/local/bin/perl
### lb2510.pl print to file table and column schema for Voyager database
### print tables in alphabetical order and within each table:
###
print xxx_id columns alphabetically first, then
###
all other columns alphabetically
### also, don’t split table output over page boundaries
### Word settings: MonoSpacDL821 9pt portrait, 1" T&B, .9" L&R margins
use DBI;
$pagesize = 60;
$dash3 = "---";
$dash5 = "-----";
$dash6 = "------";
$dash8 = "--------";
$dash30 = "------------------------------";
$firstheading = 1;
@tablename = ();
### connect to database
$dbh = DBI->connect('DBI:Oracle:host=voyager.library.wmich.edu;sid=YOURSID',
'dbname', 'password')
or die "connecting: $DBI::errstr";
# get distinct list of table names into an array
$sqlquery = sprintf("select table_name from user_tab_columns order by table_name");
$sth = $dbh->prepare($sqlquery) or die "preparing query statement";
$rc = $sth->execute;
$oldtablename = "";
$numtables = 0;
$loopctr = 0;
while (@row = $sth->fetchrow_array)
{
if ($row[0] ne $oldtablename)
{
$numtables++;
$tablename[$numtables] = $row[0];
$oldtablename = $row[0];
}
$loopctr++;
}
$sth->finish;
# get number of columns per table
$idx = 1;
while ($idx <= $numtables)
{
$sqlquery = sprintf("select count(*) from user_tab_columns
where table_name = '%s'", $tablename[$idx]);
$sth = $dbh->prepare($sqlquery) or die "preparing query statement";
$rc = $sth->execute;
@row = $sth->fetchrow_array;
$tablecolumns[$idx] = $row[0];
$idx++;
}
$sth->finish;
8
# generate the report
$fileout = ">lb2510.rpt";
$fopen = sprintf("Cannot open %s for output\n", $fileout);
open(fileout, $fileout) or die $fopen;
doheading();
$idx1 = 1;
while ($idx1 <= $numtables)
{
$sqlquery = sprintf("select table_name,
lower(column_name),
lower(data_type),
nvl(data_precision, data_length),
data_scale,
nullable
from user_tab_columns
where table_name = '%s'
order by column_name", $tablename[$idx1]);
$sth = $dbh->prepare($sqlquery) or die "preparing query statement";
$rc = $sth->execute;
# get data from query, mark rows where the Oracle column name ends in "_id"
# and store in array
$numrows = 0;
while (@row = $sth->fetchrow_array)
{
$isid = 0;
$col = $row[1];
if (substr($col, length($col)-3, 3) eq '_id')
{
$isid = 1;
}
$rowstr = join '|', $row[0], $row[1], $row[2], $row[3], $row[4], $row[5], $isid;
@tbldata[$numrows] = $rowstr;
$numrows++;
}
# output report data (from temporary array)
$firstone = 1;
# output "_id" columns first
$idx2 = 0;
while ($idx2 < $numrows)
{
@row = split /\|/, $tbldata[$idx2];
# if fieldname ends with "_id"
if ($row[6] == 1)
{
if ($firstone)
{
$firstone = 0;
if (($linectr + $tablecolumns[$idx1]) > $pagesize) {doheading();}
printf fileout ("%-30.30s %-30.30s %-8.8s %6.6s %3.3s %1s\n",
$row[0], $row[1], $row[2], $row[3], $row[4], $row[5]);
}
else
{
printf fileout ("%-30.30s %-30.30s %-8.8s %6.6s %3.3s %1s\n",
" ", $row[1], $row[2], $row[3], $row[4], $row[5]);
}
$linectr++;
}
$idx2++;
}
# now output non "_id" columns
9
$idx2 = 0;
while ($idx2 < $numrows)
{
@row = split /\|/, $tbldata[$idx2];
# if fieldname does not end with "_id"
if ($row[6] != 1)
{
if ($firstone)
{
$firstone = 0;
if (($linectr + $tablecolumns[$idx1]) > $pagesize) {doheading();}
printf fileout ("%-30.30s %-30.30s %-8.8s %6.6s %3.3s %1s\n",
$row[0], $row[1], $row[2], $row[3], $row[4], $row[5]);
}
else
{
printf fileout ("%-30.30s %-30.30s %-8.8s %6.6s %3.3s %1s\n",
" ", $row[1], $row[2], $row[3], $row[4], $row[5]);
}
$linectr++;
}
$idx2++;
}
if ($linectr < ($pagesize-3))
{
print fileout "\n";
$linectr++;
}
$idx1++;
}
close(fileout);
### clean up at end
$sth->finish;
$dbh->disconnect;
sub doheading
{
if (not $firstheading) {print fileout "\f";}
else {$firstheading = 0;}
printf fileout ("Table Name
Column
Type
Length Dec Null?\n");
printf fileout ("%s %s %s %s %s %s\n\n", $dash30, $dash30, $dash8, $dash6, $dash3, $dash5);
$linectr = 3;
}
10
; lb2600 - Serials: titles, PO#s, details, by fund and dept - WinBatch script
; this WinBatch file starts at a certain time, ftp's the SQL report file from
; Voyager, brings it into Word, formats it, and prints it in the Library's
; Serials printer
; should run all the time
; starting this script:
;
start after main loop checking time if today is the day the report is to
;
be printed and it has already been printed
;
else can start any time and any day
; Word settings:
;
7pt Monospac 821DL, landscape,
;
.5" margins
;
print on first floor Serials printer
;*** CONSTANTS
unixpath = "/usr/local/rpt/"
pcpath = "c:\librpts\"
rptid = "lb2600"
rptext = ".rpt"
pwfilename = "c:\librpts\batchpw.psi"
pwfile = fileopen(pwfilename, "read")
pw = fileread(pwfile)
fileclose(pwfile)
pwstr = strcat(pw, "~")
;*** BUILD COMPLETE UNIX AND PC FILENAMES
unixfile = strcat(unixpath, rptid, rptext)
;message("",unixfile)
pcfile = strcat(pcpath, rptid, rptext)
;message("",pcfile)
ftpfile = strcat("c:\program files\winbatch\batch files\", rptid, "ftp.wbt")
;*** MAIN LOOP STRUCTURE
;*********
:starthere
;*********
timenow = strsub(timeymdhms(), 12, 8)
modaynum = strsub(timeymdhms(), 9, 2)
if (modaynum == "02") || (modaynum == "16") then
if (timenow >= "08:23:00") && (timenow <= "08:45:00") then
ftppwstr = strcat('sendkeysto("ftp","', pwstr, '")')
ftpgetstr = strcat('sendkeysto("ftp",', '"get ', unixfile, ' ', pcfile, '~~")')
hftp = fileopen(ftpfile, "write")
filewrite(hftp, 'run ("c:\windows\ftp.exe","")')
filewrite(hftp, 'winwaitexist("ftp", 20)')
filewrite(hftp, 'sendkeysto("ftp","open voyager.library.wmich.edu~")')
filewrite(hftp, 'sendkeysto("ftp","zimmer~")')
filewrite(hftp, ftppwstr)
filewrite(hftp, 'sendkeysto("ftp","ascii~")')
filewrite(hftp, ftpgetstr)
filewrite(hftp, 'sendkeysto("ftp","bye~~")')
fileclose(hftp)
run(ftpfile,"")
timedelay(60)
if fileexist(pcfile) then
; ***format and print it
run ("c:\program files\mso97\office\winword.exe", pcfile)
; delete leading formfeed
sendkey("{DEL}")
; set document size and orientation
11
sendkey("!f{TAB 7}{ENTER}!s!c!m!t.5!b.5!f.5!g.5{TAB 5}{ENTER}")
; set font and font size
sendkey("!e{TAB 8}{ENTER}!o{ENTER}")
sendkey("Monospac821 DL{TAB}{TAB}7")
sendkey("!k!k!p!p!w!w!o!o!m!m!h!h{TAB 2}{ENTER}")
; now send to printer
;
this sendkey string may change whenever the
;
available printer pool changes,
;
or if the default printer is changed
sendkey("^p{TAB 7}!n{DOWN 4}{TAB 9}{ENTER}")
; wait for doc to print
timedelay(60)
; now close Word (leading CR to get rid of extra message)
sendkey("~!{F4}!n")
; wait until 0823 tomorrow so can exit processing loop
now = timeymdhms()
tomorrow_at_823 = timeadd(strcat(strsub(now,1,11),"00:00:00"), “0000:00:01:08:23:00")
timewait(tomorrow_at_823)
exitvalue = 1
;
else> hook for email notification: failure, .rpt file not found
endif
else
; wait 10 minutes and try again
timedelay(600)
exitvalue = 1
endif
else
; not desired day, so wait a day
; wait until 0823 tomorrow
now = timeymdhms()
tomorrow_at_823 = timeadd(strcat(strsub(now,1,11),"00:00:00"), "0000:00:01:08:23:00")
timewait(tomorrow_at_823)
exitvalue = 1
endif
if exitvalue == 1 then goto starthere
; this would be a good location to hook into failure notification via email
errmsg = strcat("Contact programmer.%@crlf%Script for ", rptid, rptext, " exited loop.")
message("ERROR", errmsg);
exit
===================================================================================
; example from an other script showing how to restrict
; execution for specific days
timenow = strsub(timeymdhms(), 12, 8)
a = timeymdhms()
b = timejulianday(a)
c = (b + 5) mod 7
weekday = itemextract(c+1, "Sun Mon Tue Wed Thu Fri Sat", " ")
if weekday != "Sun" then
if (timenow >= "07:53:00") && (timenow <= "08:20:00") then...
12
Download