|
Domain Aggregate Functions |
|
Fundamentals of Aggregate Functions
|
|
|
Microsoft Access is a relational database application
with a high level of support for the SQL. Still, besides the operations
available in SQL, Microsoft Access has its own implementation of the
language. It does this by adding various types of functions. One category of
these functions is used to supplement the operations of data analysis. That
is, instead of using a WHERE condition, you can use a special
function that tremendously simplifies your work. The functions in this case
are applied to a series (also called a set) of records and the produce a
particular result. Because these functions act on a series of records, they
are called domain aggregate functions.
|
Practical
Learning: Introducing Domain Aggregate Functions
|
|
- Open the KoloBank1 database from
Lesson 17
- In the Navigation Pane, right-click NewTimeSheet and click Design
View
Using a Domain
Aggregate Function
|
|
A domain aggregate function has the following syntax:
DFunctionName(Expression, Domain, [Criteria])
DFunctionName is the name of the function. The
Expression argument can be the name of a column on which the
function will act. It can also be a calculation-based expression. The
Domain argument can be the name of a table or that of a query that
doesn't require an external value.
The Criteria argument is optional. If passed,
it can specify the condition used to select a specific record. It acts as
a WHERE condition. Therefore, a domain aggregate function resembles
the function formula of a SQL statement:
SELECT Expression FROM Domain WHERE Criteria
As mentioned already, Expression is usually the
name if a column whose values would be considered. Domain can be
the name of a table or query. The Criteria should be formulated as
if it was following a WHERE operator.
The Categories of Aggregate Functions
|
|
Looking up a value in a table or query consists of
visiting each one of the values of a certain field and finding out which
one of those values matches the target. The aggregate function used to
perform this operation is named DLookup. The DLookup()
function can be used to find one or more records that respond to a
criterion from another table or query.
As mentioned already, you can call this function
without passing the third argument which sets the condition. If you omit
that argument, all records from the Domain would come in the
result. This would be equivalent to a simple SELECT statement that
doesn't have a condition.
To apply a condition, pass the third argument. Here is
an example:
Private Sub cmdFindByItemNumber_Click()
ItemName = DLookup("ItemName", "StoreItems", "ItemNumber = " & txtItemNumber)
End Sub
Practical
Learning: Looking for a Record in a Domain
|
|
- On the form, double-click the Employee Number text box
- In the Properties window, click Event and double-click On Lost
Focus
- Click its ellipsis button
- Implement the event as follows:
Private Sub txtEmployeeNumber_LostFocus()
On Error GoTo txtEmployeeNumber_Error
' Access the Employees table
' Locate an employee who uses the number entered by the user
If Not IsNull(DLookup("EmployeeNumber", "Employees", _
"EmployeeNumber = '" & txtEmployeeNumber & "'")) Then
' If you find it, retrieve the corresponding name
' (last name and first name)
' and display the full name
txtEmployeeName = DLookup("LastName", "Employees", _
"EmployeeNumber = '" & _
txtEmployeeNumber & "'") & _
", " & _
DLookup("FirstName", "Employees", _
"EmployeeNumber = '" & _
txtEmployeeNumber & "'")
Else
' If you didn't find any employee with that number,
' reset the current record
cmdReset_Click
End If
txtEmployeeNumber_Exit:
Exit Sub
txtEmployeeNumber_Error:
If Err.Number = -2147352567 Then
Resume txtEmployeeNumber_Exit
Else
MsgBox "An error occured when retrieving the employee information" & vbCrLf & _
"Please call the program vendor and report the error as follows:" & vbCrLf & _
"Error #: " & Err.Number & vbCrLf & _
"Reason: " & Err.Description
Resume Next
End If
End Sub
- Close Microsoft Visual Basic and return to Microsoft Access
- Close the form
- When asked whether you want to save it, click Yes
- In the Navigation Pane, right-click TimeSheets and click Design
View
- On the form, click the employee name text box (the text box on the
right side of the Employee # text box)
- In the Properties window, click Control Source and type:
=IIf(IsNull([EmployeeNumber]),"",DLookUp("LastName","Employees","EmployeeNumber = '" & [EmployeeNumber] & "'") & ", " & DLookUp("FirstName","Employees","EmployeeNumber = '" & [EmployeeNumber] & "'"))
- Close the form
- When asked whether you want to save it, click Yes
- Open the WattsALoan1 database from Lesson 17
- In the Navigation pane, right-click the LoansAllocations form and
click Design View
- On the form, double-click the text box on the right side of the
EmployeeNumber text box
- In the Properties window, click Control Source and type:
=IIf(IsNull([EmployeeNumber]),"",DLookUp("LastName","Employees","EmployeeNumber
= '" & [EmployeeNumber] & "'") & ", " &
DLookUp("FirstName","Employees","EmployeeNumber = '" &
[EmployeeNumber] & "'"))
- On the form, click the text box on the right side of the Account #
text box
- In the Properties window, click Control Source and type:
=IIf(IsNull([AccountNumber]),"",DLookUp("LastName","Customers","AccountNumber
= '" & [AccountNumber] & "'") & ", " &
DLookUp("FirstName","Customers","AccountNumber = '" & [AccountNumber]
& "'"))
- Change the design of the form as follows:
- Close the form
- When asked whether you want to save, click Yes
- In the Navigation Pane, double-click the Customers form
- Create accounts
for a few customers
- Close the form
- In the Navigation Pane, right-click the Payments form and click
Deisgn View
- Click the text box on the right side of the EmployeeNumber text
box
- Click Control Source and type:
=IIf(IsNull([EmployeeNumber]),"",DLookUp("LastName","Employees","EmployeeNumber
= '" & [EmployeeNumber] & "'") & ", " &
DLookUp("FirstName","Employees","EmployeeNumber = '" &
[EmployeeNumber] & "'"))
- On the form, click the button on the right side of the LoanNumber
text box
- In the Properties window, click Control Source and type:
=IIf(IsNull([LoanNumber]),"",DLookUp("Customer","LoansCustomers","LoanNumber
= " & [LoanNumber]))
The First/Last of a Series
|
|
If you have a series of values that respond to a
common criterion, to get the first value of that series, you can call the
DFirst domain aggregate function. In the same way, to get the last
value in the series, call the DLast function. If there is only one
value in the group, both functions return the same value.
Practical
Learning: Finding the Last Value of a Series
|
|
- In the Controls section of the Ribbon, click the Button
and click the form.
If the wizard starts, cancel it
- Using the Properties window, change the button's characteristics
as follows:
Name: cmdGetCurrentBalance Caption:
Get Current Balance Visible: No
- Complete the design of the form as follows:
- On the form, click the LoanNumber text box
- In the Properties window, click Event and double-click On Lost
Focus
- Click the ellipsis button
to launch Microsoft Visual Basic
- Change the file as follows:
Option Compare Database
Option Explicit
' This global variable is used to hold the previous balance of the loans payments
Private CurrentBalance As Double
Private Sub LoanNumber_LostFocus()
' Make sure the user had entered a loan number.
' Based on the loan number, get the monthly payment the customer is supposed to pay.
' Show that value in the Payment Amount text box
If Not IsNull([LoanNumber]) Then
PaymentAmount = CDbl(DLookup("MonthlyPayment", "LoansAllocations", "LoanNumber = " & CLng(LoanNumber)))
End If
' Check the table of payments.
' If the loan number entered here does not have a balance in the Payments table,
' that is, if there is no previous balance of the currrent loan number,
' this means that this is probably the first payment of the loan.
If IsNull(DLookup("Balance", "Payments", "LoanNumber = " & CLng(LoanNumber))) Then
' If this is the first payment of the loan, get the Future Value
' in the Loans Allocations table for this loan number.
' Store (or reserve) that value in the global CurrentBalance variable
CurrentBalance = CDbl(DLookup("FutureValue", "LoansAllocations", "LoanNumber = " & CLng(LoanNumber)))
Else
' If there is at least one balance amount in the Payments table for this loan number,
' get that balance and store it in the global CurrentBalance variable
CurrentBalance = CDbl(DLast("Balance", "Payments", "LoanNumber = " & CLng(LoanNumber)))
End If
' Show the (previous) balance in the Balance text box
Balance = CurrentBalance
End Sub
- In the Object combo box, select cmdGetCurrentBalance
- Implement the Click event as follows:
Private Sub cmdGetCurrentBalance_Click()
MsgBox "The previous balance was " & CStr(CurrentBalance)
Balance = CurrentBalance - CDbl(PaymentAmount)
MsgBox "The new balance is " & CStr(Balance)
End Sub
- In the Object combo box, select Form
- In the Procedure combo box, select Current
- Implement the OnCurrent event as follows:
Private Sub Form_Current()
' To make sure the user doesn't accidentally click the button,
' show the Get Current Balance button only if this is a new payment
If IsNull(ReceiptNumber) Then
cmdGetCurrentBalance.Visible = True
Else
cmdGetCurrentBalance.Visible = False
End If
End Sub
- Return to Microsoft Access
- Close the form
- When asked whether you want to save it, click Yes
- From the resources that accompany these lessons, open the CeilInn1
database
- In the Navigation Pane, right-click the Payments table and click
Design View
- Change the table as follows to add New Columns:
Field Name |
Data Type |
Caption |
Field Size |
Format |
Input Mask |
ReceiptNumber |
|
|
|
|
|
EmployeeNumber |
|
|
|
|
|
PaymentDate |
|
|
|
|
|
AccountNumber |
Text |
Processed For |
20 |
|
|
FirstDateOccupied |
Date/Time |
First Day Occupied |
|
Long Date |
99/99/0000;0;_ |
LastDateOccupied |
Date/Time |
Last Day Occupied |
|
Long Date |
99/99/0000;0;_ |
TotalDays |
Number |
Total Days |
Integer |
|
|
AmountCharged |
|
|
|
|
|
TaxRate |
|
|
|
|
|
Notes |
Memo |
|
|
|
|
- Save and close the table
- In the Navigation Pane, right-click the Payments form and click
Design View
- Change its design as follows (we list only the three new text
boxes you should add to the form):
|
Control |
Name |
Caption |
Control Source |
Label |
|
|
Room Occupied From: |
|
Text Box |
|
FirstDateOccupied |
|
FirstDateOccupied |
Label |
|
|
To: |
|
Text Box |
|
LastDateOccupied |
|
LastDateOccupied |
Label |
|
|
Total Days/Nights: |
|
Text Box |
|
TotalDays |
|
TotalDays |
|
- Save the form
- On the form, click the AccountNumber text box
- In the Properties window, click Event and double-click On Lost
Focus
- Click its ellipsis button and implement the event as follows:
Private Sub AccountNumber_LostFocus()
On Error GoTo AccountNumber_LostFocusError
' If the customer account number was not entered, don't do anything
If IsNull([AccountNumber]) Then
Exit Sub
Else
' Get the first date registered with the customer's account number in the Occupancies table
FirstDateOccupied = DFirst("DateOccupied", "Occupancies", "AccountNumber = '" & [AccountNumber] & "'")
' Get the last date the customer used the room
LastDateOccupied = DLast("DateOccupied", "Occupancies", "AccountNumber = '" & [AccountNumber] & "'")
End If
Exit Sub
AccountNumber_LostFocusError:
MsgBox "There was an error resulting from" & vbCrLf & _
"Error #: " & Err.Number & vbCrLf & _
"Description: " & Err.Description
End Sub
- Return to Microsoft Access
- Switch the Payments form to Form View
- Select the value in the Customer Acnt # text box, delete it, and
re-type it as 100752
- Press Tab and notice the date in the From text box
- Return to Microsoft Visual Basic
The Minimum/Maximum of Values
|
|
The DFirst (DLast) function is used to
get the first (last) of a series values of any types, including string. If
the values are number-based or date/time type, to find the lowest value in
the series, which may not be the first, you can call the DMin
function. In the same way, to get the highest numeric value or the latest
occurring date, you can call the DMax function. Once again, if
there is only one value in the group, both functions return the same
value.
Probably the most fundamental numeric information you
may want to know about a series is the number of records it contains. This
information can be provided by an aggregate function named DCount.
When calling this function, the first argument should always be the name
of a column. Here is an example:
=DCount("Title","Videos")
This code returns the total number of videos that have
a value in the Title column. The DCount() function doesn't count
the records where the Expression value is NULL. As mentioned in the
syntax of the domain aggregate functions, you can use a criterion to
select specific records. Here is an example:
=DCount("Title","Videos","Rating = 'R'")
In this case, the function will return the number of
videos that are rated R from our table.
Practical
Learning: Getting the Number of Records
|
|
- Change the code as follows:
Private Sub AccountNumber_LostFocus()
On Error GoTo AccountNumber_LostFocusError
' If the customer account number was not entered, don't do anything
If IsNull([AccountNumber]) Then
Exit Sub
Else
' Get the first date registered with the customer's account number in the Occupancies table
FirstDateOccupied = DFirst("DateOccupied", "Occupancies", "AccountNumber = '" & [AccountNumber] & "'")
' Get the last date the customer used the room
LastDateOccupied = DLast("DateOccupied", "Occupancies", "AccountNumber = '" & [AccountNumber] & "'")
' Based on the customer account, get the number of days or nights the customer rented the room
TotalDays = DCount("RateApplied", "Occupancies", "AccountNumber = '" & [AccountNumber] & "'")
End If
Exit Sub
AccountNumber_LostFocusError:
MsgBox "There was an error resulting from" & vbCrLf & _
"Error #: " & Err.Number & vbCrLf & _
"Description: " & Err.Description
End Sub
- Return to Microsoft Access
- Switch the Payments form to Form View
- Select the value in the Customer Acnt # text box, delete it, and
re-type it as 100752
- Press Tab
- Return to Microsoft Visual Basic
The DSum() function
can calculate the total of (numeric) values of a column in a table (or
query). Here is an example that will return the amount we spent buying the
videos stored in a table:
=DSum("PriceBought","Videos")
|
|