Download Programming Example: The Seek method

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Extensible Storage Engine wikipedia , lookup

Concurrency control wikipedia , lookup

Database wikipedia , lookup

Microsoft Access wikipedia , lookup

Open Database Connectivity wikipedia , lookup

Relational model wikipedia , lookup

Clusterpoint wikipedia , lookup

PL/SQL wikipedia , lookup

Database model wikipedia , lookup

Microsoft Jet Database Engine wikipedia , lookup

Transcript
Access Programming Week 7
7. Programming the DAO (continued)
Recordsets (summary so far)
We have seen that Recordset objects provide a way to work with the data in a database. Recordsets are not persistent;
they are destroyed when you close the application. To summarise so far:
Recordsets can be based on:
Tables; queries; SQL statements; other recordsets
Recordsets can be of the following types:
Table-type; Dynaset; Snapshot; Forward-only
Recordsets are navigated using:
logical navigation
the Find.. methods (dynaset, snapshot, forward-only)
the Seek methods (table-type only)
physical navigation
the Move method, the Move.. methods, Do Loops
You can create bookmark variables for two main reasons:
- to save a place in the recordset
- to move to a record in the recordset.
To remind you, the basic technique is as follows:
strMark = rst.Bookmark
Then supposing
rst.MoveNext
To return to the saved place
rst.Bookmark = strMark
Remember, bookmarks are declared as string variables, not object variables
Use multiple bookmark variables if you need to keep track of a complex set of movements
AbsolutePosition and PercentPosition properties
The AbsolutePosition and PercentPosition properties also help you keep track of where you are in a recordset (dynasets and
snapshots only). The AbsolutePosition property can be used to return the record number, if you add one to it (reason
being the system is zero-based i.e., the first record is numbered zero, the second record is numbered one, and so on).
Start a new standard module, save it as Week7 and type the following:
Listing 7.1
Public Sub Navigate()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset("qryOrderStatus", dbOpenSnapshot)
MsgBox "The current record is " & rst.AbsolutePosition + 1 & _
" which is " & rst.PercentPosition & "%"
rst.MoveLast
rst.MoveFirst
rst.Move 5
MsgBox "The current record is now " & rst.AbsolutePosition + 1 & _
" which is " & rst.PercentPosition & "%"
MsgBox "The current Sales Order is " & rst!OrderNo
MsgBox "The number of records is " & rst.RecordCount
rst.Close
End Sub
Remember, in a dynaset or snapshot, the recordset consists only of records accessed, hence the use of the MoveLast and
MoveFirst methods.
1
Access Programming Week 7
Physical Navigation of Recordsets
You can move from one record to another according to physical location in two ways:

you can use the Move.. methods to duplicate the effect of using the navigation buttons, or

you can save your place in a recordset by setting a bookmark and then returning later to the same record
BOF, EOF
properties
You use the BOF (Beginning of File) and EOF (End of File) properties of the recordset object to determine whether
you’ve gone beyond the limits of the recordset. Both properties have the value False as long as there is a current record.
If you move after the last record the EOF property is set to True; if you move before the first record the BOF property is
set to True. If the recordset has no records at all, both the BOF and EOF properties are True.You can test the following:
Set rst = CurrentDb.OpenRecordset("Customers", dbOpenDynaset)
?rst.CustomerName
The first customer name should be displayed, Boots.
rst.MoveLast
The last record is now the current record. Execute
?rst.CustomerName
Should be Tooting Cycles. Execute
rst.MoveNext
You have now moved beyond the last record of the recordset
?rst.CustomerName
An error message should indicate there is no current record
?rst.EOF
should return the value True
rst.MoveFirst
?rst.EOF
should show False
?rst.BOF
should show False
rst.MovePrevious
?rst.BOF
should show True
Looping through recordsets
It is a standard procedure for working with a set of records to create a Recordset object and use the MoveNext method
to loop through the records one by one. To determine when you are finished, you test the value of the EOF property at
the beginning of each pass through the loop. As long as EOF is False, you make another pass through the loop, but as
soon as EOF is True you have moved beyond the last record of the recordset and the loop is finished. The use of Do Until
and Loop keywords is shown.
Do Until rst.EOF
statement(s)
rst.MoveNext
Loop
The following listings all loop through a recordset, and display a variety of syntax that can be used. The first is a basic
procedure, the recordset created is table type by default, and exclamation point syntax is used to refer to the field.
Listing 7.2
Public Sub TableRecordset()
Dim db as Database, rst as Recordset
Set db = CurrentDb
Set rst = db.OpenRecordset("Customers")
Do Until rst.EOF
Debug.Print rst!CustomerName
rst.MoveNext
Loop
End Sub
2
Access Programming Week 7
In the next procedure the fields are referred to by position.
Listing 7.3
Public Sub TableRecordset2()
Dim rst As Recordset
Set rst = CurrentDb.OpenRecordset("Customers")
Do Until rst.EOF
Debug.Print rst(0), rst(1)
rst.MoveNext
Loop
End Sub
Next we see how to assign an SQL statement to a string variable, and open the recordset using the variable name. SQL
techniques may be faster than Find or Seek methods. Note the first field is referred to using string syntax, the others
using exclamation point syntax.
Listing 7.4
Public Sub SQLRecordset()
Dim db As Database
Dim rst As Recordset
Dim strSQL As String
strSQL = "SELECT * FROM Customers WHERE City = 'Brighton' "
Set db = CurrentDb
Set rst = db.OpenRecordset(strSQL)
Do Until rst.EOF
Debug.Print rst("CustomerID"), rst!CustomerName, rst!Address1, rst!City
rst.MoveNext
Loop
End Sub
The SQL statement must be converted into a string that Jet will accept. You must identify the inner string within the
outer string with single quotes (or with pairs of double quotes).
The next listing opens a recordset in another Access database.
Listing 7.5
Public Sub RecordsetOtherDb()
Dim db As Database
Dim rst As Recordset
Set db = DBEngine(0).OpenDatabase("d:\Databases\Accounts.mdb")
Set rst = db.OpenRecordset("Invoices", dbOpenTable)
Do Until rst.EOF
Debug.Print rst(0), rst(1), rst(2), rst(3), rst(4), rst(5)
rst.MoveNext
Loop
End Sub
You can open a recordset on a TableDef, QueryDef or another Recordset.
Listing 7.6
Public Sub TableDefRecordset()
Dim rst As Recordset
Set rst = CurrentDb.TableDefs("Customers").OpenRecordset
Do Until rst.EOF
Debug.Print rst!CustomerID
rst.MoveNext
Loop
End Sub
3
Access Programming Week 7
Programming Exercise
Problem Statement
The problem is to find out when our sales orders reached a certain target, say £1000. Bear in mind that it’s most
unlikely that this was a discrete event; our target will have been exceeded during the course of adding an order to the
system. For example, our grand total may have been £947.35 after order no. 0022, and may be £1072.88 after order no.
0023.
With a difficult problem it’s sensible to divide it into subtasks. Use your judgement to select which task to work on,
write and test your solution. Then proceed to the next subtask, write and then test that. Then you will need to test the
tasks together.
Rather than present the solution in one go and explain it, the following exercises step through some of the thought
processes involved in writing the solution.
First step is to identify or create a data source that will give us the information necessary to achieve our result.
That’s easy enough; we will create a query and get it over and done with. Check the query result, and make a note of the
information, there should be one record for each order. Save the query as qryOrderTotalsByDate, and close it.
Next we need to create a recordset. As we are using a query it could be a dynaset, or it could be a snapshot, or it could be
a forward-only recordset. There’s nothing in the problem statement that says we have to change the data (you can’t edit a
Totals query anyway). Perhaps at this stage we don’t know how we are going to navigate the recordset, so we will leave
the decision about forward-only till later.
Type the following program into the module Week7. The first logical step is to create the recordset.
Listing 7.7 a
Public Sub SalesTarget()
Dim rs As Recordset
Set rs = CurrentDb.QueryDefs("qryOrderTotalsByDate").OpenRecordset
End Sub
To test the recordset you could navigate it from beginning to end using a Do Until loop and print the result to the Immediate
window. The lines for you to add are marked for your convenience.
Listing 7.7 b
Public Sub SalesTarget()
Dim rs As Recordset
Set rs = CurrentDb.QueryDefs("qryOrderTotalsByDate").OpenRecordset

|
|

Do Until rs.EOF
Debug.Print rs(0), rs(1), rs(2)
rs.MoveNext
Loop
End Sub
NB: from now save the module every now and then.
4
Access Programming Week 7
The next logical step is to put in a mechanism in the loop to recognise when our target is achieved, and stop looping.
You have to go back to the problem statement and think what information we need to track. We need to specify our
target, and keep track of the cumulative order total. That implies two variables, marked with *. We can assign the
variables while we are at it.
Listing 7.7 c
*
*
Public Sub SalesTarget()
Dim rs As Recordset
Dim SalesTotal As Single
Dim Target As Single
*
*
Target = 500
SalesTotal = 0
‘we use a small-ish number so it is easier to check
Set rs = CurrentDb.QueryDefs("qryOrderTotalsByDate").OpenRecordset

|
|
|


Do Until rs.EOF
Do While SalesTotal <= Target
SalesTotal = SalesTotal + rs(1)
Debug.Print rs(0), rs(1), rs(2), SalesTotal
rs.MoveNext
Loop
Note there are
now two loops !
‘ Debug.Print rs(0), rs(1), rs(2) ‘comment this line out or delete it
rs.MoveNext
Loop
‘this refers to the outer loop
End Sub
Our tentative solution is to put a Do While loop within the loop that navigates the whole recordset. The conditional clause
for the inner loop is that SalesTotal is less than Target. The next line adds the value of rs(1), which is the amount of the
order, to the variable SalesTotal. Next we put our debug.print statement, so we can check if the previous two lines are
working properly. The MoveNext method moves to the next record, then the Loop statement checks the condition – if
SalesTotal is still less than Target, the program runs through the loop again. If SalesTotal exceeds Target, the flow of control
passes to the outer loop which loops through to rs.EOF
Clear the Immediate window before running the program.
Assuming you haven’t previously tampered with the data, the
result should be as illustrated on the right
What does it mean? It means that the fourth row is the order that
took us past the £500 threshold, and the inner loop baled out as
planned.
5025
5026
5027
5028
79
29.2
280
335
13/05/2001
13/05/2001
13/05/2001
04/06/2001
79
108.2
388.2
723.2
The next logical step is to ‘catch’ the date so that we can satisfy the problem statement. That implies another variable,
which we can call TargetDate. The logic of the problem dictates we should assign to the variable TargetDate the date when
the cumulative value of SalesTotal exceeds the Target threshold. Add the marked lines to your code, and comment out the
debug.print statement from the previous stage.
Listing 7.7 d
*
Public Sub SalesTarget()
Dim rs As Recordset
Dim SalesTotal As Single
Dim Target As Single
Dim TargetDate As Date
Target = 500
SalesTotal = 0
Set rs = CurrentDb.QueryDefs("qryOrderTotalsByDate").OpenRecordset
Do Until rs.EOF
Do While SalesTotal <= Target
SalesTotal = SalesTotal + rs(1)

If SalesTotal >= Target Then
5
Access Programming Week 7
|
|

TargetDate = rs(2)
End If
Debug.Print TargetDate
rs.MoveNext
Loop
rs.MoveNext
Loop
End Sub
Run the code; it’s getting there but it’s not quite right. You should see lines of zeros:
00:00:00
00:00:00
00:00:00
04/06/2001
The reason is that the print statement is outside of the If ..End If block, and
will print something for every pass of the loop, hence the zeros. This is a
very typical hitch you run into when you learn to program.
You can move the debug.print TargetDate statement to just before the End If statement. On the other hand you are on much
safer ground if the print statement is outside of any loops – move it to just before the End Sub statement, and the zeros
should not show.
At this stage you could say that you should succeed. But you must test it for a range of values – suppose the target is a
figure which is not yet met, like £5000. Amend your code so that you assign 5000 to the variable Target, and then run the
program. You get an error because the inner loop has ‘overshot’ the end of the recordset. You must test for EOF within
the loops and bale out if it is encountered. Amend the program as indicated – the main change is that the keyword Exit is
used in two places to jump out of the loop prematurely. Also a boolean variable is declared and used to announce True if
the target is reached and False if not. Run the program
Listing 7.7 e
*
*
Public Sub SalesTarget()
Dim rs As Recordset
Dim SalesTotal As Single
Dim Target As Single
Dim TargetDate As Date
Dim TargetReached As Boolean
TargetReached = False
Target = 5000
SalesTotal = 0
Set rs = CurrentDb.QueryDefs("qryOrderTotalsByDate").OpenRecordset

Do Until rs.EOF
Do While SalesTotal <= Target
If rs.EOF Then Exit Do
SalesTotal = SalesTotal + rs(1)
If SalesTotal >= Target Then
TargetReached = True
TargetDate = rs(2)

End If
rs.MoveNext
Loop



If rs.EOF Then Exit Do
rs.MoveNext
Loop
Debug.Print TargetDate
Debug.Print TargetReached
End Sub
6
Access Programming Week 7
Embedding a long SQL statement in code
The recordset is based on a query; being lazy it’s easier to refer to rs(2) than rs!OrderDate. But what happens if someone
changes the order of the columns? You are on safer ground with exclamation point syntax. But then, what happens if
someone sorts the query on another column? This too will scupper your program.
Your program will be much more secure if the recordset is an SQL statement that you define in the code. Just copy and
paste the SQL from the Access query into a Notepad file. Break it up into manageable chunks, like the following:
SELECT PurchaseItem.OrderNo, Sum([quantity]*[PurchaseItem.UnitPrice])
AS ItemTotal, SalesOrders.OrderDate
FROM SalesOrders INNER JOIN (Products INNER JOIN
PurchaseItem ON Products.ProductID = PurchaseItem.ProductID)
ON SalesOrders.OrderNo = PurchaseItem.OrderNo
GROUP BY PurchaseItem.OrderNo, SalesOrders.OrderDate
ORDER BY SalesOrders.OrderDate ;
Observe Listing 7.2f. Declare the variable where marked with *
Then create the next group of statements as marked, by pasting from your Notepad file a line at a time. Take care to type
a space and the finishing double quote at the end of each line. What is happening is that you are progressively
concatenating each line of the SQL statement to a string variable strSQL, until it contains the whole statement. It’s
cumbersome, but not that complicated! Finally, the statement to create the recordset is much simplified.
Listing 7.7 f
Public Sub SalesTarget()
Dim rs As Recordset
Dim SalesTotal As Single
Dim Target As Single
Dim TargetDate As Date
Dim TargetReached As Boolean
*

|
|
|
|
|

Dim strSQL As String
strSQL = "SELECT PurchaseItem.OrderNo, Sum([quantity]*[PurchaseItem.UnitPrice]) "
strSQL = strSQL & "AS ItemTotal, SalesOrders.OrderDate "
strSQL = strSQL & "FROM SalesOrders INNER JOIN (Products INNER JOIN "
strSQL = strSQL & "PurchaseItem ON Products.ProductID = PurchaseItem.ProductID) "
strSQL = strSQL & "ON SalesOrders.OrderNo = PurchaseItem.OrderNo "
strSQL = strSQL & "GROUP BY PurchaseItem.OrderNo, SalesOrders.OrderDate "
strSQL = strSQL & "ORDER BY SalesOrders.OrderDate ;"
TargetReached = False
Target = 5000
SalesTotal = 0

Set rs = CurrentDb.OpenRecordset(strSQL)
Do Until rs.EOF
Do While SalesTotal <= Target
If rs.EOF Then Exit Do
SalesTotal = SalesTotal + rs(1)
If SalesTotal >= Target Then
TargetReached = True
TargetDate = rs(2)
End If
rs.MoveNext
Loop
If rs.EOF Then Exit Do
rs.MoveNext
Loop
Debug.Print TargetDate
Debug.Print TargetReached
End Sub
7
Access Programming Week 7
Programming Example: The Seek method
contains many example programs which give you a start in using various objects and methods;
this program is adapted from one. You can run these programs against Northwind.mdb, or you can try
to adapt them to your own databases.
Help
Listing 7.8
Sub SeekX()
Dim
Dim
Dim
Dim
Dim
Dim
Dim
db As Database
rstProducts As Recordset
intFirst As Integer
intLast As Integer
strMessage As String
strSeek As String
varBookmark As Variant
Set db = CurrentDb
' You must open a table-type Recordset to use an index, and hence the Seek method.
Set rstProducts = db.OpenRecordset("Products", dbOpenTable)
With rstProducts
' Set the index.
.Index = "PrimaryKey"
' Get the lowest and highest product IDs.
.MoveLast
intLast = !ProductID
.MoveFirst
intFirst = !ProductID
Do While True
' Display current record information and ask user for ID number.
strMessage = "Product ID: " & !ProductID & vbCr & _
"Name: " & !ProductName & vbCr & vbCr & _
"Price: " & Format(!UnitPrice, "£#.00") & vbCr & vbCr & _
"Enter a product ID between " & intFirst & _
" and " & intLast & "."
strSeek = InputBox(strMessage)
If strSeek = "" Then Exit Do
' Store current bookmark in case the Seek fails.
varBookmark = .Bookmark
.Seek "=", Val(strSeek)
' Return to the current record if the Seek fails.
If .NoMatch Then
MsgBox "Product ID not found!"
.Bookmark = varBookmark
End If
Loop
.Close
End With
End Sub
8
Access Programming Week 7
DAO Connectivity
We’ve looked at methods of DoCmd to transfer data; there are also DAO methods. Connections can
be of two types:
connecting to another Jet database or SQL Server
bypassing Jet by using the Connection object.1
The following example connects one Jet database to another. It uses the Connect and
SourceTableName properties of the TableDef object. It doesn’t use the Connection object. Specifically it
puts a link to the Customers table into the file Accounts.mdb. (Just modify pathnames and table names
to reuse the code).
The task of the program is creating a connection string, and assigning it to the Connect property of
the TableDef object. The connection string looks like:
";DATABASE=path to .mdb file"
Listing 7.9
Sub Connect_1()
Dim db As Database
Dim tdf As TableDef
Dim rst As Recordset
Dim strConnect As String
' Open a Microsoft Jet database to which you will link a table.
Set db = OpenDatabase("\\nsq024vs\u8\csathfc\Desktop\Accounts.mdb")
Modify path
' Put connection string in a variable
strConnect = ";DATABASE=\\nsq024vs\u8\csathfc\Desktop\Company2004.mdb"
' Create a new TableDef, set its Connect and SourceTableName properties
Set tdf = db.CreateTableDef("Cust") 'this is the link name
tdf.SourceTableName = "Customers"
'this is the source table
tdf.Connect = strConnect
'append it to the TableDefs collection
db.TableDefs.Append tdf
db.Close
End Sub
You could run this code from any database, not just the database that provides the source table.
As a test, here I run this program from a new database and incorporate User Id and Password
information. I open a database called Madrid.mdb and create a link called ronny to a table named
Ronaldo in a database called Manc.mdb. The user ID is andy and the logon password is niceday.
Listing 7.10
Sub Connect_2()
Dim db As Database
Dim tdf As TableDef
Dim rst As Recordset
Dim strConnect As String
' Open a Microsoft Jet database to which you will link a table.
Set db = OpenDatabase("d:\databases\Madrid.mdb", , , "JetTable;uid=andy;pwd=niceday")
strConnect = ";DATABASE=d:\databases\Manc.mdb"
Set tdf = db.CreateTableDef("ronny")
tdf.SourceTableName = "Ronaldo"
tdf.Connect = strConnect
1
A Connection object represents a connection to an ODBC database (ODBCDirect workspaces only). ODBCDirect workspaces are
not supported in Microsoft Access 2010
9
Access Programming Week 7
db.TableDefs.Append tdf
db.Close
End Sub
Providing password information in the OpenDatabase method:
The Connect argument is expressed in two parts: the database type, followed by a semicolon (;) and
the optional arguments e.g "JetTable;uid=andy;pwd=niceday"
The following example demonstrates a blank password.
Set db = OpenDatabase("D:\Databases\Accounts.mdb", , , "JetTable;uid=andy;pwd=")
Documentation:
Name
Required/Optional
Description
Name
Required
the name of an existing Microsoft Access database file, or the data source name (DSN) of an ODBC data
source. See the Name property for more information about setting this value.
Options
Optional
Sets various options for the database, as specified in Remarks.
ReadOnly
Optional
True if you want to open the database with read-only access, or False (default) if you want to open the
database with read/write access.
Connect
Optional
Specifies various connection information, including passwords.
Using CreateWorkspace method
Here is an alternative procedure to incorporate passwords using the CreateWorkspace method of
DBEngine. A workspace is created on line 8, and the user id and password information are provided in
the CreateWorkspace method. Otherwise the program is the same as previously.
Listing 7.11
Sub Connect_X()
Dim db As Database
Dim tdf As TableDef
Dim rst As Recordset
Dim strConnect As String
Dim wrkJet As Workspace
Set wrkJet = CreateWorkspace("", "andy", "niceday", dbUseJet)
' Open a Microsoft Jet database to which you will link a table.
Set db = wrkJet.OpenDatabase("d:\databases\accounts.mdb")
' put connection string in a variable
strConnect = ";DATABASE=d:\databases\company2004.mdb"
' Create a new TableDef, set its Connect and SourceTableName properties
Set tdf = db.CreateTableDef("tblCustomers")
tdf.SourceTableName = "Customers"
tdf.Connect = strConnect
'append it to the TableDefs collection
db.TableDefs.Append tdf
db.Close
End Sub
10
Access Programming Week 7
Name
Required/Optional
Description
Name
Required
A String that uniquely names the new Workspace object. See the Name property for details on valid
Workspace names.
UserName
Required
A String that identifies the owner of the new Workspace object. See the UserName property for
more information.
Password
Required
A String containing the password for the new Workspace object. The password can be up to 20
characters long and can include any characters except ASCII character 0 (null).
UseType
Optional
One of the WorkspaceTypeEnum values.
Note
ODBCDirect workspaces are not supported in Microsoft Access 2010. Setting the type argument
to dbUseODBC will result in a run-time error. Use ADO if you want to access external data
sources without using the Microsoft Access database engine.
Exercise
Write a program that opens the Accounts database, creates a recordset based on an SQL statement using the Invoices
table and debug prints the ChequeNumber field to the Immediate Window
11
Access Programming Week 7
VBA: Do Loops
If Then statements and Select Case statements are conditional control structures i.e., statements are executed depending
on whether or not one or more conditions are true.
Loops are control structures that are concerned with repetition. Loops also often test a condition to determine whether a
statement should be repeated – how many times does a statement need to be executed? There are two categories of
loops in VBA, Do loops and For loops. Both Do loops and For loops offer variations, giving the programmer strategic
options, but often the same result can be accomplished by using one or other.
There are four varieties of the Do Loop.
Do While . . . Loop
Do . . . Loop While
Do Until . . . Loop
Do . . . Loop Until
To test some of these loops, start a new standard module, and save it as LoopTests
Do While .. Loop
The syntax is:
Do While condition
statement(s)
Loop
Public Sub DWL()
Dim x As Integer
x = 0
Do While x < 5
Debug.Print x
x = x + 1
Loop
End Sub
x < 5 is the condition which evaluates to True
two statements to be executed
The key word Loop returns control to the Do While statement which re-evaluates the condition;
there should be a statement somewhere before the Loop statement which changes the
condition otherwise the loop will run ‘forever’
(Note: Ctrl + Break should terminate most runaway loops; if not Ctl Alt + Delete and end Access - and lose unsaved work!)
The key characteristic of the Do While Loop is that, depending on circumstances, it may never execute the statements at all.
For instance, change the above code by assigning the value 5 to the variable x, and run the code again – nothing prints. If
the condition evaluates to False, program execution jumps to the statement after Loop – which in this case is the End Sub
statement.
Do .. Loop While
The syntax is:
Do
statement(s)
Loop While condition
Public Sub DLW()
Dim x As Integer
x = 0
Do
Debug.Print x
x = x + 1
Loop While x < 5
there is no condition at this stage so the statements to be executed happen at least once.
The Loop Statement returns control to the Do statement only if the condition evaluates to true.
End Sub
12
Access Programming Week 7
Using Do Loop While is guaranteed to execute the statements at least once. To illustrate, assign 6 to the variable x
immediately before the Do statement. The sequence of events is as follows:
6 is printed
x is incremented by one, therefore equals 7
Loop While tests the condition, which evaluates to False
Program execution continues to the statement after Loop While, which happens to be End Sub
The Do While… Loop is generally very useful – many programming tasks can be handled that way
Do Until . . Loop and Do . . Loop Until
These can be used in ways which are functionally equivalent to the While loops above. If you replace Do While by Do
Until the condition is initially False and the statements are repeated until the condition is True. In our example you have
to change the direction of the comparison operator to get the equivalent result.
Public Sub DUL()
Dim x As Integer
x = 0
Do Until x > 5
Debug.Print x
x = x + 1
Loop
End Sub
Public Sub DLU()
Dim x As Integer
x = 0
Do
Debug.Print x
x = x + 1
Loop Until x > 5
End Sub
In these examples we are controlling how many times a loop executes but in general Do Loops are used when you need
a statement to be repeated an unspecified number of times.
The Do Until loop is the standard way to loop through recordsets. In general programming, using Until can occasionally
seem unintuitive. For example consider the following:
Public Sub DUL()
Dim x As Integer
x = 0
Do Until x < 5
Debug.Print x
x = x + 1
Loop
End Sub
The statements in the loop are never executed because the condition is
already True.
Points to Note:



Loops can contain control statements such as If Then or other loops
If statements can contain loops
You can break out of a loop if necessary by using the Exit Do keywords
13
Access Programming Week 7
Suggested solution to exercise
Sub
Dim
Dim
Dim
Dim
myConnect()
stSQL As String
db As Database
rs As Recordset
dbname As String
dbname = "C:\Users\andy\Desktop\Accounts.mdb"
Set db = Workspaces(0).OpenDatabase(dbname)
stSQL = "SELECT ChequeNumber FROM Invoices"
Set rs = db.OpenRecordset(stSQL, dbOpenDynaset)
Do While Not rs.EOF
Debug.Print rs!ChequeNumber
rs.MoveNext
Loop
rs.Close
End Sub
READING
http://oreilly.com/catalog/progacdao/chapter/ch08.html
Sample chapter from
DAO Object Model: The Definitive Reference By Helen Feddema
14