Microsoft Access VBA Tutorials for self-paced learning, Class Modules, SQL Techniques, and AI Integration Guides.

Showing posts with label Accesstips. Show all posts
Showing posts with label Accesstips. Show all posts

Opening Access Objects from Desktop

Opening Access Objects from the Desktop.

  1. Set the Form Name in the Display Form Option of the current database in Access Options.

    BIG DEAL! This is the first trick any novice learns when he/she starts learning Microsoft Access.

  2. Create an AutoExec macro with the FormOpen action and the required Form Name in the Property.
  3. The above method opens the form when the database is launched.

Opening a Form Directly, without any Changes to the Database.

We would like to launch a specific Form tomorrow to continue updating data in that form, without making any changes in the database.

If you would like to print a particular Report, first thing in the morning without fail, then here is a simple trick.

Note: Your Database's Navigation Pane must be accessible.

  1. Open the Database.

  2. Click the Restore Window Control Button to reduce the Application Window size, so that the empty area of the Desktop is visible.

  3. Click and hold the Mouse Button on the Form Name in the Navigation Pane, then drag the form to the desktop and drop it there.

  4. Close the Database.

  5. Double-Click on the Desktop-Shortcut. The Form will open when the Database is open.

    You can open the following Objects directly with Desktop-Shortcuts:

Try it out yourself.

  1. MS-Access Class Module and VBA
  2. MS-Access and Collection Object Basics
  3. Dictionary Objects Basics
  4. Withevents and All Form Control Types
Share:

Add Class Objects as Dictionary Items

Add Class Objects as Dictionary Items.

We have learned the fundamentals of the Dictionary Object, experimented with sorting simple items, and displayed Access table records on an MS Access Form from the Dictionary Object.

Now, let us move a step further to learn how to add MS Access Class Objects to a Dictionary, retrieve each object item, and display their Property values and Method outputs in the Debug Window.

If you would like to revisit the earlier related articles for reference, their links are provided below.

We need to have the ClsArea class object in the database to try out this example using the Dictionary object.

If it is not already present, you can create it by following these steps:

  1. Open the VBA Editor.

  2. Insert a new Class Module.

  3. In the Properties Window, change the (Name) property of the new class to ClsArea.

  4. Copy and paste the following VBA code into the ClsArea class module and save it.

Option Compare Database
Option Explicit

Private p_Desc As String
Private p_Length As Double
Private p_Width As Double

Public Property Get strDesc() As String
  strDesc = p_Desc 'copy the value from p_Desc
End Property

Public Property Let strDesc(ByVal strNewValue As String)
  p_Desc = strNewValue
End Property

Public Property Get dblLength() As Variant
  dblLength = p_Length
End Property

Public Property Let dblLength(ByVal dblNewValue As Variant)
    Do While Val(Nz(dblNewValue, 0)) <= 0
      dblNewValue = InputBox("Negative/0 Values Invalid:", "dblLength()", 0)
    Loop
  p_Length = dblNewValue
End Property

Public Property Get dblWidth() As Variant
  dblWidth = p_Width
End Property

Public Property Let dblWidth(ByVal dblNewValue As Variant)
    Do While Val(Nz(dblNewValue, 0)) <= 0
      dblNewValue = InputBox("Negative/0 Values Invalid:", "dblwidth()", 0)
    Loop
  p_Width = dblNewValue
End Property

Public Function Area() As Double
  If (Me.dblLength > 0) And (Me.dblWidth > 0) Then
     Area = Me.dblLength * Me.dblWidth
  Else
     Area = 0
     MsgBox "Error: Length/Width Value(s) Invalid., Program aborted."
  End If
End Function

Private Sub Class_Initialize()
    p_Length = 0
    p_Width = 0
    'MsgBox "Initialize.", vbInformation, "Class_Initialize()"
End Sub

Private Sub Class_Terminate()
   'MsgBox "Terminate.", vbInformation, "Class_Terminate()"
End Sub

The ClsArea Class object has three properties — strDesc, dblLength, and dblWidth — and one method: Area().

We will create multiple instances of this class to represent different rectangular shapes or rooms, and calculate their areas using the Area() method, and add each class object instance as an Item in a Dictionary object.

The value stored in the class object's strDesc property will be used as the Key for each corresponding item in the dictionary.

Since dictionary keys must be unique, make sure that the strDesc property values are not duplicated.

For example, if you have several bedrooms to calculate areas for, you can name them Bedroom1, Bedroom2, Bedroom3, and so on.

The ClassObjInDictionary() Procedure Code.

Let us try the Dictionary with the Class Module Object ClsArea as Items. The sample VBA Code for the Dictionary Object is given below.  Copy and paste it into a Standard Module and save the Module.

Public Sub ClassObjInDictionary()
'--------------------------------------------------
'Add Class Object as Items to Dictionary Object
'Retrieve the Class Object from Dictionary Object
'and Print the values in the Debug Window.
'--------------------------------------------------
Dim C As ClsArea
Dim D As Object, Desc As String, mKey

Set D = CreateObject("Scripting.Dictionary")
D.CompareMode = 1
Desc = ""

Do While Not Desc = "Q"
'instantiate Class Object
Set C = New ClsArea
    
    'Get input Values for ClsArea Object\
    Do While Len(Desc) = 0
      Desc = InputBox("Description or Q=Quit:")
    Loop
       If Desc = "Q" Then Exit Do
       
    C.strDesc = Desc
    C.dblLength = CDbl(InputBox("Length of " & UCase(Desc) & ": "))
    C.dblWidth = CDbl(InputBox("Width of " & UCase(Desc) & ": "))
    
'add to Dictionary
'Description is added as Key of Dictionary Object
    D.Add Desc, C
    Desc = ""
'Clear Class Object
    Set C = Nothing
Loop


If D.Count = 0 Then
  MsgBox "No Data in Dictionary Object!" & vbCr & "Program Aborted."
  Exit Sub
End If

'Output Section
Debug.Print "Key Value", "Description", "Length", "Width", "Area"

For Each mKey In D.keys
        Set C = D(mKey)
        Debug.Print mKey, C.strDesc, C.dblLength, C.dblWidth, C.Area
Next

End Sub

The VBA Code Line by Line.

At the beginning of the code, we create and instantiate the Dictionary object D.

We use the Desc string variable to capture the description text that will be assigned to the strDesc property of the class object. This same variable also acts as the control for the Do While ... Loop.

The loop continues to run until the user enters the single character Q (for Quit) into the Desc variable.

This trial allows you to add any number of class object instances into the Dictionary. When you are done, simply enter Q in the description prompt to exit the loop.

Next, we create an instance of the ClsArea class object using the object variable C.

Inside this loop, the statement Desc = InputBox() is placed within a second Do While ... loop. This ensures that the user actually enters a value into the Desc variable.

If the user presses Enter, clicks OK, or Cancel without entering any text, the InputBox() function will repeat the prompt until a valid value is entered.

The valid Description Value is assigned to the C.strDesc Property of the Class Object.

Through the next two InputBox() functions, collect the Length and width values of the Room from the user and assign them to C.dblLength and C.dblWidth Properties, respectively. 

Now, the ClsArea Class Object is ready to be added to the Dictionary Object.

The statement D.Add Desc, C adds the current instance of the ClsArea Class Object in the Dictionary Object as its first Item to Desc (or C.strDesc Property Value) as the Key of the Dictionary Item.

Next, we clear the ClsArea Class Object instance C from memory.

You might have noticed that the Class Object instance C is created at the beginning of the outer Do While ... Loop, fills up the Class Object Property Values, adds it to the Dictionary Object, and C is Set to Nothing as the last statement within the Loop. 

The Class Object C is a temporary Object that captures the data entry values before transferring the valid data into the Dictionary Object. Class Object C is reset to Nothing so it can be reinitialized for another Entry. That means we are creating a New Class Object instance for each Item in the Dictionary Object.

Why it has to be this way- creating new instances of the Class Object for each Item- is an important point to keep in mind.

The Class Object instance is added as an Item to the Dictionary; internally, the Class Object’s Location Address is saved in the Dictionary Object as a Pointer.  The actual Class Object Property values are not moved to the Dictionary Object Item. 

When we execute the statement Set C = Nothing, the Class Object instance C is cleared, but the instance’s location reference (pointer) is saved in the Dictionary Object Item.  The actual ClsArea Class Object remains in that location, and we can retrieve it using the Object Pointer saved in the Dictionary Object Item.

When a new Class Object Instance is created, it is stored in a new memory location, and its reference is added to the Dictionary Object.

Enter a Description for a few bedrooms, Length, and Width Values to test the Code. Enter the letter Q to Quit and complete the Data entry when you are ready to take a listing in the Debug Window.

A sample Listing is given below:

Key Value     Description   Length        Width         Area
Bed Room1     Bed Room1      14            15            210 
Bed Room2     Bed Room2      12            12            144 
Living Room   Living Room    23            24            552 
Kitchen       Kitchen        11            11            121 
Store Room    Store Room     21            14            294 

In the printing code segment, we did not create a new  ClsArea object (C) instance to read the class object pointers stored in the dictionary items. Instead, we directly accessed the stored object references from the dictionary and printed their values in the Debug Window.

Note: If you feel more comfortable doing so, you may create an ClsArea object instance (C) and assign the stored dictionary item reference to it. Both approaches work equally well.

The statement

Set C = D(mKey)

reads the object reference (pointer) of the ClsArea object from the dictionary item into C. Once assigned, you can retrieve its property values and method output and print them to the Debug Window.

If you have already run the sample code and understood how it works, try a small modification:

  • Move the object creation and object cleanup (removal) statements for the ClsArea object outside the Do While...Loop.

  • Then, rerun the code, add a few items to the dictionary, and print their property values to verify the output in the Debug Window.

Take a Trial Run With the Following Changes in the Code

The Do While ... loop segment with suggested changes is below.  Check the highlighted statements above and below the Do While ... Loop.

Desc = ""
Set C = New ClsArea

Do While Not Desc = "Q"
'instantiate Class Object
    
    'Get input Values for ClsArea Object
    Do While Len(Desc) = 0
      Desc = InputBox("Description or Q=Quit:")
    Loop
       If Desc = "Q" Then Exit Do
       
    C.strDesc = Desc
    C.dblLength = CDbl(InputBox("Length of " & UCase(Desc) & ": "))
    C.dblWidth = CDbl(InputBox("Width of " & UCase(Desc) & ": "))
    
'add to Dictionary
'Description is added as Key of Dictionary Object
    D.Add Desc, C
    Desc = ""
'Clear Class Object
Loop
    Set C = Nothing

I moved the statement Set C = New ClsArea to a position above the Do While...Loop, and placed the Set C = Nothing statement below the Loop so that it executes only after completing the data entry of Class Objects into the Dictionary within the Do While...Loop.

I entered all five sample items listed earlier, using the same names but different values for Length and Width.

Finally, the printing section listed all five items in the Debug Window.
However, instead of showing the individual values entered for each item, only the last item's values are printed for all five entries.

Key Value     Description   Length        Width         Area
Bed Room1     Store Room     12            13            156 
Bed Room2     Store Room     12            13            156 
Living Room   Store Room     12            13            156 
Kitchen       Store Room     12            13            156 
Store Room    Store Room     12            13            156 


Why has it happened this way?

When we add a Class Object with its Properties to a Dictionary Object, only the reference (memory address) of the Class Object is stored in the Dictionary Item—not its actual Property values.

When an instance of the Class Object is created using the New keyword, that instance is assigned a fixed memory location (address). Any new values entered into its Properties will overwrite the previous values stored in that same instance. Each time this same object reference is added to the Dictionary, the Dictionary stores only the address of the Class Object, not a copy of its current Property values.

By contrast, if we create a new instance of the Class Object during each loop cycle, a fresh object is created, with a different memory address. The Dictionary stores these unique addresses, allowing each Item to retain its own distinct Property values.

When the statement Set C = Nothing is executed, it simply clears the reference from the object variable C so it no longer points to any location. However, the actual object data remains alive in memory because the Dictionary still holds a reference to it.

But when we moved the Set C = New ClsArea and Set C = Nothing statements outside the Do While...Loop, we ended up using only a single instance of the Class Object to input multiple sets of values. Each new set of Property values overwrote the previous ones in that same object. As a result, all the Dictionary Items ended up pointing to a single object instance, which holds only the last set of values entered.

Therefore, during printing, even though the Keys appear correctly in the listing, all the Items show the same (last entered) Property values.

Next week, we will learn how to add, edit, update, and delete Class Objects in the Dictionary through an MS Access Form.

MS-ACCESS CLASS MODULE

  1. MS Access Class Module and VBA
  2. MS Access VBA Class Object Arrays
  3. MS Access Base Class and Derived Objects
  4. VBA Base Class and Derived Objects-2
  5. Base Class and Derived Object Variants
  6. MS Access Recordset and Class Module
  7. Access Class Module and Wrapper Classes

    COLLECTION OBJECT

  8. MS Access and Collection Object Basics
  9. MS Access Class Module and Collection Object
  10. Table Records in Collection Object and Form

    DICTIONARY OBJECT

  11. Dictionary Object Basics
  12. Dictionary Object Basics-2
  13. Sorting Dictionary Object Keys and Items
  14. Display Records from Dictionary to Form
  15. Add Class Objects as Dictionary Items
  16. Update Class Object Dictionary Item on Form

Share:

Ms-Access and Collection Object Basics

Collection Object Basics.

A Collection object is a built-in VBA object that provides a convenient way to store and manage a group of related objects or values as a single unit. It is available in all Microsoft Office applications that support VBA, including Microsoft Access, Excel, Word, Outlook, and PowerPoint.

Unlike an array, a Collection is dynamic, meaning items can be added or removed at runtime without resizing the collection. Each item in the Collection is automatically assigned a numeric index, and it may also be assigned a unique string key for direct data retrieval.

Key Characteristics

  • Dynamic storage – Items can be added or removed at any time during program execution.

  • Ordered collection – Items are maintained in the order in which they are added unless inserted at a specific position.

  • Heterogeneous contents – A Collection can contain objects, variables, or values of different data types.

  • Indexed access – Items can be accessed by their numeric position (1-based indexing).

  • Key-based access – Items may optionally be assigned unique string keys for faster identification.

  • Automatic memory management – VBA manages the internal storage of Collection, eliminating the need for manual resizing.

Typical Uses

The Collection object is widely used to:

  • Store instances of custom class objects.
  • Maintain lists of Forms or Controls.
  • Organize records or business objects in memory.
  • Build reusable object frameworks.
  • Manage wrapper class instances in Microsoft Access applications.
  • Replace dynamically resized arrays where frequent additions or deletions are required.

In VBA, Arrays are more commonly used than Collection objects for storing multiple sets of related values (in rows and columns). We have already used Arrays to store User-Defined Types and Class Module objects. Now, it’s time to explore something new—the use of Collection and Dictionary objects. The Collection object is particularly convenient for grouping related items together. As for the Dictionary object, we will discuss its usage at the appropriate time.

When using Arrays, we must dimension a variable, User-Defined Type, or Class Module object with the required number of elements in advance—or re-dimension it later to increase or decrease its size—before storing values in it. This extra step is not necessary with a Collection object. Once a Collection object is instantiated, we can dynamically add any number of items to it. Its members can be of any data type, including built-in objects, Class Module objects, or even other Collection objects with their own item members.

Collection Object Demo Program.

Let us write a simple program to demonstrate the usage of a Collection Object.

Public Sub CollTest1()
Dim C As Collection
Dim j As Integer

‘instantiate the Object
Set C = New Collection
                            
C.Add 5
C.Add 15
C.Add "iPhone"
C.Add "Disk 2TB"
C.Add 35.75

'Print the items in debug window
GoSub Listing

C.Remove 3 'Remove 3rd item

GoSub Listing

Set C = Nothing

Exit Sub

Listing:
Debug.Print
For j = 1 To C.Count
    Debug.Print C.Item(j)
Next
Return

End Sub

Code Review Line By Line.

The first two lines declare the Variable C as a Collection Object. The next line declares the Variable j as an Integer type, as a control variable for the For... Next Loop.  The third line instantiates the Collection Object C in memory.

The Collection Object has four built-in methods: Add, Count, Item, and Remove, for managing the Collection items in memory.

The Collection Object Instance image given below displays its list of methods.

  • The Add method adds a new Item to the Collection.  The Remove method removes an item by its numeric index or key.

  • To access a specific item, we can use the Item method with its index number. The Count property returns the total number of items in the Collection.

  • In the current example, we are not working with object-type items but with a few simple mixed data types—Integer, String, and Double—as members of the Collection. Using the Add method of the Collection object named C, we have inserted five items: the first two are integers, the next two are strings, and the last one is a double-precision number.

  • The syntax: C.Add (Item, [Key], [Before], [After])  The Add method is followed by a space, and then the actual value to be added. Other parameters are optional.

  • The Add method accepts four optional parameters, as shown in the image below.

  • The parameters are: Item, [Key], [Before], [After].  The first parameter, Item, is mandatory; the Value to be added to the Collection.

  • The next three parameters are optional. 

  • When using any of the optional parameters of the Add method, you must insert comma placeholders to skip over unused parameters—except when you are specifying parameters from the rightmost side in order.

    Alternatively, you can explicitly use parameter names with their values, which allows you to provide the parameters in any order.

    We will explore this technique in another VBA example.

    Note: Do not misinterpret the Item Parameter of the Add Method with the Item() Method of the Collection Object.

  • We have added five items as Collection Object members with the Add method.  Two integer-type values, two String-type Values, and one double-precision number. 

    It demonstrates that you can add any data type, except User-Defined Types (UDTs), into the Collection.  When you want to add UDTs into a Collection, convert your UDTs into a Class Module Object.

    Next, the program calls a printing subroutine that outputs the Collection members to the Debug window. This subroutine uses a For...Next loop that runs from 1 to the total number of items (C.Count) in the Collection. The loop control variable j is used as the index parameter of the Collection’s Item() method to retrieve each value and print it to the Debug window.

    The next Line removes the third item (iPhone) from the item members by calling the Remove method.

    The printing subroutine is called again to print the list of items after removing the third item from the earlier list.

    The Exit Sub statement prevents the program control from dropping into the internal subroutine lines and stops the program.  The listing will appear in the Debug Window as shown below.

    The Output in the Debug Window.

    5 
    15 
    iPhone
    Disk 2TB
    35.75
    
    5 
    15 
    Disk 2TB
    35.75
    

    We can insert a value before a particular item member by specifying the item number with the Before key Name.

    C.Add 2, Before:=1 ‘add value 2 Before existing first item 
    

    OR

    C.Add 2,,1

    The above statement will add value 2 as the first item in the above program, pushing all existing items down.

    C.Add 20, After:=3 ‘Add value 20 After existing item number 3
    

    OR

    C.Add 20,,,3

    This statement inserts the value 20 after the third item, after value 15,  in the list.

    The Code below demonstrates the Before:= and After:= Parameter Names.

    Public Sub CollTest2()
    Dim C As Collection
    Dim j As Integer
    
    Set C = New Collection
    
    C.Add 5
    C.Add 15
    C.Add "iPhone"
    C.Add "Disk 2TB"
    C.Add 35.75
    
    GoSub Listing
    
    C.Add 2, Before:=1 'Insert the item before the first item
    C.Add 20, After:=3 'Insert the item after first 3 items
    
    GoSub Listing
    
    Set C = Nothing
    Exit Sub
    
    Listing:
    'Print the items
    Debug.Print
    For j = 1 To C.Count
       Debug.Print C(j)
    
    Next
    Return
    
    End Sub
    

    Note: By using parameter names, you can pass values in any order you want when you need to use more than one parameter in a statement.

    C.Add After:=3,Item:=20

    The second example demonstrates parameter use without explicitly specifying their parameter names, placing each value in its defined correct positional order.

    Public Sub CollTest2_2()
    Dim C As Collection
    Dim k As Integer
    

    Set C = New Collection C.Add 5 C.Add 15 C.Add "iPhone" C.Add "Disk 2TB" C.Add 35.75 GoSub Listing C.Add 2, , 1 'Insert the item before the first item C.Add 20, , , 3 'Insert the item after first 3 items GoSub Listing Set C = Nothing Exit Sub Listing: 'Print the items Debug.Print      For k = 1 To C.Count          Debug.Print C(k)      Next: Debug.Print Return End Sub

    Sample printout in the Debug Window is shown below:

    5 
     15 
    iPhone
    Disk 2TB
     35.75 
    
     2 
     5 
     15 
     20 
    iPhone
    Disk 2TB
     35.75 
    

    In all our printing examples, we have used the Item’s index number to retrieve values for display in the Debug Window. However, when a collection contains many items, it becomes difficult to remember the index number of a specific item we want to access. To overcome this, we can associate each item with an easily memorable Key along with its Value—for example, using a contact’s first name as the Key in an address book Collection—so we can retrieve the item’s value directly by its Key instead of relying on its index number.

    Usage of Item Keys.

    Let’s write a new program to demonstrate how to use Keys with Values in a Collection.

    Public Sub CollTest3()
    Dim C As Collection
    Dim strKey As String
    Dim strGet As String
    
    Set C = New Collection
    
    C.Add 5, Key:="FIVE" 
    C.Add 15, Key:="FIFTEEN"
    C.Add "iPhone", "7+"     'you can omit the KEY param name
    C.Add "Disk 2TB", "DISK" ' Add method's 2nd Parameter is KEY
    C.Add 35.75, "999"
    
    'add value 2 with Key "TWO" before the first item.
    'this item will be the first item in the collection
    'parameter names not in proper order – valid
    
    C.Add Item:=2, Before:=1, Key:="TWO"
    
    'add value 7 with Key "SEVEN" as third item in the collection
    'parameter names not in proper order – valid
    
    C.Add Key:="SEVEN", Item:=7, After:=2
    
    'Retrieve value using it's KEY from collection
    
    strKey = ""
    Do While strKey = ""
        strKey = InputBox("Value Key: " & vbCr & vbCr & "Q - Quit", "Enter Key", "")
        
        Select Case strKey
            Case "Q"
               Exit Do
            Case "TWO", "FIVE", "SEVEN", "FIFTEEN", "7+", "DISK", "999"
               strGet = C(strKey)
            Case Else
               strGet = " Not Found!"
       End Select
       
    MsgBox "Key:<<" & strKey & ">> Value: " & strGet
    strKey = ""
    Loop
    
    Set C = Nothing
    
    End Sub
    

    The KEY value must be of String Type.  The KEY value must be a unique identifier.

    Refer to the second image on this page to view the Add method of the Collection Object and the proper order of Parameters, displayed by the VBA IntelliSense.

    The sample programs shown earlier, with mixed data types, were intended solely for demonstration purposes. In practical use, a Collection object typically stores items of a single data type, most commonly used to hold objects—such as Forms, Reports, Class Module objects, or Database objects—along with their associated properties and methods.

    CLASS MODULES.

    1. MS-Access Class Module and VBA
    2. MS-Access VBA Class Object Arrays
    3. MS-Access Base Class and Derived Objects
    4. VBA Base Class and Derived Objects-2
    5. Base Class and Derived Object Variants
    6. MS-Access Recordset and Class Module
    7. Access Class Module and Wrapper Classes
    8. Wrapper Class Functionality Transformation

    COLLECTION OBJECT.

    1. MS-Access and Collection Object Basics
    2. MS-Access Class Module and Collection Object
    3. Table Records in Collection Object and Form

    DICTIONARY OBJECT.

    1. Dictionary Object Basics
    2. Dictionary Object Basics-2
    3. Sorting Dictionary Object Keys and Items
    4. Display Records from Dictionary to Form
    5. Add Class Objects as Dictionary Items
    6. Update Class Object Dictionary Item on Form
Share:

User Defined Data Type-2

User-Defined Data Type 2.

This is the second post on User-Defined Data Types (UDTs).

You can find the link to the first post on this topic [here].

The need for User-Defined Data Types arose when we used two-dimensional arrays of the Variant data type to store different types of values (such as String, Integer, and Double) in each array element. The Variant data type can automatically adjust its type depending on the value assigned to it.

Instead of using a single Variant variable with a multi-dimensional array, we could also use several separate single-dimensional variables of different data types. For most simple data-processing tasks, these approaches are more than sufficient.

However, learning new techniques is always exciting in programming.

The User-Defined Data Type is one such interesting feature in VBA, and in this post, we will explore how to create and use it in our programs.

How to Define a User-Defined Data Type

The steps go something like this:

  1. You can define a new data type that combines multiple built-in variable types—such as Integer, Long, Double, and String—into a single structure. This User-Defined Data Type (UDT) must be declared within a Type ... End Type block at the module level, typically at the beginning of a Standard Module, before any procedures.

  2. The following example defines a UDT named myRecord with two elements: RecordID (of type Long) and Description (of type String):

    Public Type myRecord
    
    RecID as Long
    Description as String
    
    End Type
    

    By default, a User-Defined Type (UDT) has Public scope, though explicitly declaring it as Public or Private is optional. If declared as Private, the UDT is accessible only in the same module where it is defined. In that case, variables such as Dim AbcRec As myRecord can be declared and used only inside that module.

    When declared with the default Public scope, the UDT becomes available to all modules within the current project, and even to other projects that reference this database.

    Let’s begin with a simple example:

    Type Sales
        Desc As String
        Quantity As Long
        UnitPrice As Double
        TotalPrice As Double
    End Type
    

    The Data Type name is Sales.

    As you can see in the Sales data type, we have used built-in data Types String, Long Integer, and Double for different data elements.

    Using the User-Defined variable in the program starts with dimensioning a Variable of Type Sales, like any other variable.   

    Public Function typeTest()
    Dim mySales As Sales
    
       mySales.Desc = "iPhone 8 Plus"
       mySales.Quantity = 1
       mySales.UnitPrice = 75000#
       mySales.TotalPrice = mySales.Quantity * mySales.UnitPrice
    
    Debug.Print mySales.Desc, mySales.Quantity, mySales.UnitPrice, mySales.TotalPrice
    
    End Function
     

    Result printed in the Debug Window:

    iPhone 8 Plus  1             75000         75000 
    

    Unlike built-in variables, the elements of a User-Defined Type are always accessed by specifying the Type name, followed by a dot, and then the element name (for example: mySales.Desc). In this way, the Desc, Quantity, UnitPrice, and TotalPrice elements are treated as individual properties of mySales.

    To make the code cleaner and more flexible, we can place these element references inside a With… End With structure. This allows us to enter data directly from the keyboard into each element of the Sales record using the InputBox() function.


Public Function typeTest()
Dim mySales As Sales

With mySales
   .Desc = InputBox("Item Description: ")
   .Quantity = InputBox("Item Quantity: ")
   .UnitPrice = InputBox("Item Unit Price: ")
   .TotalPrice = .Quantity * .UnitPrice
End With

'Print the values on Debug Window
With mySales
  Debug.Print .Desc, .Quantity, .UnitPrice, .TotalPrice
End With
End Function

The modified code will retrieve information from a single Record and print it out on the Debug Window.  Before running the Code, open the Debug Window (Ctrl+G) to view the output.

Arrays of User-Defined Type

Next, we will define an array of mySales variables to store information for five different items. We will then pass this array of user-defined variables—each containing multiple data elements—to the SalesPrint() function as a parameter. The SalesPrint() function will calculate and update the TotalPrice element for each item before printing the array values in the Debug Window.
(Keep the Debug Window open while running the program.)

The sample VBA code for this program is given below:

Public Function SalesRecord()
Dim mySales(5) As Sales
Dim j As Integer, strLabel As String

For j = 0 To UBound(mySales) - 1
    strLabel = "(" & j + 1 & ") "
    With mySales(j)
       .Desc = InputBox(strLabel & "Item Description:")
       .Quantity = InputBox(strLabel & "Quantity:")
       .UnitPrice = InputBox(strLabel & "UnitPrice:")
       .TotalPrice = 0
    End With
Next

Call SalesPrint(mySales())

End Function

Check the Dim statement—it works like any other array definition. We also declare two additional variables: j and strLabel. The variable j serves as the control variable in the For…Next loop, while strLabel is used to construct and store a label such as (1), (2), etc., which appears in the InputBox() prompt. This label helps identify the current record number as we enter data into each record.

We have chosen meaningful names for the array elements—Desc, Quantity, and UnitPrice—instead of using array indexes such as Sales(0,0) for Description or Sales(0,1) for Quantity. The 'MySales(j).TotalPrice' element is initially assigned 0; its value will be calculated and updated in the SalesPrint() function. The array is passed to SalesPrint() as a ByRef parameter.

The SalesPrint() Function.

The SalesPrint() function Code is given below:

Public Function SalesPrint(ByRef PSales() As Sales) Dim j As Integer, strLabel As String Debug.Print "Description", " ", "Quantity", "UnitPrice", "Total Price" For j = 0 To UBound(PSales) - 1 strLabel = "(" & j + 1 & ") " With PSales(j)

'calculate TotalPrice

.TotalPrice = .Quantity * .UnitPrice 'print the values in debug window Debug.Print strLabel & .Desc, " ", .Quantity, .UnitPrice, .TotalPrice End With Next End Function

The SalesPrint() function receives the Sales Record array by reference through the PSales variable. Within the function, two local variables are defined: j as an Integer and strLabel as a String. The function begins by printing a record field column heading line in the debug window.

When printing the data, commas are used to separate each item, placing them in 14-column zones on the same line. To allow the Item Description to occupy more space, an empty string is inserted as the second item on the print line. This effectively moves the Quantity value to the 28th column while keeping the layout neat and aligned.

Next, the For... Next loop is used to access each record in memory, with the control variable j serving as the array index. The loop runs from 0 to 4, processing all five records.

The first line inside the loop constructs a label in the format (1), (2), and so on, to indicate the sequence of records as they were entered using the InputBox() function.

The next statement uses a With... End With structure on the PSales(j) record. This allows direct access to its elements (Desc, Quantity, etc.) without repeatedly referencing the top-level array name.

Within the With block, the TotalPrice element is calculated and assigned its value. The following line then prints the current record to the Debug Window. This process repeats for each record, ultimately displaying all items in the array.

By now, you should have a good understanding of the usefulness of User-Defined Types. With a little further exploration, you can even save these records from memory into an Access table.

Keep in mind that a User-Defined Type is usually designed for a specific task, and its structure may not be suitable for general-purpose use like built-in variables. For example, elements such as Desc, Quantity, UnitPrice, and so on, may not be relevant outside the context for which the type was created.

There are, however, many interesting ways to leverage User-Defined Types, and we will continue this discussion in next week’s post.

Share:

Dots and Exclamation Marks Usage with Objects in VBA3

The Final Post and Continued from Last Week's Post.

In Microsoft Access, application objects such as Tables, Queries, Forms, Text Boxes, Labels, and others should be given meaningful names when created. If we don’t, Access assigns default names similar to Form1, Form2, Text1, Label1, and so on. These defaults provide no real indication of what the object represents. Assigning descriptive names related to their purpose makes it much easier to recognize and remember them later—especially when they are used in calculations, VBA code, or other references.

For example, in VBA, we can directly reference a control like this:

Forms!Employees!Salary

instead of the longer form:

Forms("Employees").Controls("Salary").Value

Last week, we began with a simple example that showed how the exclamation mark (!) symbol can shorten object references compared to using multiple dot separators. Once the form name and control name are known, the expression becomes more concise with the '!' symbol.

This shorthand also applies to Recordset fields. For instance:

rset!LastName

is equivalent to:

rset.Fields("LastName").Value

and both return the contents of the field’s default Value property.

If you are a new visitor to this page and topic, then please visit the earlier two pages and continue from here. The links are given below:

Referencing Form's Controls.

I will repeat the first example here to go further into this discussion.

? Forms!frmMain!frmSubForm.Form!frmInsideSubForm.Form!Text7
'
'The above command without the use of the ! Symbol, you must write it in the following manner to get the same result.
'
? Forms("frmMain").Controls("frmSubForm").Form.Controls("frmInsideSubForm").Form.Text7.value

Note: When it frmSubForm is placed as a subform within frmMain It becomes a control on the main form. Like any other control, it has its own set of properties and contains its own controls. If you generate a list of the controls on the main form, the subform will appear in that list just like a textbox, button, or label.

To see this in action:

  1. Open a form that contains a subform.

  2. In the Debug Window, type the following command on a single line (adjusting the form name as needed), then press Enter to display the list of control names of the main form:

For Each ctl In Forms!frmMain.Controls: Debug.Print ctl.Name: Next

This will print the names of all controls on the main form, including the subform control itself.

for j=0 to forms!frmMain.controls.Count-1:? j, forms!frmMain.controls(j).name:next
'Result of the above command, on my Form.
'
 0            Label0
 1            Text1
 2            Label2
 3            Text3
 4            Label4
 5            frmSubForm
 6            Label5

The frmSubForm is listed as a Control of the frmMain with index number 5

Now, about the example given at the beginning, we have three open Forms: frmMain, frmSubForm & frmInsideSubForm, layered one inside the other. We are trying to print the Text7 Text Box from the innermost form in the debug window.  Look at the command given below:

? Forms!frmMain!frmSubForm.Form!frmInsideSubForm.Form!Text7
The actual Text7 TextBox addresses are joined with the symbol!, except for the '.Form' after the names frmSubForm and frmInsideSubForm. This command will work without the '.Form' part. Try the command given below.

? Forms!frmMain!frmSubForm!frmInsideSubForm!Text7

If the address works without the'.Form' part, why do we need it in the address, and what does it mean? It works without an explicit reference because the system knows that it is a Sub-Form control by default.

When you drag and drop a Sub-Form onto the Main Form, Microsoft Access creates a container control on the main form and inserts the Sub-Form into it. To be more specific, if you select the outer edge of the subform control, you can select this container control. Display its Property Sheet(F4) and check the Source Object Property setting. You can see that the subform's name is inserted there. This is the control where we set the Link Master Fields and Link Child Fields properties to set the relationship between data on the master form and subform.

You can rewrite this property value with any other form's name to load it. When you do that, consider the relationship change if the new form's source data is not related.

Coming back to the point, i.e., what does the '.Form' part in the address above mean? It means that the Sub-Form Control created by Access is a container control for loading a Form into it, and it will always be a form control, whether you explicitly add the '.Form' part in the address or not.

Loading a Table or Query in a Sub-Form Control.

But the interesting part is that you can insert a Table or a Query (not an Action Query) into this control.

Try that: if you have a Form with a sub-form, open it in design view.

  1. Click on the outer edge of the Sub-Form to select the Sub-Form control.

  2. Display the Property Sheet (F4) and select the Source Object Property.

  3. Click on the drop-down control to the right of the property to display the available forms, Tables, and Queries.

    At the top of the list, you will see all Forms. These are followed by the list of Tables, and then the list of Queries. Tables are displayed in the format:

    Table.TableName

    and queries appear in the format:

    Query.QueryName

    This notation indicates the category of object that can be assigned to the Source Object property of the subform control.

  4. Select a Table or Query to insert into the Source Object Property of the Sub-Form control.

  5. Save the Form and open it in Form View.

  6. You will find the Table or Query result displayed in the Sub-Form control.

  7. Try to print the value of one of the fields displayed in the debug window.

    Tip: It will print the value of the active record in the sub-form, if selected; otherwise, the first record field value.

Is this the command you have typed in the Debug Window?

? Forms!frmMain!frmSubForm.Table!LastName

Then you are wrong; it is not a Table Control; it is a Form control. When you set the Source Object Property Value to a Table's name, the system adds the category name to the object's name (Table.TableName or Query.QueryName) to identify what type of object is loaded into the sub-form control.

So the correct command is:

? Forms!frmMain!frmSubForm.Form!LastName
'
'OR
'
? Forms!frmMain!frmSubForm!LastName
Share:

Dots and Exclamation Marks Usage with Objects in VBA2

Dots and Exclamation Marks Usage with Objects in VBA2. Last Week's Topic

Last week, we learned a few examples of using the dot (.) separator and the bang (!) symbol with loaded Form and Report objects in memory. In this article, we’ll continue exploring the topic further.

If you haven’t read the earlier article yet, I recommend visiting that page first before proceeding here: [Dots and Exclamation Marks Usage with Objects in VBA].

After working through the previous examples, you might be a little uncertain about which syntax is easiest to use, since we experimented with different ways of referencing forms and controls in VBA. For now, let’s set that aside and approach things from a different angle.

In this section, we’ll focus specifically on the dot (.) separator as it applies to built-in library objects. Unlike with forms and controls, the bang (!) symbol is not valid for referencing these objects. You’ll also see a visual hierarchy of some of the library objects, along with examples of how to access their properties or call their methods directly from the Debug Window.

Object Library View.


Tools --> Options --> Editor --> AutoList Members.

  1. Open your Access Database.

  2. Open the VBA Editing Window (Alt+F11).

  3. Open the Debug Window (Ctrl+G).

  4. Display the Object Browser Window(F2).

    • Select Options from the Tools Menu.

    • On the Editor Tab, select the Auto List Members item if it is not already selected.

  5. Select Access from the <All Libraries> Control's drop-down list.

  6. Move the Classes scrollbar down, find the item named CurrentProject, and select it.

    Check the right-side window listing of  CurrentProject’s Properties and Methods.

  7. If the Object Browser Window is small, then drag the right and bottom edges to make it large enough to display all the Properties and Methods of the CurrentProject Object in the right-side window.

  8. Click and hold the Title area of the Object Browser window, and drag it to the right if it overlaps the Debug Window area.

When you select a Class Object or Public Constant definition from the Classes Window (left panel), the object members are displayed in the right-side window.

Let us display information stored in some of these objects, see how we can address object properties/methods, and the order in which we specify them.

We will display the full PathName (.FullName property value) of the active database with the following command, by typing it in the Debug Window and pressing the Enter Key:

? Access.CurrentProject.FullName
'Result: G:\New folder\pwtracker.accdb

The '.FullName' Property Value of the CurrentProject Object, from the Access Library of Objects, is displayed.  When you open a database from a particular location, the FullName Property value is assigned the full Pathname of the Database.  We have joined the object elements in the correct sequence, joined by dots to specify the FullName property at the end. The Name property will display the database name.

Let us see how many Forms we have in our database by reading the Count Property Value of the AllForms Object.

? Access.CurrentProject.AllForms.Count
'Result: 75 – There are 75 user created Forms in my active database.
'
? Access.CurrentProject.AllForms.item(50).Name
'Result: frmEmployees 
'
'The 50th index numbered item (i.e. 51st item)in my database is frmEmployees. 
'This Form is not opened in memory, but it is taken from the Database’s .AllForms Collection. 
'
? Access.CurrentProject.BaseConnectionString
'
'Result: PROVIDER=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=G:\New folder\pwtracker.accdb;PERSIST SECURITY INFO=FALSE;Jet OLEDB:System database=G:\mdbs\BACAUDIT_1.MDW
'

In the above examples, the CurrentProject object's Property Values are assigned in the System. We have used the Forms Collection Object to address the open forms in memory in last week's examples.

Note: You may explore some of the other objects yourself.

From the above few examples, you can see that we have used the dot separator Character only to join each object/property. You cannot use the (!) symbol to address predefined objects, methods, or properties.

When we reference a User-Defined object (it should have a name), we can use the (!) symbol followed by the object/control Name to access that Control's default Property values or other controls/properties, eliminating the lengthy syntax. To make this point very clear, we will try one simple example below.

The TempVars Object.

  1. Scroll down to the bottom of the Classes Window.

  2. Select the TempVars Class Object. You can see its Methods (.Add(), .Remove() & .RemoveAll()) and Properties in the right-side window.

  3. Above the TempVars Class, you can see another object named TempVar Class. Click on that and check the right-side window. You will find only two properties: Name & Value.

  4. Type the next line of code in the Debug Window and press Enter.

TempVars.Add "website", "MsAccessTips.com"

We have called the Add() method of the TempVars Collection Object to instantiate the TempVar Class and assigned the Name property: website, and the Value: MsAccessTips.com. The new TempVar variable website is added to the TempVars Collection at index 0 because this is the first TempVar variable we have defined in memory so far.

The TempVar data type is a Variant Type, i.e., whatever data type (Integer, Single, Double, Date, String, etc.) you assign to it, it will automatically adjust to that data type.

We can print the website Variable content in two different ways.  The first method uses dot separators; the second uses the (!) symbol.

'1st method
? TempVars.item(0).value ' without the .value part also works, .value is default
'Result: MsAccessTips.com
'OR
? TempVars.item("website").value
'Result: MsAccessTips.com
'
'OR
X="website"
? TempVars.item(X).value
'Result: MsAccessTips.com
'

'2nd method
'the above lengthy syntax can be shortened
'with ! symbol and the user-defined name:website
'point to note:after ! symbol Name property value should follow.
? TempVars!website
'Result: MsAccessTips.com
'
'next command removes the website variable from memory.
TempVars.Remove "website"
'
'the .RemoveAll method clears all the user-defined Temporary Variables from memory.
'TempVars.RemoveAll

The TempVars Variables are Global in nature, which means you can call this variable (Tempvars!website) in Queries, text boxes (=TempVars!website) on Forms or on Reports, and in expressions like: ="Website Name is: " & TempVars!website. If the Value property is assigned numerical values (like the Exchange Rates), it can be used in Calculations.

Tip: Try defining a few more TempVar variables, assigning different data types: Integer, Double, Date, etc., with appropriate Name Property Values.

The Tempvar variable named website is our own creation and is in memory.  Objects (Form/Report) should be loaded into memory with their controls (Textbox, Combobox, Labels, Sub-Form/Sub-Report, and so on) to address them using the bang (!) symbol followed by the control name.

We have used the item collection object in the first three examples.  This is used immediately after the TempVars Collection Object.  When we address text boxes, labels, and other controls on an open Form or Report, we must use the keyword Controls.

You may explore other objects by selecting them in the left-side panel and inspecting their properties, Methods, and Events when you are in doubt about something.

The Data Access Object (DAO).

Tables & Queries are part of the DAO library. You may select DAO in the Object Browser control and explore DAO-related Classes, their Properties, and Methods.

Assume that you are now comfortable with the period (.) and bang (!) symbols in object references. We will explore a few more aspects in the next session before we conclude the discussion on this topic.

Share:

Combining Active and Backup Database Records in Union Query

Combining Active and Backup Database Records in a Union Query.

Microsoft Access database has a maximum size limit of 2GB. To maintain performance and avoid reaching this limit, older records (such as previous year’s transactions) can be safely archived into a backup database for future reference. Once these records are backed up, they can be deleted from the active database. Run the Compact & Repair Utility to optimize performance for day-to-day operations.

However, there are situations where older data is required for analysis—for example, preparing budgets, setting sales targets, or comparing trends.  In such cases, we may need to reintegrate archived records with the current master table in the active database to perform meaningful analysis.

The Union Query Solution.

We can merge records from both the active Table and backup table (with the same name) in a Union Query.

A simple example is given below:

SELECT Export.* 
FROM Export
UNION ALL SELECT Export.*
FROM Export IN 'G:\NEW FOLDER\DB1.MDB';

In the example above, you can see that the names of the tables exported to the active database and the backup database(DB1.MDB) are the same. No need to link the table to the active database to get data from the backup database.

Share:

ROUNDUP Function of Excel in Ms-Access

ROUNDUP Function in Excel and MS Access. 

Microsoft Access doesn't have this function built in. An attempt to write the code for this function; use it at your own risk. Before going into the code, take a look at the usage examples of this function in Excel.

ROUNDUP() function in Microsoft Excel.

The Rules.

Rounds a number up, away from 0 (zero).

Syntax: ROUNDUP(number, num_digits). A number is any real number that you want rounded up.

Num_digits is the number of digits you want to round the number to.

Remarks: ROUNDUP behaves like ROUND, except it always rounds a number up.

If num_digits is greater than 0 (zero), then the number is rounded up to the specified number of decimal places.

If num_digits is 0, then the number is rounded up to the nearest integer.

If num_digits is less than 0, then the number is rounded up to the left of the decimal point.

Examples: 

=ROUNDUP(3.2,0) Rounds 3.2 up to zero decimal places (4)

=ROUNDUP(76.9,0) Rounds 76.9 up to zero decimal places (77)

=ROUNDUP(3.14159, 3) Rounds 3.14159 up to three decimal places (3.142)

=ROUNDUP(-3.14159, 1) Rounds -3.14159 up to one decimal place (-3.2)

=ROUNDUP(31415.92654, -2) Rounds 31415.92654 up to 2 decimal places to the left of the decimal (31500)

Courtesy: Microsoft Excel Help Documents.

Copy and paste the following VBA Code into a Standard Module of your Database and try it out. The examples given above have successfully passed testing code.

The ROUNDUP() Function.

Public Function ROUNDUP(ByVal dblNum As Double, ByVal intprecision As Integer) As Double
'-------------------------------------------------
'ROUNDUP() Function of Excel Redefined in MS-Access
'Author: apr pillai
'Date  : June 2016
'Rights: All Rights Reserved by www.msaccesstips.com
'-------------------------------------------------
On Error GoTo ROUNDUP_Err
Dim sign As Integer
    sign = Sgn(dblNum)
    dblNum = Abs(dblNum)
    dblNum = dblNum * 10 ^ intprecision
ROUNDUP = (Int(dblNum + (1 - IIf((dblNum - Int(dblNum)) <> 0, (dblNum - Int(dblNum)), 1))) / 10 ^ intprecision) * sign

ROUNDUP_Exit:
Exit Function

ROUNDUP_Err:
MsgBox Err & ": " & Err.Description, , "ROUNDUP()"
Resume ROUNDUP_Exit
End Function

Suggestions for improvement of the above VBA Code are welcome.

Share:

DIR TREE DOS COMMANDS

Dir Tree DOS Commands.

The Dir Command, originally part of the Disk Operating System, is also available in Microsoft Access VBA. While it is commonly used to check the location of files or folders on a disk, you can also use it to generate a complete listing of all folders and files, along with their full pathnames. For example, you can retrieve paths in the format 'C:\Folder\Subfolder\Subfolder\... or C:\Folder\Subfolder\FileName'. Such a listing is useful for reviewing disk usage, organizing files, or maintaining records for future reference.

In 1996–97, during our organization’s migration from Novell NetWare to a Windows NT System, all user departments were instructed to review their server folder structures and remove any unused or unnecessary files and folders before the transition. This requirement led me to take a closer look at the DIR command. By using a combination of optional parameters, I was able to generate a complete listing of all folders and subfolders on our department’s server, accessed through the mapped server drive on a Windows 95 client machine. This listing proved invaluable in reviewing the contents and identifying obsolete folders and files for removal before migration.

You can generate a folder listing using either the DIR command or the TREE command, each producing a different output style. Personally, I prefer the DIR command. The TREE Command creates a graphical view, displaying the hierarchical structure of folders and subfolders. In contrast, the DIR command presents each folder and subfolder on a single line, separated by backslashes. A sample of both the Command listings is given below:

 styles are shown below for comparison:

Dir Command has several optional parameters to prepare listings in different ways depending on your requirements. Most of the time, we ignore these options because their usage is uncommon.

DOS Command Help.

You can get a list of all optional parameters with a simple help command parameter (/?). The Usage is as given below. First, let us open the DOS Command Window.

  1. Right-click the Windows Start Button and click Run command.
  2. Type cmd in the control and click OK to open the DOS Command Prompt.
  3. If the prompt appears as something like C:\Users\User>, then Type:
    Cd \ then press Enter key to set the prompt to C:\>

    CD stands for the Change Directory command. The \ is the name of the Root Folder. This will set the C: Drive root folder as the current directory.

    Tip: Type the Command Exit and press the Enter key to close the DOS window any time you want.

  4. Type the following command to display a list of optional parameters of the DIR command:
    DIR /?
    

You can display the details of any DOS command and its usage by typing the command followed by /? in the DOS Command prompt.

Display Folders in the C: Drive.

Now, let us display the folder listing in the C: drive on the screen.

Warning: Don't say I didn't warn you that this will be a lengthy list and may take a few minutes to display all of them on the screen.

Tip: You may terminate the runaway listing at any time by pressing Ctrl+C Keys.

Type the following command in the DOS Prompt and press Enter.

C:/>DIR /A:D/S/B/P

Let us take a look at each parameter given with the DIR command.

DIR Command and its few Options.

  • /A - Display files with specific Attributes. Specific attributes are given, separated by a colon, like /A:D D - for directories.
  • /S - include subfolders in the listing.
  • /B - take a Bare-format listing and exclude summary information.
  • /P - display the listing Page-wise (Pause the listing when a screen full of information is displayed. Press any key to display the next page).

If you need a listing of a particular folder and its sub-folders only, then include the folder name in the command as given below:

C:/>DIR "\RADIO" /A:D/S/B/P

Saving the Directory Listing to a File.

By default, the output of a DOS command is displayed directly on the screen. If you need a printed copy, the output must first be saved to a text file. This can be done using the output redirection symbol (>) followed by the file name. For example, the following command saves the output to a file named FolderList.txt:

C:/>DIR "\RADIO" /A:D/S/B > FolderList.txt

Note: If you are generating a listing of all folders and subfolders/files on a disk, the process may take some time to complete and save all the details to a text file. During this period, it may appear as though the computer has hung. Be patient and wait for the DOS prompt (C:\>) to reappear.

If you wish to terminate the command, press Ctrl+C before it finishes.

You may open the text file FolderList.txt in any plain-text editor App to take printouts.

The TYPE command.

You may use the following DOS command to display the contents of the text file:

Type FolderList.txt | More

TYPE - Displays the contents of the text file on the screen.

| (Vertical Bar) – This symbol is called the piping symbol. It directs the output of one command to another command for further processing.

For instance, when used with the TYPE command, the piping symbol passes its output to the MORE command. The MORE command displays the output one screen at a time, similar to using the /P parameter with the DIR command. Press any key to view the next page of output.

The TREE Command.

The TREE command displays the folder list in a hierarchical structure.

C:/>TREE | More

Display the folder structure listing page-wise.

C:/>TREE/F | More

/F parameter displays folder names followed by Filenames.

Hope you have enjoyed doing something different and useful.

Share:

Calculating Work Days from Date Range

Calculating Workdays from a Date Range.

How to find the number of workdays (excluding Saturdays and Sundays) from a date range in Microsoft Access?

The logic is straightforward: first, determine the number of whole weeks within the specified date range. Multiplying whole weeks by 5 gives the number of workdays from entire weeks.  From the remaining days, exclude Saturdays and Sundays, if any. Add the remaining days to the total workdays.

The DateDiff() and DateAdd() functions are used to perform date calculations. The Format() function determines the day of the week in its three-character abbreviated form, allowing Saturdays and Sundays to be identified and excluded from the remaining days.

Find the VBA Code segments for the above steps below, and the full VBA Work_Days() Function Code at the end of this Article.

  1. Find the number of Whole Weeks between Begin-Date and End-Date:

    WholeWeeks = DateDiff("w", BeginDate, EndDate)

    The WholeWeeks * 5 (7 - Saturdays & Sundays) will give the number of working days in whole weeks. Now, we need to find how many working days to take, if any.

  2. Find the date after all the weekdays:
    DateCnt = DateAdd("ww", WholeWeeks, BeginDate)
  3. Find the number of workdays in the remaining days by checking and excluding Saturdays and Sundays:
    Do While DateCnt <= EndDate
          If Format(DateCnt, "ddd") <> "Sun" And _
            Format(DateCnt, "ddd") <> "Sat" Then
             EndDays = EndDays + 1
          End If
          DateCnt = DateAdd("d", 1, DateCnt)'increment the date by 1
        Loop
    
  4. Calculate the Total Workdays:

    Work_Days = Wholeweeks * 5 + EndDays

The Whole Calculation is in the Work_Days Function.

The full VBA Code of the Work_Days() Function is given below:

Function Work_Days(BegDate As Variant, EndDate As Variant) As Integer

   Dim WholeWeeks As Variant
   Dim DateCnt As Variant
   Dim EndDays As Integer
         
   On Error GoTo Err_Work_Days

   BegDate = DateValue(BegDate)
   EndDate = DateValue(EndDate)
'Number of whole weeks
   WholeWeeks = DateDiff("w", BegDate, EndDate)
'Next date after whole weeks of 7 days each
   DateCnt = DateAdd("ww", WholeWeeks, BegDate)
   EndDays = 0 'to count number of days except Saturday & Sunday

   Do While DateCnt <= EndDate
      If Format(DateCnt, "ddd") <> "Sun" And _
        Format(DateCnt, "ddd") <> "Sat" Then
         EndDays = EndDays + 1
      End If
      DateCnt = DateAdd("d", 1, DateCnt)'increment the date by 1
    Loop
'Calculate total work days and return the result
   Work_Days = WholeWeeks * 5 + EndDays

Exit Function

Err_Work_Days:

    ' If either BegDate or EndDate is Null, return a zero
    ' to indicate that no workdays passed between the two dates.

    If Err.Number = 94 Then
                Work_Days = 0
    Exit Function
    Else
' If some other error occurs, provide a message.
    MsgBox "Error " & Err.Number & ": " & Err.Description
    End If

End Function

The above VBA Code was taken from the Microsoft Access Help Document.

Share:

PRESENTATION: ACCESS USER GROUPS (EUROPE)

Translate

PageRank

Post Feed


Search

Popular Posts

Blog Archive

Powered by Blogger.

Labels

Forms Functions How Tos MS-Access Security Reports msaccess forms Animations msaccess animation Utilities msaccess controls Access and Internet MS-Access Scurity MS-Access and Internet External Links Queries Array Class Module msaccess reports Accesstips msaccess tips WithEvents Downloads Objects Menus and Toolbars MsaccessLinks Process Controls Art Work Collection Object Property msaccess How Tos Combo Boxes ListView Control Query VBA msaccessQuery Calculation Dictionary Object Event Graph Charts ImageList Control List Boxes TreeView Control Command Buttons Controls Data Emails and Alerts Form Custom Functions Custom Wizards DOS Commands Data Type Key Object Reference ms-access functions msaccess functions msaccess graphs msaccess reporttricks Command Button Report msaccess menus msaccessprocess security advanced Access Security Add Auto-Number Field Type Form Instances ImageList Item Macros Menus Nodes Recordset Top Values Variables msaccess email progressmeter Access2007 Copy Excel Expression Fields Join Methods Microsoft Numbering System RaiseEvent Records Security Split SubForm Table Tables Time Difference Utility WScript Workgroup Wrapper Classes database function msaccess wizards tutorial Access Emails and Alerts Access Fields Access How Tos Access Mail Merge Access2003 Accounting Year Action Animation Attachment Binary Numbers Bookmarks Budgeting ChDir Color Palette Common Controls Conditional Formatting Data Filtering Database Records Defining Pages Desktop Shortcuts Diagram Disk Dynamic Lookup Error Handler Export External Filter Formatting Groups Hexadecimal Numbers Import Labels List Logo Macro Mail Merge Main Form Memo Message Box Monitoring Octal Numbers Operating System Paste Primary-Key Product Rank Reading Remove Rich Text Sequence SetFocus Summary Tab-Page Union Query User Users Water-Mark Word automatically commands hyperlinks iSeries Date iif ms-access msaccess msaccess alerts pdf files reference restore switch text toolbar updating upload vba code