DAO Exercises with Answers

DAO Recordsets Create a Recordset of the type Snapshot based on the Employees table that debug prints the LastName field and the RecordCount

Sub EmpSnapshot() Dim rs As DAO.Recordset Set rs = CurrentDb.OpenRecordset("Employees", dbOpenSnapshot) Do While Not rs.EOF Debug.Print rs!LastName rs.MoveNext Loop Debug.Print "No of records in " & rs.Name & " is " & rs.RecordCount End Sub

Create a Recordset of the type based on an SQL statement that debug prints the LastName field from the Employees table with an Ascending sort order and the RecordCount

Sub EmpSql() Dim strsql As String Dim rs As DAO.Recordset strsql = "SELECT LastName FROM Employees ORDER BY LastName" Set rs = CurrentDb.OpenRecordset(strsql) Do While Not rs.EOF Debug.Print rs!LastName rs.MoveNext Loop Debug.Print "No of records in " & rs.Name & " is " & rs.RecordCount End Sub

Write a DAO recordset to Excel Write a sub that creates a new Excel file, and writes a recordset based on the Customers table to cell B1 and saves the file as Customers.xlsx

Sub CustsToExcel_Simple() 'minimal version, unreliable Dim rs As DAO.Recordset Set rs = CurrentDb.OpenRecordset("Customers", dbOpenForwardOnly) Dim xlAp As New Excel.Application xlAp.Workbooks.Add xlAp.Visible = True Cells(2, 1).CopyFromRecordset rs Set rs = Nothing Set xlAp = Nothing End Sub better version: Sub CustsToExcelAndSave() ' uses variables for excel objects so ' must have a reference to Microsoft Excel Object model Dim xlAp As New Excel.Application Dim wb As Excel.Workbook ' you won't be able to save without a workbook variable Dim ws As Excel.worksheet Set wb = xlAp.Workbooks.Add Set ws = wb.Worksheets(1) xlAp.Visible = True Dim rs As DAO.Recordset Set rs = CurrentDb.OpenRecordset("Customers", dbOpenTable) ws.Cells(2, 1).CopyFromRecordset rs wb.SaveAs myPath1 & "Customers.xlsx" 'xlap.Quit Set rs = Nothing Set xlAp = Nothing End Sub Create a DAO recordset from an Excel program (You can only do this to mdb files. You would have to use ADO for accdb files, I will provide ADO revision later) Start a new Excel file, and add a reference to Microsoft DAO 3.6 Object Library Write a program that imports a recordset file based on the Customers table

Private Sub getDatafromMdb() ' Run this code from Excel Dim db As DAO.Database Dim rs As DAO.Recordset Dim fld As DAO.Field

Dim x As Integer Dim wks As Worksheet Dim r As Range Dim response As Integer

Set db = OpenDatabase("C:\Users\andy\Desktop\Company2014.mdb") Set rs = db.OpenRecordset("Customers", dbOpenSnapshot)

Set wks = Worksheets.Add response = MsgBox("Are you sure?", vbYesNo + vbQuestion)

Select Case response Case vbYes Set r = wks.Cells(4, 1) On Error Resume Next

x = 1 For Each fld In rs.Fields wks.Cells(4, x).Value = fld.Name x = x + 1 Next

Set r = wks.Cells(5, 1) r.CopyFromRecordset rs wks.Columns.AutoFit

Case vbNo GoTo CleanUp End Select

CleanUp: Set wks = Nothing: Set r = Nothing rs.Close Set fld = Nothing: Set rs = Nothing db.Close Set db = Nothing End Sub

Create a DAO recordset in another database In Company2014 write a sub that checks whether the number of records in the SalesOrders table is the same as the number of records in the Invoices table in Accounts.accdb. Create two recordsets, one for SalesOrders, and one for Invoices. (You will need to use OpenDatabase to open Accounts)

Sub CompareRecordsets() Dim db As DAO.Database Dim rs As DAO.Recordset Dim rsOther As DAO.Recordset

Set rs = CurrentDb.OpenRecordset("SalesOrders") Debug.Print rs.RecordCount & " rows in this db" Set db = OpenDatabase(myPath1 & "Accounts.accdb") Set rsOther = db.OpenRecordset("Invoices") Debug.Print rsOther.RecordCount & " rows in other db" rs.Close: rsOther.Close: db.Close End Sub Bookmarks Write a sub named HighestPay. The program is to loop through a recordset based on the Employees table and bookmark the record with the highest PayRate. After the loop has stopped your code should return to the bookmark variable, thus making it the current record. All that is required is a debug.print statement, just before the End Sub, that outputs the FirstName, LastName and PayRate of the employee. You can assume that only one record has the highest value of PayRate in the table. ub HighPay() 'DAO version Dim rstEmployees As DAO.Recordset Dim HighestSoFar As Double Dim bk As Variant

Set rstEmployees = CurrentDb.OpenRecordset("Employees", dbOpenSnapshot)

With rstEmployees .MoveLast .MoveFirst HighestSoFar = !PayRate 'store pay rate of current record bk = .Bookmark 'store the bookmark of the current record

Do While Not .EOF 'check if the current record's pay rate is > highest pay rate so far If !PayRate > HighestSoFar Then HighestSoFar = !PayRate 'store pay rate of current record bk = .Bookmark 'store the bookmark of the current record End If .MoveNext Loop

.Bookmark = bk 'go to the record indicated by the stored bookmark Debug.Print !FirstName & " " & !LastName & " earns £" & !PayRate & " per hour" .Close End With

End Sub

SQL Recordset Write a program that debug prints the FirstName, LastName and highest PayRate, this time using a recordset based on an SQL statement. No need for a loop or bookmarks. Revise the SQL2 notes on how to write a subquery. Sub highestpaySQL() Dim strsql As String strsql = "SELECT FirstName, LastName, PayRate FROM Employees " strsql = strsql & "WHERE PayRate In " strsql = strsql & "(SELECT Max(PayRate) FROM Employees);" Set rs = CurrentDb.OpenRecordset(strsql) Debug.Print rs!FirstName, rs!LastName, rs!PayRate End Sub

Create an expression Put an unbound text box on a form, and write an expression for its Control Source that displays the Highest Pay from the Employees table. Use a Domain Aggregate function (Part 4 notes, Appendix). Note that you can’t obtain the LastName.

=DMax("PayRate","Employees")

Form Recordset Put a button on the Employees form. Write a program for its Click event which will find the highest PayRate and make that record the current record. Revise 5.3 for how to use the RecordsetClone property and 7.7c for how to use an If statement inside a loop. Advice: save your work each time before you run the code, I had several ‘Not Responding’ episodes.

Private Sub cmdHighest_Click() Dim HighestSoFar As Single Dim rst As Recordset Dim mark As String

Set rst = Me.RecordsetClone 'start at beginning of clone rst.MoveFirst

HighestSoFar = 0 'not strictly necessary Do Until rst.EOF ' loop through the clone, if payrate > variable ' assign it to the variable and set bookmark If rst!PayRate > HighestSoFar Then HighestSoFar = rst!PayRate mark = rst.Bookmark Debug.Print HighestSoFar End If rst.MoveNext Loop ' finally synchronise current record in form to bookmark in clone Me.Bookmark = mark End Sub

Navigate a DAO recordset and find three consecutively increasing values in a numeric field Keeping track of consecutive records isn’t something SQL can do easily so you would employ a recordset program. You can use the table imported from Sales.xlsx. Find three consecutively increasing values of the field Net, bookmark the record that was the first of the sequence, and debug print the record number, the date, and percentage increase. (Advice: manually edit the table so three increasing values of the field Net appear sooner rather than later and step through your code while observing the table)

Sub ThreeRises() Dim val1 As Single, val2 As Single, val3 As Single 'three variables to store three consecutive values Dim bk As Variant

Dim rst As DAO.Recordset Set rst = CurrentDb.OpenRecordset("xlsales", dbOpenSnapshot) With rst 'using With makes program less readable but should run faster .MoveLast .MoveFirst val1 = !net 'store value of field of first record bk = .Bookmark 'store the bookmark of the first record .MoveNext

Do While Not .EOF 'check if the current record's value is > than previous If !net > val1 Then val2 = !net 'store net of current record in second variable and move on .MoveNext

If !net > val2 Then 'testing for third value val3 = !net .Move -2 bk = .Bookmark 'store the bookmark of the current record Exit Do Else val2 = 0 'third field wasn't higher, reset second variable val1 = !net 'start again, store field in first variable End If

Else 'second value wasn't higher val1 = !net 'start again, store field in first variable .MoveNext End If Loop .Bookmark = bk 'go to the record indicated by the stored bookmark Debug.Print val3 & " found which is a " & ((val3 - val1) / val1) * 100 & _ "% increase over record number " & .AbsolutePosition + 1 & " on " & !Date .Close End With End Sub

An application of this idea would be to track movements in share prices in a large table. For more sophisticated ideas like bookmarking the largest of consecutive increases, you would need to create an array of variants to store multiple bookmarks and the values. That would involve many hours learning array basics so I wouldn’t prioritise it if I were a relative newcomer to programming.

ForEach loops Look at week 9 for examples. a)Write a program that debug prints all the table names in the current database, the date created and the date last updated

Sub ShowTables() Dim db As DAO.Database Dim tdf As TableDef Set db = CurrentDb For Each tdf In db.TableDefs Debug.Print tdf.Name, tdf.DateCreated, tdf.LastUpdated Next End Sub the output contains a lot of unwanted items, so, b)modify the program to exclude system tables and any garbage from deleted tables.

Sub ShowTables2() Dim db As DAO.Database Dim tdf As TableDef Set db = CurrentDb For Each tdf In db.TableDefs If Not tdf.Name Like "msys*" And Not tdf.Name Like "~TMP*" Then Debug.Print tdf.Name, tdf.DateCreated, tdf.LastUpdated End If Next End Sub c) As above but connect to another database

Sub ShowTablesOtherDB() Dim db As DAO.Database Dim tdf As TableDef Set db = OpenDatabase(myPath1 & "Accounts.accdb") For Each tdf In db.TableDefs If Not tdf.Name Like "msys*" And Not tdf.Name Like "~TMP*" Then Debug.Print tdf.Name, tdf.LastUpdated End If Next End Sub d)Write a program that debug prints names of any tables updated within the last month (the LastUpdated property refers to changes in the design)

Sub ShowTables3() Dim db As DAO.Database Dim tdf As TableDef Set db = CurrentDb Debug.Print vbTab & vbTab & vbTab & vbTab & "Date Created" & vbTab & vbTab & _ vbTab & "Last Updated" Debug.Print "======" For Each tdf In db.TableDefs If tdf.LastUpdated >= #4-April-2016# And Not tdf.Name Like "msys*" _ And Not tdf.Name Like "~TMP*" Then Debug.Print tdf.Name, tdf.DateCreated, tdf.LastUpdated End If Next End Sub

On reflection, it’s easier to do it this way than use Containers