Wednesday, November 02, 2005

Check for Numeric Values in a String using VBA

I needed to check that the values entered into a textbox called StoreID in an Access Database where numerical and composed of 3 digits. Here is one solution: on the AfterUpdate event of the textbox, put this code:

Private Sub StoreID_AfterUpdate()
Dim intLen, intChar, i As Integer
Dim strTextBox As String

intLen = Len(StoreID) 'Len is a function that counts the amount of characters in a string
If intLen <> 3 Then ' if the length is not 3, give message box
MsgBox "The field 'Store ID' requires 3 digits from 001 to 900"
Else ' if length is 3 then assign variables and start loop for checking numerical values
intLen = Len(Me!StoreID)
'Me! always refers to the active form
strTextBox = Me!StoreID
For i = 1 To 3 'For 1 to 3
intChar = Mid(strTextBox, i, 1) 'Mid function takes middle values (expression,start value, length of selection)
If IsNumeric(intChar) = False Then
MsgBox " ' " & intChar & " ' is not a number, please enter numeric values only from 001 to 900"
Exit Sub
Else
End If
Next
End If
End Sub

Call an Access Database Procedure from another Access Database

Here is an Access VBA example of how to call an external Access Database VBA procedure from within a different access database.

Sub ForeignProcedure()

Dim appAccess As Access.Application

' Create instance of Access Application object.
Set appAccess = CreateObject("Access.Application")

' Open MyDatabaseName.mdb database in Microsoft Access window.
appAccess.OpenCurrentDatabase “C:\MyDatabaseName", False
'False so as not to open in exclusive mode
' Run Sub procedure.

appAccess.Run "ForeignProcedureName"
appAccess.Quit
Set appAccess = Nothing

MsgBox "Done!"

End Sub

Call an Access Database VBA Procedure from Excel

In order to call an Access vba procedure from an Excel spreadsheet, the first thing you need in Excel is a Reference for the Microsoft Access Object Library, as seen in the picture below ...

Access Object Library


To see this screen, from within Excel, go to VBA (press ALT + F11), then select Tools from the top menu and then References

Public Sub ProcedureInAccess()

‘this VBA code is run in Excel
Dim acApp As Object
Dim db As Object
Set acApp = CreateObject("Access.Application")
acApp.OpenCurrentDatabase ("C:\MyDatabaseName.mdb")
Set db = acApp
acApp.Run "NameOfProcedureInAccess"
acApp.Quit
Set acApp = Nothing

End Sub

Delete Rows from Access Database Table Using VBA and SQL

Using the DoCmd property you can delete all rows in an Access Database table using Access VBA and SQL

Sub DeleteRows()

'Deletes all rows from tblName in an Access Database

DoCmd.RunSQL "DELETE tblName.* FROM tblName;"

End Sub

Sunday, October 09, 2005

Access Database Programmer Forum

I recently came across a great resource for Access Database programming. It is a forum where you can post questions and receive knowledgeable answers from the forum's members. http://www.utteraccess.com/

Tuesday, September 13, 2005

Transaction Log for Microsoft Access Database

Here is one of the most useful pieces of code I have every come accross the Internet for programming an access database. This code will track all changes made by a user, meaning it will keep track of what data was changed, who changed it and when it was changed. This functionality is usually called a transaction log or a change log. I have copied the code directly from this page:http://www.tek-tips.com/faqs.cfm?fid=291 . The code was written by Michael Red a regular contributor at Tek-tips, which is a wonderful website that I have used many times for finding answers to many programming questions.

I have learned a few things not explained in his original code:

1) Put this code in a Module.
2) Call the basLogTrans function from the BeforeUpdate event of any form that you want to track changes.
3) Pass 3 values to the basLogTrans function: FormName, Name of Field with Unique ID, and the Unique ID.
In my implementation, I use Me as the form name, "CustomerID" as the Unique ID field, and CustomerID to pass the actual customer id value. So here is how I would call the basLogTrans function:

Private Sub Form_BeforeUpdate(Cancel As Integer)

Call basLogTrans(Me, "CustomerId", CustomerId)

End Sub

4) Mike says the code will work only on a form formated as single form, but I see it also works on a datasheet form.
5) He alos says that Access Security needs to be enabled, but I'm not sure it's true. When I used his original code for CurrentUser(), I got back "Admin" as the user that was making changes. But what I really want to know is the NT User ID of whoever is making the changes, therefore, I use Environ("Username"). If you have problems with the Environ function, please see here how to enable the Environ Function properly.
6) The rest of the instructions are pretty clear, but just to be safe, remember to add a reference for DAO, bind the form to a table, but who's to say this won't work on a Select Query? I don't know, why don't you tell me later? Make 2 tables, one called tblHist and the other tblHistMemo. First create tblHist, with the fields indicated in code comments in the function called basAddHist, then make a copy of it, name it tblHistMemo and change the OldVal and NewVal fields to datatype Memo.

That's it, it should work easily.



OK, HERE IS THE ORIGINAL VBA CODE:
All this needs to be placed in a Module, and called from the BeforeUpdate event of a form.


Public Function basLogTrans(Frm As Form, MyKeyName As Variant, MyKey As Variant) As Boolean

'Michael Red 8/1/2002 Transaction log for Ms. Access BOUND forms.

'The following three functions and table definitions are
'(should be) sufficient to establish a 'poor mans' transaction
'log for Ms. Access bound forms.

'As noted in basAddHist, you will need to create the tables
'for History (general fields) and Memo History (history of
'JUST memo fields).


'Also, note that these functions are designed to work in
'conjunction with Ms. Access Bound forms where the view is
'set to single form. Further, the history will only capture
'the user if the db App is "secured".

'In the following, "MyKey" refers to the Record ID (Unique value)
'for the single record which the form is 'tied' to.


Dim MyDb As DAO.Database
Dim MyCtrl As Control
Dim MyMsg As String
Dim Hist As String


'In the Statement block below, basFlgValidRec is a routine which
'includes validation of all fields necessary to 'define' a record
'is valid. Commented out here, as I do not know what validation
'rules need to be checked/enforced.

' If (Not basFlgValidRec) Then
' basLogTrans = False 'Let User know of FAILURE!!
' Exit Sub
' End If



For Each MyCtrl In Frm.Controls
If (basActiveCtrl(MyCtrl)) Then 'Consider replacing w/ test for "ControlSource"
If ((MyCtrl.Value <> MyCtrl.OldValue) _
Or (IsNull(MyCtrl) And Not IsNull(MyCtrl.OldValue)) _
Or (Not IsNull(MyCtrl) And IsNull(MyCtrl.OldValue))) Then
If (MyCtrl.ControlType = dbMemo) Then
Hist = "tblHistMemo"
Else
Hist = "tblHist"
End If
Call basAddHist(Hist, Frm.Name, MyKey.Name, MyCtrl)
End If
End If
Next MyCtrl

basLogTrans = True 'Let User know sucess

End Function
Public Function basActiveCtrl(Ctl As Control) As Boolean
Select Case Ctl.ControlType

Case Is = acTextBox
basActiveCtrl = True

Case Is = acLabel
Case Is = acRectangle
Case Is = acLine
Case Is = acImage
Case Is = acCommandButton
Case Is = acOptionButton
Case Is = acCheckBox
basActiveCtrl = True
Case Is = acOptionGroup
Case Is = acBoundObjectFrame
Case Is = acListBox
basActiveCtrl = True
Case Is = acComboBox
basActiveCtrl = True
Case Is = acSubform
Case Is = acObjectFrame
Case Is = acPageBreak
Case Is = acPage
Case Is = acCustomControl
Case Is = acToggleButton
Case Is = acTabCtl

End Select
End Function
Public Function basAddHist(Hist As String, Frm As String, MyKeyName As String, MyCtrl As Control)

'tblHist
'FrmName Text 80 Name of the form where change Occured
'FldName Text 80 Field Name of the changed value
'dtChg Date/Time 8 Date/Time of Change (MACHINE value!!)
'OldVal Text 255 Field Value BEFORE change
'NewVal Text 255 Field Value after change
'UserId Text 50 User who Made Change
'MyKey Variant ?? KeyField as Indentified by Caller
'MyKeyName Text 80 'Key Field Contents

'tblHistMemo is the same structure except the "type" for the fields
'OldContents and NewContents are Memo (and therfore the length is "??")


Dim dbs As DAO.Database
Dim tblHistTable As DAO.Recordset

Set dbs = CurrentDb
Set tblHistTable = dbs.OpenRecordset(Hist, dbOpenDynaset)

With tblHistTable
.AddNew
!MyKey = Forms(Frm).Controls(MyKeyName)
!MyKeyName = MyKeyName
!frmName = Frm
!FldName = MyCtrl.ControlSource
!dtChg = Now()
' !UserId = Environ("Username") 'Orlando's Way
!UserId =CurrentUser() 'Mike's way, example of current user would be Admin
!OldVal = MyCtrl.OldValue
!NewVal = MyCtrl
.Update
End With

End Function

Thursday, September 01, 2005

First and Last Access Function not supported in SQL Server

In a Microsoft Access database, in order to return the first or last record in the result set returned by a query, you can use the First and Last Functions. The syntax is simple: First(expr) or Last(expr). If you try to use these functions in SQL Server, however, they will not work. You will get a message similar to this:

Server: Msg 195, Level 15, State 10, Line 2
'First' is not a recognized function name.


In order to repeat the desired outcome in SQL Server, simply use the MIN and MAX function.

ACCESS SQL VERSION:
SELECT
ContractorID, FIRST(Contractor)
FROM
tblContractor
WHERE
ContractorID = "ABC6783"
GROUP BY
ContractorID


(T-SQL) SQL SERVER VERSION:
SELECT
ContractorID, MIN(Contractor)
FROM
tblContractor
WHERE
ContractorID = 'ABC6783'
GROUP BY
ContractorID

Monday, August 29, 2005

Loop in VBA Easy Example

There are different versions of looping in VBA. Here is an example of the Do While version.

Sub letsLoop()
Dim intCounter As Integer

intCounter = 1 'Set the counter to 1

Do While intCounter <3'Loop while value of intCounter less then 3
MsgBox intCounter 'show message box with value of intCounter
intCounter = intCounter + 1 ' increase value of intCounter by 1
Loop 'loop again

End Sub

Monday, August 15, 2005

Capture Signature and Date Stamp in Excel Worksheet

With all the Sarbanes-Oxley (SOX) requirements going around lately, there has been a big push to making staff attest that they have reviewed the various Excel reports they are sent. One way to do that is to have them sign and date the report and save the report somewhere on the network. Later I will run an Excel macro that goes and looks for everyone’s signature and produces a report of who has signed and when.

Anywho, for the signature portion, I've added a sheet in the Excel reports, the sheet is called Signature. This sheet has a check box. Clicking this check box called chkSignature, populates cells C2 and C3 with the Windows User ID and the Date.

For the user's Windows User ID, we use the method Environ("username"). And for the Date we use well, the Date function.

Here is the code behind the click event of check box chkSignature:

Private Sub chkSignature_Click()

If chkSignature.Value = True Then
Sheets("Signature").Range("C2").Value = Environ("username")
Sheets("Signature").Range("C3").Value = Date
Else
Sheets("Signature").Range("C2").Value = ""
Sheets("Signature").Range("C3").Value = ""
End If

End Sub

Wednesday, August 10, 2005

Automatically Maximize Access Form

To maximize an Access form automatically, use the "Maximize" method of the DoCmd Object.

Example, let's say I have a form called MainForm, on the "On Load" Event property of the form, I would use this sub procedure:

Sub MainForm_Load()

DoCmd.Maximize

End Sub

Monday, August 08, 2005

Find the Number of Series in Excel Chart

While adding a trend line to a group of charts, I needed to know how many data series where in the Graph's Series Collection. I will add an equal amount of trend lines.


Sub countseries()

MsgBox ActiveChart.SeriesCollection.Count

End Sub

Monday, July 25, 2005

Using a Combo Box in Excel

From the top menu, navigate thru: View / Toolbars / Control Toolbox



When the Control Toolbox appears, Select the Combo Box control. With your mouse, make a rectangular shape on the excel sheet.



Define the choices that will be available in the Combo Box. In this example, the names of fruits are written on Column F from row 1 thru 4.




Tell the combobox where to get it's data from. Right click on the combobox to get it's properties.




Then in the ListFillRange, enter the range of cells that hold the combox values. In this case F1:F4.



That's all there is to it, close design view and your combo box should be working fine.

Tuesday, July 19, 2005

Securing an Access Database

A reader from Kuwait wrote the other day...


Orlando,

I was browsing for some help on the net and just saw
your name, I had a question, could you please help me.

My question is, i have developed a database, and i
want to give it to my friend, the question is, i want
to secure the Queries, Form & Reports from being
edited or re-designed, i dont want these to be visible
whenever he uses it. he should be able to print &
update database, but he should not be able to see what
queries i have set as well he should not be able to go
to the design view to modify my forms & Reports.

Could you please help.

Regards,

Oswald
Kuwait


Oswald...

There are a couple of different ways that the above can be accomplished.

1) User Level Security. But I don't recommend it because it is difficult to maintain.

2) A combination of setting the Start Up options, tweaking the properties of the Forms, and making an mde file.

You will have to play around with option number 2 to get the desired results. But here are a few pointers.

From the menu bar, go to Tools / Start Up and un-check "Display Database Window". Next time the database starts, the database window will not be available. If you want to see it, then you would go to Window / Unhide and select the database window. If you choose to not see the database window, you would have to have some form that would serve as the main menu for your database.




Another thing that you could do is hide your database objects, but this is the least effective way, because in the Database Options there is the option to View Hidden Objects. But anyway, here is how you could hide them: Right Click on the object to arrive at the Properties window and check Hidden.




Another alternative is to allow Design Changes on Forms Only in Design View. And to not allow viewing the form any other way then you intended. Forms can be viewed as FORMS, DATASHEETS, PIVOT TABLES, PIVOT CHART. So make sure that in the Forms Format Properties you unselect the view types you do not want the user to use.







Finally, after you have implemented a combination of the tips above, make the database an MDE file. Go to Tools / Database Utilities / Make MDE file.

Sunday, July 10, 2005

How to Filter Access Subforms based on a control from a Main Form

If you are reading this then you have probably noticed that filtering a Subform based on a control from the Main form is a pain in the neck.

Here's one way to filter the subform by changing the underlying form.

Sub frameTaskStatus_Click()
Dim intStat As Integer
intStat = frameTaskStatus.Value
' 1 = all
' -1= closed
' 0 = open
' 2 = new open frmCreateNewRequest


Select Case intStat
Case -1
Me!sbfrmMainRequests.SourceObject = "subfrmRequestsFiltered"
Case 0
Me!sbfrmMainRequests.SourceObject = "subfrmRequestsFiltered"
Case 1
Me!sbfrmMainRequests.SourceObject = "subfrmRequestsAll"
Case 2
Me!sbfrmMainRequests.SourceObject = "subfrmRequestsNew"
End Select

End Sub



Cases -1 and 0 (closed and open, respectively) make subfrmRequestsFiltered the underlying subform. This subform's datasource is a query that applies a filter also based on the value selected in frameTaskStatus.

Case 1 makes subfrmRequestAll the underlying subform in the Main form. subfrmRequestAll is also based on a query but it is not filtered.

Case 2 makes subfrmRequestsNew the underlying subform in the Main form. subfrmRequestsNew is a data entry only form.

Wednesday, July 06, 2005

How to Determine the Version or Edition of SQL Server

Open Query Analyzer, connect to any database on your server and type one of the following:

SELECT SERVERPROPERTY('ProductLevel')
SELECT @@VERSION
SELECT SERVERPROPERTY('ProductVersion')


If you are not sure whether you are running an edition of the SQL Server 2000 database engine or MSDE 2000, execute the following query:
SELECT SERVERPROPERTY('Edition')

Tuesday, June 21, 2005

A word of Advice for my International Programming Brothers

Collation is the way in which data will be sorted in SQL Server.

When building SQL Server databases for American clients, be sure to define the database collation as SQL_Latin1_General_CP1_CI_AS, which means Latin characters, case insensitive, accent sensitive. This is the default setting for Windows Desktops in America. If you are developing in another country, your installation of Windows will probably have a different default language setting. If when you created the SQL Server database, you chose “default” for the collation settings, the database will have been created with a different collation setting, a non-American collation setting.

If you are developing a multi-language capable database, an international database, define your table fields as nvarchar whenever possible. Nvarchar ia a UNICODE character, which means it uses two bytes per character, as opposed to ASCII characters which are one byte in length and thus limits the number of possible ASCII characters

Thursday, June 16, 2005

Access: How to Refresh Form Data or Data on a Control

Simple:

use the .Requery Method

Forms!FormName.ControlName.Requery

or if you want to refresh all controls in the form, then

Forms!FormName.Requery

Monday, June 13, 2005

User Friendly Prompt for Requesting Required Information in Access Form

I have a form which has a SAVE RECORD button, which runs a Save Record Macro. The underlying form's table has a Required field. When the Required field is not populated and the SAVE RECORD button is clicked, a popup message prompts the user for the Required field. The problem is that the popup message prompts for the field name as defined in the table and in some cases this might be confusing to the user.

In order to make a user friendly popup message, you could add a condition to the Save Record Macro which checks whether the Required field control is populated or not with: is null(Required Field). If it is true, exit the macro, else continue.

Sunday, June 05, 2005

How to Run an Access Macro from Excel VBA

In excel you would need the following Sub procedure:

Sub RunMacroInAccess()

Dim Acc as Object
Set Acc = CreateObject("Access.Application")
Acc.OpenCurrentDatabase("C:\My Documents\AccessDatabase.mdb")
Acc.DoCmd.RunMacro "AccessMacroName"

End Sub