{"id":332,"date":"2004-09-30T21:02:19","date_gmt":"2004-09-30T13:02:19","guid":{"rendered":"http:\/\/foxpro.ntsl119.com\/scr\/?p=332"},"modified":"2007-10-29T11:49:35","modified_gmt":"2007-10-29T03:49:35","slug":"vfp-sql-verus-do-while","status":"publish","type":"post","link":"https:\/\/foxpro.ntsl119.com\/scr\/archives\/332","title":{"rendered":"VFP SQL verus DO WHILE"},"content":{"rendered":"<p><font face=\"Tahoma, Verdana, sans-serif\">172<\/font> bugs-to-squash+features-to-code down&#8230; <font face=\"Tahoma, Verdana, sans-serif\">1,161,017<\/font> to go. I&#8217;ll break from the task for a while and blog a little.<\/p>\n<p>I visited a client yesterday confident that I had tweaked the ILS program to make things faster. I ended up realizing &#8216;on site&#8217; that things got slower by <font face=\"Tahoma, Verdana, sans-serif\">1560<\/font> folds. <\/p>\n<p>Bad.  Too bad really.<\/p>\n<p>Because of some server folder\/file-security-related issues, I have to separate the directories that are used for the ILS module (the main library system) and SASM (the book+author+subject+callnum+isbn searching) module that is being used by the students\/faculty members in a given library.<\/p>\n<p>Because the tables are normalized (UGH I still have an <a href=\"http:\/\/foxpro.ntsl119.com\/archives\/00000321.html\">unfinished discussion blog about normalization<\/a>), I have to use some VFP SQL queries to gather all the data needed from three separate tables. VFP SQL ((sans the JOIN&#8230;. yup using that makes the querying of data turtle-fast (no offense to the turtles)) is still slow. <\/p>\n<p>(More than <font face=\"Geneva, Arial, Helvetica, sans-serif\">30<\/font> seconds of query-ing is slow by Foxpro standards (we&#8217;re so used to Rushmore&#8217;s legendary lightning speed technology)).<\/p>\n<p>For those who are not used to Visual Foxpro, VFP has it&#8217;s own &#8216;native&#8217; SQL functions which can be used without relying on ADODB, OLEDB, ODBC and whatever ODODODODO-database-related-technologies proliferating around.<\/p>\n<p>So to tighten up things a little bit I decided to make a separate &#8216;gatherer module&#8217; which will be executed on the server\/admin part and will be thrown to the student\/users PC used for searching instead of slowing down things every time the user &#8216;SASMs&#8217;.<\/p>\n<p>I tried using the VIEWS approach on this one (which apparently uses VFP SQL commands too) but have to withdraw at the last minute since there are some incompatibility issues with some table formats that I&#8217;m using and I don&#8217;t want to completely dive in without testing things further.<\/p>\n<p>So I decided to just create a different &#8216;buffer table&#8217; that will hold the fields gathered from these three databases&#8230; using the native VFP SQL command. Here&#8217;s the code:<\/p>\n<pre><font size=\"2\" face=\"Tahoma, Verdana, sans-serif\">cDATABASE = 'BOOKSASM'<br \/>\r\nset safety OFF<br \/>\r\n<\/font><font color=\"#0000FF\">select<\/font> BOOKS.ACCESSNO, BOOKS.CALLNUM, BOOKS.TITLE, BOOKS.ISBN, ;<br \/>\r\n      BOOKS.BORROWED, min(AUTHORS.NAME) as [NAME], ;<br \/>\r\n      LOCATION.LOCATION ; <br \/>\r\n   <font color=\"#0000FF\">from<\/font> BOOKS, AUTHORS, LOCATION ;<br \/>\r\n   <font color=\"#0000FF\">into dbf<\/font> &amp;cDATABASE ;<br \/>\r\n   <font color=\"#0000FF\">group by<\/font> BOOKS.ACCESSNO, BOOKS.CALLNUM, BOOKS.TITLE, ;<br \/>\r\n      BOOKS.ISBN, BOOKS.BORROWED, LOCATION.LOCATION ;<br \/>\r\n   <font color=\"#0000FF\">where<\/font> ((BOOKS.ACCESSNO == AUTHORS.ACCESSNO) or ;<br \/>\r\n      BOOKS.NUM_AUTHOR == 0) ;<br \/>\r\n      and BOOKS.LIBSECTION == LOCATION.ID <br \/>\r\nset safety ON<br \/>\r\n   <br \/>\r\nselect BOOKSASM<br \/>\r\n   if !file('BOOKSASM.cdx')<br \/>\r\n      index on alltrim(ACCESSNO) tag CBOOIDNO<br \/>\r\n      index on upper(alltrim(CALLNUM)) tag CBOOCALL<br \/>\r\n      index on upper(alltrim(TITLE)) tag CBOOTITL<br \/>\r\n      index on alltrim(LOCATION) tag CBOOLIBS<br \/>\r\n      index on alltrim(ISBN) tag CBOOISBN<br \/>\r\n      index on upper(alltrim(NAME)) tag CBOONAME <br \/>\r\n   endif<br \/>\r\n   <br \/>\r\nclose databases<br \/>\r\nclose all<\/pre>\n<p>\nGuess how long it took for that piece of code to process <font face=\"Tahoma, Verdana, sans-serif\">2224<\/font> records in BOOKS.dbf, <font face=\"Tahoma, Verdana, sans-serif\">2856<\/font> records in AUTHORS.dbf and <font face=\"Tahoma, Verdana, sans-serif\">15<\/font> records in LOCATION.dbf?<\/p>\n<p>Well long enough for me to visit another office and install a newly updated AVRCOM module, discuss that module with the user, return and discuss (with the librarians this time) another set of topics from their lovelife to the difference between computer science and other courses with the &#8216;IT&#8217; letters in it to topics which made me retrieve the baby pictures I have in my wallet.<\/p>\n<p><font face=\"Tahoma, Verdana, sans-serif\">52<\/font> minutes&#8230; for that code&#8230; for that number of records.<\/p>\n<p>And I did not even include the instances where a conflict with the screensaver crashed the query process that I have to start things all over again, and that I copied the files outside the arms of a burdened Novell Netware <font face=\"Tahoma, Verdana, sans-serif\">6<\/font> server and transferred it to the local drive for faster processing.<\/p>\n<p><font face=\"Tahoma, Verdana, sans-serif\">52<\/font> whoopin&#8217; minutes!<\/p>\n<p>So when I got home. I re-configured the code using a reliable old school approach&#8230; DO WHILE\/FOR LOOPS + SET FILTER TO. <\/p>\n<p>Here&#8230;<\/p>\n<pre><font size=\"2\" face=\"Tahoma, Verdana, sans-serif\">select BOOKS\t<br \/>\r\nnCountTotal = reccount()<br \/>\r\nnCounter = 0<br \/>\r\nset filter to <br \/>\r\nset order to CBOOIDNO<br \/>\r\ngo top<br \/>\r\ndo while not eof()\t\t<br \/>\r\n   nCounter = nCounter + 1<br \/>\r\n\t\t<br \/>\r\n   cAccessNo = BOOKS.ACCESSNO<br \/>\r\n   cCallNum = BOOKS.CALLNUM<br \/>\r\n   cBookTitle = BOOKS.TITLE<br \/>\r\n   cISBN = BOOKS.ISBN<br \/>\r\n   lBorrowed = BOOKS.BORROWED<br \/>\r\n   cLibSection = BOOKS.LIBSECTION<br \/>\r\n\t\t<br \/>\r\n   select AUTHORS<br \/>\r\n   set filter to (AUTHORS.ACCESSNO == cAccessNo)<br \/>\r\n   go top<br \/>\r\n   cAuthor = AUTHORS.NAME<br \/>\r\n   set filter to<br \/>\r\n   cLocation = ''<br \/>\r\n   <br \/>\r\n   select LOCATION<br \/>\r\n   set filter to <br \/>\r\n   set order to CLOCIDNO<br \/>\r\n   go top<br \/>\r\n   seek cLibSection<br \/>\r\n   if found()<br \/>\r\n      cLocation = LOCATION.LOCATION<br \/>\r\n   endif<br \/>\r\n             <br \/>\r\n   select BOOKSASM <br \/>\r\n   append blank<br \/>\r\n      replace BOOKSASM.ACCESSNO with cAccessNo<br \/>\r\n      replace BOOKSASM.CALLNUM with cCallNum<br \/>\r\n      replace BOOKSASM.TITLE with cBookTitle<br \/>\r\n      replace BOOKSASM.ISBN with cISBN<br \/>\r\n      replace BOOKSASM.BORROWED with lBorrowed<br \/>\r\n      replace BOOKSASM.NAME with cAuthor<br \/>\r\n      replace BOOKSASM.LOCATION with cLocation<br \/>\r\n             <br \/>\r\n   .cStatusCounter.value = str(nCounter) + '\/' + str(nCountTotal)<br \/>\r\n             <br \/>\r\n   select BOOKS <br \/>\r\n   skip<br \/>\r\nenddo<\/font><\/pre>\n<p>\nNow guess how long this code processed those <font face=\"Tahoma, Verdana, sans-serif\">2224*2856*15<\/font> (Yes * not + : figure that out).<\/p>\n<p>Less than <font face=\"Tahoma, Verdana, sans-serif\">15<\/font> seconds. <\/p>\n<p>I was even tempted to write an exact time counter after an initial test run but things were so fast that writing that part was not needed anymore.<\/p>\n<p>OK&#8230; let me write a code to grab the exact time&#8230; wait.<\/p>\n<table width=\"201\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tr>\n<td width=\"82\">TimeStart:<\/td>\n<p><\/p>\n<td width=\"119\"><font color=\"#0000FF\" face=\"Tahoma, Verdana, sans-serif\">20:48:46<\/font><\/td>\n<\/tr>\n<tr>\n<td>TimeEnd:<\/td>\n<td><font color=\"#0000FF\" face=\"Tahoma, Verdana, sans-serif\">20:48:54<\/font><\/td>\n<\/tr>\n<\/table>\n<p>It is even less than <font face=\"Tahoma, Verdana, sans-serif\">10<\/font> seconds!<\/p>\n<p>So tell me&#8230; what am I missing here?<\/p>\n<p>(Well aside from the fact that VisualFoxpro is fast and it rocks&#8230; everyone knows that already&#8230; including VB-lovin&#8217; humans [GRIN])<\/p>\n","protected":false},"excerpt":{"rendered":"<p>172 bugs-to-squash+features-to-code down&#8230; 1,161,017 to go. I&#8217;ll break from the task for a while and blog a little. I visited a client yesterday confident that I had tweaked the ILS program to make things faster. I ended up realizing &#8216;on site&#8217; that things got slower by 1560 folds. Bad. Too bad really. Because of some [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,10],"tags":[],"class_list":["post-332","post","type-post","status-publish","format-standard","hentry","category-visual-foxpro","category-workblog"],"_links":{"self":[{"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/posts\/332","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/comments?post=332"}],"version-history":[{"count":0,"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/posts\/332\/revisions"}],"wp:attachment":[{"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/media?parent=332"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/categories?post=332"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/foxpro.ntsl119.com\/scr\/wp-json\/wp\/v2\/tags?post=332"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}