status bar hangs when parsing through 250,000 line text file

hey guys,

when i'm parsing through a textfile with 250,000 lines my application becomes "not responding" and my status bar does not update anymore. my status bar is showing 10,000 / 250,000 lines read, 20,000 / 250,000 lines read.

what can i do to make it responsive again? thanks guys!! = ))
developingprogrammerAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Jeffrey CoachmanMIS LiasonCommented:
clearly define "parsing"

Opening the file in Notepad.?
Viewing the text in Access?
Opening a linked text document in Access, ?
Editing text in Access?

Not sure why you are storing that much text in Access, ...why not export this to a text file...?
0
developingprogrammerAuthor Commented:
oops sorry boag2000 i'm importing into Access!! = ))

Private Function NG506_rawClean_To_dbUnfiltered(ByRef strImportTable As String)
    Dim objFSO                      As FileSystemObject
    Dim tsNG506                     As TextStream
    Dim strPathFile             As String
    Dim strTotalLines               As String
    Dim strCurrentLine              As String
    Dim booGetNextEndingBalance     As Boolean
    Dim objRegEx                    As VBScript_RegExp_55.RegExp
    Dim objMatchCollection          As MatchCollection
    Dim rsdataReconciliationAccount As DAO.Recordset
    Dim curEndingBalance            As Currency
    Dim dteProcessingDate           As Date
    Dim strProcessingDate           As String
    Dim strYear                     As String
    Dim strMonth                    As String
    Dim strDay                      As String
    Dim strSQL                      As String
    Dim dteImportDateTime           As Date
    Dim strSQLSelect                As String
    dteImportDateTime = Now()
    
    strPathFile = modGenericResources.ShowFileDialogChooser
    Set objFSO = New FileSystemObject
    
    'get total lines
    Set tsNG506 = objFSO.OpenTextFile(strPathFile, ForReading)
    
    'this is for a progress bar
    Call SysCmd(acSysCmdSetStatus, "Initialising parse through textfile.")
    tsNG506.ReadAll
    strTotalLines = Format(tsNG506.Line, "###,###,###")

    'preparing regex to search for ending balance
    Set tsNG506 = objFSO.OpenTextFile(strPathFile, ForReading)
    Set objRegEx = New VBScript_RegExp_55.RegExp
    
    With objRegEx
        .MultiLine = False
        .Global = True
        .IgnoreCase = True
        .Pattern = "-?[\d,.]+"
    End With
        
    strSQLSelect = "SELECT dataReconciliationAccount.* " & _
                   "FROM dataReconciliationAccount " & _
                   "WHERE (((dataReconciliationAccount.Type)=""General Ledger""))" & _
                   ";"

    Set rsdataReconciliationAccount = CurrentDb.OpenRecordset(strSQLSelect, dbOpenDynaset)
    
    Do While Not tsNG506.AtEndOfStream
        If tsNG506.Line Mod 10000 = 0 Then
            Call SysCmd(acSysCmdSetStatus, "Extracted " & Format(tsNG506.Line, "###,###,###") & " out of " & strTotalLines & " lines.")
        End If
    
        strCurrentLine = tsNG506.ReadLine
                
        'get processing date --> do once only
        If dteProcessingDate = 0 Then
            If InStr(1, strCurrentLine, "            ON ") > 0 Then
                strYear = Mid(strCurrentLine, 22, 4)
                strMonth = Mid(strCurrentLine, 19, 2)
                strDay = Mid(strCurrentLine, 16, 2)
                dteProcessingDate = DateSerial(strYear, strMonth, strDay)
            End If
        End If
        
        If booGetNextEndingBalance = False Then
            'check if line contains GL account number
            rsdataReconciliationAccount.MoveFirst
            Do While Not rsdataReconciliationAccount.EOF
                If InStr(1, strCurrentLine, rsdataReconciliationAccount("AccountNumber") & " " & rsdataReconciliationAccount("PCCode") & "  " & rsdataReconciliationAccount("Section")) > 0 Then
                    booGetNextEndingBalance = True
                    Exit Do
                End If
                rsdataReconciliationAccount.MoveNext
            Loop
        End If
        
        If booGetNextEndingBalance Then
            'get ending balance
            If InStr(1, strCurrentLine, "ENDING BALANCE(ORIGINAL CURR)   :") > 0 Then
                Set objMatchCollection = objRegEx.Execute(strCurrentLine)
                curEndingBalance = objMatchCollection(0)
                
                'write to database
                strSQL = "INSERT INTO " & strImportTable & " (ImportDateTime,GLAccountNumber,PCCode,Section,ValueDate,EndingBalance) " & _
                    "VALUES (#" & dteImportDateTime & "#,""" & rsdataReconciliationAccount("AccountNumber") & """,""" & rsdataReconciliationAccount("PCCode") & """,""" & rsdataReconciliationAccount("Section") & """,#" & Format(dteProcessingDate, "m-d-yyyy") & "#," & curEndingBalance & ");"
                CurrentDb.Execute strSQL, dbFailOnError
                booGetNextEndingBalance = False
                
            End If
        End If
    Loop
    Call SysCmd(acSysCmdSetStatus, " ")
    
    tsNG506.Close
ErrEx.CatchAll
    modGlobalErrorHandler.Unwind
ErrEx.Finally
    
End Function

Open in new window

0
Jeffrey CoachmanMIS LiasonCommented:
Does the work if you comment out all the status bar code?
0
Newly released Acronis True Image 2019

In announcing the release of the 15th Anniversary Edition of Acronis True Image 2019, the company revealed that its artificial intelligence-based anti-ransomware technology – stopped more than 200,000 ransomware attacks on 150,000 customers last year.

Jeffrey CoachmanMIS LiasonCommented:
Also note that you are not setting the recordset to nothing at the end of your code, so you are not releasing the memory.

tsNG506.Close
Set tsNG506=Nothing

Beyond that, and the sheer number of rows you are trying to process, i can't see anything else wrong...

Perhaps another expert can help optimize the looping...
or perhaps you could split up the text file....?
0
developingprogrammerAuthor Commented:
hi boag2000! yup the procedure works perfect with or without the status bar code = )

the only thing is that i'm trying to get consistent updates for the status bar as it increases by 10,000 each time = )

boag2000! i tried inserting a DoEvents line right after the status bar line and the status bar updates as it should.inserting a Screen.ActiveForm.Repaint doesn't work though (as expected i guess cause the status bar is an application thing)


however boag2000 i don't want to use DoEvents to get the status bar to update. DoEvents is for something else and using its side effect of a total screen update is more of a hack i feel.

what do you think i should do? = )
0
developingprogrammerAuthor Commented:
hrmm boag2000 for releasing the record set, as soon as the variable goes out of scope it's destroyed by the reference count decreasing by 1 to 0 (as i only refer to it in this procedure). when it's destroyed doesn't it also release the memory?

hrmm as to why i don't set the variable to nothing explicitly hrmm, ok it's gonna sound dumb what i'm gonna say next but perhaps you can correct me and i can improve = )

i don't set my variables to nothing because it involves a lot of extra work and the variable will go out of scope anyway already. BUT the main reason is for consistency. if i set some variable to nothing and some i don't because i forget, then i lose consistency in my programming style already due to my fallible and forgetful mind.and thus to preserve consistency in my programming, i actively choose NOT to set my variables to nothing at the end.

what do you think? are there any repercussions that i should take note of and heed?

thanks in advance boag2000!! = ))
0
Jim Dettman (Microsoft MVP/ EE MVE)President / OwnerCommented:
Couple comments:

<<what do you think? are there any repercussions that i should take note of and heed? >>

Always close objects you open and set object variables to nothing.  Yes, VBA is supposed to do it for you, but throughout the years, we've seen many times where it simply doesn't.

 Any good developer of VBA code will do this without question.  And the operations do different things.  Both are required.

<<when i'm parsing through a textfile with 250,000 lines my application becomes "not responding">>

 Many mis-understand the "not responding" message from Windows.  While it may mean your program is hung, that's not always the case.

 Open a large table in Access, do a find and after 20-30 seconds, you will most likely see "not responding".   Yet the operation will complete if you give it time.  You can also hit Ctrl/Break and get an immediate response.

"Not responding" in Windows simply means that a message was sent to the window and it hasn't been processed yet.  The program may still be executing fine, but it may be waiting for other operations to complete before it does anything else.

 You can see this often as well with sync queries being run.

Jim.
0
Jeffrey CoachmanMIS LiasonCommented:
Yeah, I hated it when "Not responding" became common when Access is just "processing".
May people presume that it has crashed and make matters worse by Ctrl_Alt-Del-ing, out of Access...

I rarely use the status bar for progress indication, so I will let Jim help you with that...
0
developingprogrammerAuthor Commented:
cool!! thanks Jim!! well i want to be a good programmer so i will start closing all my objects and setting them to nothing at the end of my procedures moving forward!! thanks so much for that tip!! = ))

ha boag2000 am glad that you are also affirming this user experience that i'm facing - at least i know i'm on the right track!! haha = )

boag2000, if you don't use the status bar for progress indication, what do you usually use? fyed wrote and article on progress bar and i read through it, it's quite cool and i would love to implement it when i wrap up my project. here it is (http://www.experts-exchange.com/Microsoft/Development/MS_Access/A_2573-Progress-Bars-Keeping-users-informed-during-extensive-processing-periods.html). but what do you personally use for progress indication? thanks boag2000!!! = ))

so Jim, what do you think i can do to ensure the status bar updates? i think the DoEvents is kinda like a hack with bad side effects haha.

thanks guys!! = ))
0
BitsqueezerCommented:
Hi,

using "DoEvents" is OK to give the control back to Access for a moment so it can say to Windows "Hey, I'm still living" and it also executes other events including the screen refresh. You should NOT use it in a fast running loop as it would slow down your loop a lot and it would also bring the CPU to glow (like the following):
Do
   DoEvents
Loop Until SomeCondition

Open in new window

(This can be improved by using a Windows API Sleep call.)

In your case, where you only refresh the status bar every 10,000 lines it is OK to insert DoEvents exactly there, at the same position where you refresh the status bar, so it is called very rarely. There is no workaround to use this in long running loops, but it should be used with any kind of counter to not call it in every cycle of the loop. A API Sleep is of course no choice in such a loop as it is a worker loop and not a waiting loop.

Some hints for your code: The "rsdataReconciliationAccount" loop costs really a lot of time as you must go through the complete recordset again and again. I would first insert the rows of the external file into a temporary import table and then use SQL to parse that. I.e., you can then create a cartesian product of all import rows with all account records and set a result column where InStr(...) returns a value > 0, so you can then filter that out. Then you can use the filtered list to take it into a INSERT...SELECT query. (Do you remember? "Think SQL, not VBA")
I would bet that the import would be a lot faster so in the end you even do not need a progress bar...;-)

In general: A progress bar is a really important thing for long running things as the user should always see that there is something happening. If the user must wait longer than 10 seconds it is most likely that he will call the task manager...:-)

Set to Nothing: May be some extra work and very annoying, but you should really try to do that always. I also forget that here and there, but whenever I see that later I add it. Sometimes it costs really a lot rows to do that, but for that purpose there are tools like MZTools which can insert a code block you can define on your own. For example this one:
If Not rs Is Nothing Then
    rs.Close
    Set rs = Nothing
End If

Open in new window

If you do not always use a new name for a recordset variable that is enough (in most cases you only need one recordset variable inside one procedure so it is not needed to give it a more meaningful name).

You're right, VBA does that job on it's own, but such automatisms cannot do anything for you. For example the recordset: The standard job VBA does is, set it to Nothing. This would call a terminate procedure in the recordset class and it is most likely that this will contain a "Close" execution so that's be done automatically also. But you don't know that for sure as you cannot look into the code of the recordset object - and so it is better to do it explicitly than doing it implicitly. In case of your own classes you should also always have a Class_Terminate procedure if there is any object variable in your class which needs to be set to Nothing.
The other reason is: If you don't do it, yes, the last reference pointer count will set the counter to 0, that's the signal to VBA to remove the object from memory. The problem is: When will this be done? It is wrong to think that this will be done in the moment your procedure ends. VBA does this in a procedure called Garbage Collection (which was also the case in computers like C64, no new invention, of course the modern ones are a lot better). This goes through all objects and removes them from memory, but it will be executed only if VBA has nothing else to do (or not much). So think of the recordset example: It is still in memory while your application does other things and it STILL HAS AN OPEN CONNECTION and all the data you loaded into it. Only when the Garbage Collector has time to release the objects from memory the Terminate procedure will be executed, the connection will be closed and the recordset will be removed from memory. So you see, it can be very important to do that explicitly, in special, the Close method, so you can be sure that at least the connection is closed immediately. The "Set rs = Nothing" will then immediately call the Terminate sub so the rs object has the chance to release anything it used by itself immediately. The object will also not be destroyed at this moment, the Garbage Collector does it's job anytime later after your application lets it enough time. But you can be sure that anything inside the object is dead, no connection, no other active thing.

Cheers,

Christian
0
developingprogrammerAuthor Commented:
(developingprogrammer is very excited and researching cartesian product now)
0
Jim Dettman (Microsoft MVP/ EE MVE)President / OwnerCommented:
<<using "DoEvents" is OK to give the control back to Access for a moment so it can say to Windows "Hey, I'm still living" and it also executes other events including the screen refresh. >>

 um you didn't state that quite right; using DoEvents tells Access to yield it's processing time to the OS so it can do other things (like processing events in its queue and all key presses).  It doesn't give control back to Access.

<<boag2000, if you don't use the status bar for progress indication, what do you usually use? fyed wrote and article on progress bar and i read through it, it's quite cool and i would love to implement it when i wrap up my project. >>

 I have a form class that I use for my messaging (attached).  Drop the form into a DB and then call it as shown in the demos.  Couple different type of bars in there (timed, stepped, etc).

Jim.
ProgressBar.zip
0
BitsqueezerCommented:
Hi Jim,

OK, if you want... "DoEvents" is a function which is part of VBA, and although VBA is an own object it is also part of Access, so it is executed "by Access" (by VBA) first - there must be something which executes it, before it gets to Windows, right? And in the other direction: Windows sends a message back to Access (Access, not VBA) that says "do a screen refresh" and so the control is now at Access which refreshes the screen and does any other needed event procedure (which includes answering the system message to tell Windows that it is still "alive") until it gives the control back to the running VBA procedure.

But really, is that an important difference to explain here...?...;-)

Cheers,

Christian
0
Jeffrey CoachmanMIS LiasonCommented:
boag2000, if you don't use the status bar for progress indication, what do you usually use?
...To be perfectly honest
...In most of what I do the hourglass is more than sufficient enough.
But in cases where I do need a progress bar, I use a form based solution like what Jim posted.
I just like to keep these things around as "forms", so I can just drop them into my apps.

My other concern is that perhaps MS will one day decides to change the way the status bar functions, thus possibly breaking all code written for it... :-O

JeffCoachman
0
Jim Dettman (Microsoft MVP/ EE MVE)President / OwnerCommented:
Christian,

<<and so the control is now at Access>>

 No, the OS does its things, which is processing messages to/from the window and processing queues.   Part of that could be redrawing the window on the screen, processing of keystrokes, mouse movements, etc, or "I'm alive" message, but all of it has already happened.

  Once you issue a DoEvents(), MSAccess.exe does not get execution time back to do anything until the OS has processed everything outstanding related to the window.

 Once that happens, MSAccess.exe starts executing again when it gets its next set of time slices.

<<which refreshes the screen and does any other needed event procedure (>>

 No and that's why I pointed this out; execution of MSAccess.exe completely stops when a DoEvents() is hit.  That includes any and all threads it owns (VBA and JET).

<<But really, is that an important difference to explain here...?...;-)>>

 I thought so or I would not have made the comment.  

 DoEvents() all too often is used exactly the opposite of what it was intended for.

Jim.
0
BitsqueezerCommented:
Hi Jim,

we can make a long discussion about that, but the result is always the same: You need to use DoEvents in case of long running loops, isn't it?

And, by the way, which procedure do you think redraws a window (any application, not only Access)? Windows only gives the command (the message) to redraw, the application itself needs to do it itself, Windows only draws the window itself. And that's the only way it works - how should Windows know anything about the contents of a window in any application? It only rebuilds (not redraws) a window if it for example moves a window by holding the mousebutton because that can be done faster by a graphic card. But if you release the button, the message goes to the application to redraw and it's up to the application to do it or not.

But the more interesting question would be: Why do you think it's used for the opposite in some cases? You can not do anything meaningful with this command other than described. I would like to know examples where it can be misused (other than in my example above to call it too often).

Cheers,

Christian
0
Jim Dettman (Microsoft MVP/ EE MVE)President / OwnerCommented:
<<You need to use DoEvents in case of long running loops, isn't it?>>

 Depends on what the loop is doing and what the issue is.

<<But the more interesting question would be: Why do you think it's used for the opposite in some cases? You can not do anything meaningful with this command other than described. I would like to know examples where it can be misused (other than in my example above to call it too often).>>

  This is a clear example and when it's most often mis-used; DoEvents() is sprinkled in to let Access "catch up".

  Yet it performs the opposite function, it stops Access from executing and let's the OS catch up and other apps run.  

 DoEvents() was placed in VBA to support OLE automation.  It was designed and intended for places where you wanted/needed to let an app other then MSAccess.exe get something done.  In regards to Access itself, there is never any need for it really, unless you have a very tight loop and want to give the ability to the user to interupt quickly.

 So to wrap this up, from the on-line help:

"Yields execution so that the operating system can process other events."

 Which is exactly opposite of what you said:

"using "DoEvents" is OK to give the control back to Access for a moment so it can say to Windows "Hey, I'm still living""

which is not what it does.

Jim.
0
BitsqueezerCommented:
Hi Jim,

Depends on what the loop is doing and what the issue is.
Simply no. Show me an example where a loop which runs at least around 20 seconds or longer would not profit from using DoEvents (as long as it is not called too often). The sense of using it (independent of what the OS or Access or VBA does) as programmer is to don't let Access becoming "not responding" and the possibility to refresh any form contents and to react on user activity.

Yet it performs the opposite function, it stops Access from executing and let's the OS catch up and other apps run.
That's what I said above: This is an assumption from coming from some silly text in the help file where the author also didn't want to get too deep into Windows internal details (and why should he/she if you think of which kind of users MS wants to use Access...).

What is done when the interpreter reaches the DoEvents? It is first this part of the application which executes the DoEvents so it can stop Access and VBA to let the OS doing it's job. But what is it what Windows is doing? Beside giving a time share to other applications which are not of interest here, it also sends a message to redraw the contents of any window so how can this happen when Access never gets the chance to do that? How can it send any message in response to what the OS is sending if it never get the control back before VBA is running again? If it would be true that only Windows gets some job done, then the VBA procedure would go on running and the form will never change it's contents during a loop and also a mouse click to a Stop button would not work! Who do you think handles the click event, and more than that: Executes another VBA procedure although a running loop in the other procedure exists?

So pleaasse can we stop this discussion now as it really doesn't lead to anything? It is hair splitting at it's best.

Cheers,

Christian
0
Jim Dettman (Microsoft MVP/ EE MVE)President / OwnerCommented:
<<So pleaasse can we stop this discussion now as it really doesn't lead to anything?>>

 Like I'm the one that keeps responding!

 Get over it...

Jim.
0
developingprogrammerAuthor Commented:
hi all! thanks so much for all your responses!

you know whenever i programme then i hit a road block and seek your advice, if it's a big ideological change in what i'm doing then i'll always have to go back to the drawing boards and rethink everything through haha - but that's good! cause that means yall are enlightening me so much to so many things!! = ))

hi Jef!! = )) thanks for all your help on this question!! i think it's definitely very reassuring when someone with so much knowledge as yourself share what your personal practices are - that helps me know that i'm on the right track too!!! = )) okie dokes, i will adopt the progress form and add it to my programme = )) i'm actually very excited to do this because i think it makes my programme look so much more professional!! haha = )) thanks Jeff!! = ))

hi Jim!! the demo .mdb with the progress bar form is great!! i went through it a couple of times and am looking forward to integrate your progress bar into my app - i think it would be a fantastic touch!! thanks for that!! = ))

hi Jim and Christian!! thanks so so much for sharing your discussions in this question!! as an observer and also a beginner, i've learnt so much from yall through all your answers in the past and now as well!! = ))

i'm kinda piecing together what i've read from yall and i think i've kinda got the picture in my head! i'd love to share! = )

wait.... wait.... and ta da!!! my SUPER IMPRESSIVE POWER POINT SKILLS!!!! hahahhaa

doevents
so guys, i guess the question is - is there any other way other than DoEvents to redraw the Access application without giving time share to other applications in Windows?

thanks guys!! = ))
0
developingprogrammerAuthor Commented:
hi Christian!!

i tried the SQL way and BOY IT WAS OUT OF THE BOX THINKING!! = ))

i never would have thought of a cartesian product with instr ha = )

hrmm, i'm not sure why but it actually takes a heap lot longer than the current procedure i'm writing now

here's my syntax. hrmm, rightfully it should at max take just as long as the recordset method.

but WHAO - using SQL to extract stuff from a text file? super cool man. i could never think of that ha = )

SELECT DELETENG506.Field1, dataReconciliationAccount.AccountNumber, InStr(1,[Field1],[AccountNumber]) AS test
FROM DELETENG506, dataReconciliationAccount
WHERE (((InStr(1,[Field1],[AccountNumber]))>0));

Open in new window


hrmm so issue 1 Christian is the speed of it.

issue 2 is that - for my extraction i'm finding a certain line, and then after that i'm finding the line with a certain text. this next line could be 10 lines away, could be 100 lines away - it's variable.

how would i write an SQL to do that? seems like it's getting a bit complex for SQL - or rather a bit complex for me!! = ))
0
BitsqueezerCommented:
Hi,

regarding your Powerpoint I would say, yes, something like this, only that in my opinion VBA goes directly to Windows and not the step to Access in between (as DoEvents is a VBA function). But the exact way is only known by MS people, I think, maybe if you find the details in the Internet somewhere. I say: It's not so important to know, better to know how and when to use it.

Could you upload a demo database? It's a little bit difficult to test that without the data. Often the problem in performance is a missing index or something like that. You could also replace the Instr in SQL by using LIKE '*' & [AccountNumber] & '*' because you would stay in SQL in that case whereas Instr would need to call the VBA function (didn't thought of that when I wrote the thing with InStr).

Issue #2: You can use the first query to find out the IDs of the lines and then use that as subquery for the next query using something like "WHERE ... IN (YourSubquery)".

Cheers,

Christian
0
developingprogrammerAuthor Commented:
ah yes Christian! yup yup when i was reading your reply when i read to the words "replace Instr in SQL" i immediately thought of the EMERGENCY article hahaha

hrmm i'm not sure how to omit / scramble the sensitive data in the textfile so i'm not sure how to upload it = (

hrmm but Christian it seems to me that for simple extraction it's possible and probably faster to use SQL. but for complex extraction it may be easier to use procedural methods. hrmm for example if i need to extract a lot of records form an excel sheet that has multiple tables, so the procedure is i use the find function to find the certain cell first, then the next field is an offset(,2), then the next field is an offset(1,1), then the next field is at the top of the small data island that i use an end(xlup) function to find. i think in that case it would be better to use a procedural method right?

hrmm so the same applies for the WHERE... IN (subquery) i think - it's something like regex. it is theoretically possible to find all email addresses but it will be very very complex. do you think this is true Christian? or should i try and up my SQL skills so that i can do everything in SQL? well i mean i know it's always the right tools for the right things, but as a training purpose would you think that all extractions can be done through SQL? i can't see how the end(xlup) and multiple offset cases can be done in SQL - but in the same breath there were many things i thought weren't possible but later you showed me how haha = )

thanks Christian!! = ))
0
BitsqueezerCommented:
Hi,

for your data file, create a simple data generator which uses RND to create senseless data in the right format (so that your program can import it), i.e., if you need to create an email address, create a random short string, add an @, add another short string, add a dot and a "com" or anything you want. In the same way you can do that for other formats, seperate the result by the wanted separator like Tab or whatever you need, create the output file by writing it into the file.
It can be done with a little VBA procedure. I'm sure you are able to achieve that...;-)

No, of course you cannot do ANYTHING with SQL, in some situations a procedure has advantages. In case of Excel it is also that you should first think about if it is possible to use the Excel table as a SQL table (by, for example, open it through ADO or DAO).

Cheers,

Christian
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
developingprogrammerAuthor Commented:
yes of course i can!! are you doubting me???? I'M FROM TCSOA!! haha = ))

okie gimme some time to do that ya, just finishing up this other component now!! = ))
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Access

From novice to tech pro — start learning today.