Naming Objects in Microsoft Access: 
Version 2 of a Proposed Standard

By Stan Leszynski and Greg Reddick

Distributed with permission from Stan Leszynski, Greg Reddick, 
and the publisher of Smart Access, Pinnacle Publishing, Inc., 
18000 72nd Ave South, Suite 217, Kent, WA  98032

Copyright 1993 by Stan Leszynski and Greg Reddick. All Rights Reserved
 
For reprint rights, contact Pinnacle Publishing, Inc.
For order information, call 206-251-1900 or 800-788-1900, price $79 per year, 
including Companion Disk.

An earlier version of this standard was published in the February 1993 
(Charter) issue of Smart Access. 

If you've ever inherited a project from another developer, you know 
how frustrating it is to try to dissect another developer's style 
and maintain his or her code. When developers code with a common   
style, however, you can minimize these frustrations. To best share 
ideas and knowledge, the Access development community will benefit 
greatly if it adopts a common programming style so that we can 
benefit from each other's expertise with a minimum of translation 
overhead. Although Microsoft uses certain naming conventions in 
the Access documentation, to date, they haven't published an 
official standard. Furthermore, we think Microsoft's naming 
guidelines, although useful for some users, don't meet the needs of 
Access developers and are inconsistent with other products such as 
Visual Basic and Microsoft C. Thus, we've formulated a set of 
naming conventions to better serve Access users and developers. 

These conventions were originally published in the Charter Issue of 
Smart Access. Since then, we've logged thousands of hours of 
development time and scores of comments from Smart Access readers 
and we've found ways to improve the style and make it more useful. 

This version of our naming style ties Access conventions more 
closely to Visual Basic conventions because we recognize that 
many Access developers also use or plan to use Visual Basic 
for some data access applications. Access and Visual Basic 
are becoming more similar with each released version. We've 
written these naming conventions so you can also use them 
with Visual Basic database applications.

There are two levels to the naming conventions. Level 1 is 
comprehensive, but doesn't clarify objects as explicitly as 
Level 2. Level 1 is suitable for beginning developers, and 
Level 2 is intended for more experienced developers and 
developers involved in complex development projects and 
multiple-developer environments. You should experiment and 
choose the level that works best for you. (Note: Not all 
parts of the standard have two levels.)

If you're already using our original conventions, you'll need 
to make a few changes to accommodate the enhancements in 
this revision. Because Access provides little help in 
renaming objects, you may wish to leave existing applications 
as is and apply the revised conventions to new projects, going 
back to existing applications as time permits. 

Naming conventions: An overview

Our naming style is based on a method of naming called Hungarian, 
referring to the nationality of its creator, Charles Simonyi (who, 
incidentally, worked on the first version of Access). Hungarian was 
first proposed in his doctoral thesis. 

Some elements of Hungarian style are used in Microsoft's Visual 
Basic manuals and the Windows SDK manuals, among others. 
Microsoft uses Hungarian internally, and many programmers around 
the world use it as well. We've adapted the Hungarian style for 
the Access environment.

In our Access naming style, object names are made up of four 
parts: prefixes, tag, base name, and qualifier. The four parts 
are assembled as follows:

[prefixes]tag[Basename][Qualifier]

(Note: The brackets denote that these components are optional and 
aren't part of the name.)

The tag is the only required component, but in almost all cases 
the name will have the base name component because you need to 
be able to distinguish two objects of the same type [1]. Here are a 
few examples:

Name                Prefix     Tag       Base            Qualifier

tblCustomer                    tbl       Customer
aintPartNum           a        int       PartNum
strCustNamePrev                str       CustName        Prev

Prefixes and tags are always lowercase so your eye goes past them to 
the first uppercase letter where the base name begins. This makes the 
names more readable. The base and qualifier components begin with an 
uppercase letter. 

The base name succinctly describes the object, not its class. 
This is the name you'd likely give the object if you weren't 
using any particular naming style. For example, in the query name 
qryPartNum, "PartNum" is the base name; it's an abbreviation 
for Part Number. Object tags are short and mnemonic. Object 
prefixes precede some object names and tags and provide further 
information. For example, if an integer variable intPartNum is 
an array of part numbers, the prefix "a" for array is added to 
the front, as in aintPartNum(). Further, a variable that provides
an index into the array would use the name of the array prefixed 
with the index prefix "i", as in iaintPartNum.

Applying a naming style like this requires more effort up front, 
but try to imagine which of these two code samples makes more 
sense to you a year from now when you want to modify or try to 
reuse your code:

	  Z = Y(X)

or

	  intPart = aintPartNum(iaintPartNum)

Object qualifiers may follow a name and further clarify names that 
are similar. Continuing with our parts index example, if you kept 
two indexes to the array, one for the first item and one for the 
last, the variable iaintPartNum above would become two qualified 
variables_iaintPartNumFirst and iaintPartNumLast.

Naming database objects

Database objects (tables, queries, forms, reports, macros, and modules) 
are the most frequently referenced items in an Access application. 
They appear in your macro code, in your Access Basic routines, and in 
properties. Thus, it's important that you standardize how you name 
them.

 Microsoft's examples in the Northwind Database and Access manuals 
 allow for spaces in object names. We don't use them in our style. In 
 most database engines and programming languages, including Access 
 Basic, a space is a delimiter character between items. It isn't a 
 logical part of an item's name. Also, spaces in field names don't 
 work in most other database platforms or Windows applications such 
 as SQL Server or Word for Windows. Instead, use upper and lowercase 
 designations in names, such as tblAccountsPayable. If spacing is 
 still necessary, use the underscore (_) character instead of a space 
 to be consistent with traditionally accepted SQL syntax.

Tags for database container objects

All database container object names in our style have tags. Adding 
tags to these objects may make them less readable to nondevelopers, 
but new users will understand their value when they're trying to 
discern a table from a query in the listbox for a New Report wizard 
or a form's Control Source property. This is because Access merges 
table and query names into one long list. Here are Level 1 database 
container object name tags:

Object          Tag             Example

Table           tbl             tblCustomer
Query           qry             qryOverAchiever
Form            frm             frmCustomer
Report          rpt             rptInsuranceValue
Macro           mcr             mcrUpdateInventory
Module [2]      bas             basBilling

At Level 1, the only name qualifier (appended to the name) that we 
use for database container objects is Sub, which we place at the end 
of a form or report name for a subform or subreport. The form 
frmProductSupplier would have the related subform frmProductSupplierSub. 
This allows objects and their subform or subreport to sort next to 
each other in the database container.

Level 2 tags, shown here, provide more descriptive information.

Object                  Tag                   Example

Table                   tbl                   tblCustomer
Table (lookup) [3]      tlkp                  tlkpShipper
Table (system) [4]      zstbl                 zstblUser
Query (select)          qry (or qsel)         qryOverAchiever
Query (append)          qapp                  qappNewProduct
Query (crosstab)        qxtb                  qxtbRegionSales
Query (delete)          qdel                  qdelOldAccount
Query (form filter)     qflt                  qfltSalesToday
Query (lookup) [3]      qlkp                  qlkpStatus
Query (make table)      qmak                  qmakShipTo
Query (system) [4]      zsqry                 zsqryMacroName
Query (update)          qupd                  qupdDiscount
Form                    frm                   frmCustomer
Form (dialog)           fdlg                  fdlgLogin
Form (menu)             fmnu                  fmnuUtility
Form (message)          fmsg                  fmsgWait
Form (subform) [5]      fsub                  fsubOrder
Form (system) [4]       zsfrm                 zsfrmSecurity
Report                  rpt                   rptInsuranceValue
Report (subreport) [5]  rsub                  rsubOrder
Report (system) [4]     zsrpt                 zsrptMacroName
Macro                   mcr                   mcrUpdateInventory
Macro (for form) [6]    m[formname]           mfrmCustomer
Macro (menu) [7]        mmnu                  mmnuEntryFormFile
Macro (for report) [6]  m[rptname]            mrptInsuranceValue
Macro (system) [4]      zsmcr                 zsmcrLoadLookup
Module [2]              bas                   basBilling
Module (system) [4]     zsbas                 zsbasAPI

Using our Level 2 style causes objects with similar functions to 
sort together in the database container in large applications. 
Imagine that you have a database container with 100 forms in it 
(we do!), 30 of which are messages that display during the application. 
Your users now want all message forms to have red text instead of 
black, so you must change each of the 30 forms. Having the message 
forms sort together in the database container (because they've all 
got the same tag) saves you significant effort trying to discern 
which forms you need to change.

Database object prefixes

We use four database object prefixes:

o       "zz" denotes objects you've deserted but may want to keep in 
	 the database for awhile for future reference or to reuse later 
	 (for example, zzfrmPhoneList). "zz" causes the object name to 
	 sort to the bottom of the database container, where it's 
	 available but out of the way. 

o       "zt" for temporary objects (for example, ztqryTest). 

o       "zs" for system objects (for example, zstblObjects). 

o       "_" for objects under development (for example, _mcrNewEmployee). 
	 An underscore before an object name sorts to the top of the 
	 database container to visually remind you that it needs attention. 
	 Remove the underscore when the object is ready to use and it 
	 sorts normally.

Choose your table names carefully. Name each database object that 
refers to that table with the same name, using the appropriate tag to 
differentiate them. For example, if your table is tblCustomer, its 
primary form would be frmCustomer, its primary report would be 
rptCustomer, and the macros that drive all of the events would be 
mfrmCustomer and mrptCustomer. We also suggest that you don't make 
table names plural (for example, use tblCustomer, not tblCustomers), 
because a table usually holds more than one record, so it's plural by 
implication. 

Tags for fields

Using tags in field names is a hotly-debated issue, even between 
the authors of this article. Greg maintains that tags in field names 
uniformly apply the naming style across all database elements and 
further document your work in Access Basic routines and form or 
report properties. Stan prefers that the database schema remain 
pure (platform- and data type-independent) for migration and 
connectivity to other products or platforms. He prefers that a 
field remain independent of its data type. Consider both positions, 
along with your unique needs, when you choose whether to apply the 
field name tags shown here:


Field Type       Tag              Example

Binary [8]       bin              binInternal
Byte             byt              bytFloorNum
Counter [9]      lng              lngPKCnt
Currency         cur              curSalary
Date/Time        dtm              dtmHireDate
Double           dbl              dblMass
Integer          int [10]         intUnit
Long             lng [11]         lngPopulation
Memo             mem              memComments
Ole              ole              oleEmpPhoto
Single           sng [12]         sngScore
Text             str [13]         strFirstName
Yes/No           ysn [14]         ysnDiscounted

Tags for control objects

Access forms and reports automatically assign the field name to 
the Control Name property when you create a new bound control. With 
the control name and field name the same, it creates some ambiguity 
in the database schema and in some cases may cause errors in Access 
Basic code referencing both a control and a field with the same name. 
To resolve this situation, apply the naming style to form and report 
controls by inserting the appropriate tag from the list below, in front 
of the control name suggested by Access. For example, the control name 
for a field whose Control Source is LastName would be txtLastName.

At Level 1, we recognize that users need to know the difference 
between an active control and a label, but may not be concerned with 
the type of the control. Thus the control tags are as follows:

Object               Tag           Example

Label                lbl           lblLastName
Other types          ctl           ctlLastName

Level 1 tags provide the minimum differentiation necessary to still 
prove useful in functions, macros, and program documentation. For 
example, the control tags above allow you to differentiate between 
labels, which aren't modifiable at runtime, and other controls, 
which accept values from code and users.

Level 2 control tags denote the specific type of the control on the 
form or report. This makes Access Basic code and macros more explicit 
with respect to the properties and events of the individual control:

Object                 Tag             Example

Chart                  cht             chtSales
Check box              chk             chkReadOnly
Combo box              cbo             cboIndustry
Command button         cmd             cmdCancel
Frame                  fra             fraPhoto
Label                  lbl             lblHelpMessage
Line                   lin             linVertical
List box               lst             lstPolicyCode
Option button          opt             optFrench
Option group           grp             grpLanguage
Page break             brk             brkPage1
Rectangle (shape) [15] shp             shpNamePanel
Subform/report         sub             subContact
Text box               txt             txtLoginName
Toggle button          tgl             tglForm

The only prefix for controls, zs, appears at Level 2. It denotes 
system level controls used by the form or code but not displayed to 
the user. Such controls usually aren't visible at runtime but they 
may store temporary values or parameters passed to the form.

Naming Access Basic and macro objects

Using standardized and descriptive variable, constant, and function 
names greatly enhances the ability of developers to share, maintain, 
and jointly develop code.

Procedures and macros

Access Basic requires that each nonprivate procedure name in a database 
be unique. For a function called from a property on a form, construct 
the function name as follows:

	formname_controlname_propertyname

For example:

	frmEmployee_cmdAdd_OnPush

(Note: If you use long form and conrol names, your function names may run 
into Access' 40-character name limit. Thus, we suggest using short form 
and control names.)

This tells you that this function is called from the OnPush property 
of the control cmdAdd on the form frmEmployee. For a property that 
affects the entire form, just use formname_propertyname, as in 
frmEmployee_OnOpen. If two or more controls on one form execute the 
same code, create unique functions for each using the naming style 
in this section, then have each of these functions call the same 
private function that contains the common code.

Macro names inside a macro group also use this format. In the macro 
group mfrmEmployee, the macro cmdAdd_OnPush contains the actions for 
the cmdAdd button's OnPush event. For example, the cmdAdd button on 
your frmEmployee form would have one of these properties, depending 
on whether you use modules or macros to implement the task:

  OnPush...... =frmEmployee_cmdAdd_OnPush()
  OnPush...... mfrmEmployee.cmdAdd_OnPush

Prefix procedure names in library databases with a unique set of 
characters to prevent their names from conflicting with any other 
names from attached libraries. The prefix should be in uppercase 
letters, followed by an underscore, and be no more than four letters. 
For example, we prefix all the library function names for our 
mail-merge utility, Access To Word, with "ATW_". Global constants 
and variables in a library should use the same prefix because they 
must also be unique across the entire database name space. Similarly, 
it is important to use these prefixes in Declare statements to alias 
all external DLL function and procedure calls.


Tags for Access Basic variables

Every Access Basic variable should have a type tag from the following 
list:

Variable Type           Tag           Example

Control                 ctl           Dim ctlVapor As Control
Currency                cur           Dim curSalary As Currency
Database                db            Dim dbCurrent As Database
Double                  dbl           Dim dblPi As Double
Dynaset                 dyn [16]      Dim dynTransact As Dynaset
Flag (Y/N, T/F) [17]    f             Dim fAbort As Integer
Form                    frm           Dim frmGetUser As Form
Integer                 int           Dim intRetValue As Integer
Long                    lng           Dim lngParam As Long
QueryDef                qry           Dim qryPrice As QueryDef
Report                  rpt           Dim rptYTDSales As Report
Single                  sng [18]      Dim sngLoadFactor As Single
Snapshot                snp           Dim snpParts As Snapshot
String                  str           Dim strUserName As String
Table                   tbl           Dim tblVendor As Table
Type (user-defined)     typ           Dim typPartRecord As  mtPART_RECORD
Variant                 var           Dim varInput As Variant
Yes/No [17]             ysn           Dim ysnPaid As Integer
					
					
Our style doesn't use data-type suffixes such as $ and % on 
variable names, because the Access and Visual Basic documentation 
recommends against using these suffixes.

Tags for database object variables such as the Form and Report 
types are the same as those used for the objects. This helps when 
coding, because the variable you assign an object to (for example, 
tblVendor) usually has the same name as the object it references 
(tblVendor), providing you with consistent object names when 
coding.

Constants and user defined types

It is common practice in Windows programming to use uppercase names 
for constants, but the authors differ on how to treat constants. 
Stan prefers using the uppercase notation and adding a scope prefix 
(see below), so a global constant for a specific error might be 
gNO_TABLE_ERROR. Greg prefers to treat constants as typed variables 
without scope, for example, strNoTableError.

In the above table, we've added a variable type tag of "typ" for 
user-defined types, and suggest a convention that matches that of 
constants, because you can think of both user-defined types and 
user-defined constants as persistent, user-created objects. The 
recommendations for a user-defined data type syntax include: use 
uppercase letters (or upper/lower syntax if you use that optional 
convention for globals); use a tag of "t" in front of the type name 
to denote that it's a type structure; and use "g" and "m" prefixes 
to denote the scope of the type (see below).

Prefixes for scope

Level 2 of the naming convention introduces scope prefixes for 
variables and constants. The scope prefix comes before any other 
prefixes. 

o       Variables declared locally with a Dim statement have no prefix. 

o       Variables declared locally with a Static statement are prefixed 
	  with "s", as in "sintAccumulate". 

o       Variables that are declared in the Declarations section of a 
	  module (or form in Visual Basic) using a Dim statement are 
	  prefixed with "m", as in "mcurRunningSum". 

o       Variables declared with global scope using a Global statement 
	  in the Declarations section have the prefix "g" as in 
	  "glngGrandTotal". 

 o      Variables that denote parameters passed in to a function 
	  (in the parentheses after the function name) have a prefix of 
	  "p" as in "pstrLastName". 

Object qualifiers follow the variable name and further differentiate 
it from similar names. You'll probably devise a list of qualifiers 
relevant to the types of applications you develop, but here are some 
of our common ones:

Variable Property               Qualifier       Example

Current element of set          Cur             iaintCur
First element of set            First           iaintStockFirst
Last element of set             Last            iaintStockLast
Next element of set             Next            strCustomerNext
Previous element of set         Prev            strCustomerPrev
Lower limit of range            Min             iastrNameMin
Upper limit of range            Max             iastrNameMax
Source                          Src             lngBufferSrc
Destination                     Dest            lngBufferDest

Access Basic labels

For Access Basic labels, we use a qualifier on the function name to 
create several standard labels. For On Error Goto statements, we use 
the name of the function with the qualifier Error and stripped of 
underscores, for example:

   FrmEmployeeCmdAddOnPushError:

Some functions also have a label for jumping forward to the end of 
the function, because it's more appropriate to leave a function only 
in one place than to scatter Exit Function statements throughout a 
routine. We use the Done qualifier, as in:

   FrmEmployeeCmdAddOnPushDone:

Access Basic example

Below is an example of an Access Basic routine using the naming 
conventions. 

We put a header in every function that describes, at a minimum: 
purpose, comments, author's name/date, last revision date and notes, 
and parameters passed in or returned. 

We return to the Done routine from the Error routine to ensure that 
open objects are closed properly before exiting the function. The 
temptation to simply use Exit Function from an error handler may 
leave files open and locked.

Function EliminateNulls (ByVal pstrFieldName As String, ByVal pstrTableName As String) As Integer
' What:        Replaces Null values with unique ascending                      
'              integers. A standardized version of a routine   
'              from NWIND and Chapter 8.
' Author:      Microsoft Created: 11/92 Last Revision: 6/24/93 By: grr/swl
' Passed in:    field name and table name
' Returns:      0/-1

	On Error GoTo EliminateNullsError
	Dim db As Database
	Dim dynTableSrc As Dynaset
	Dim varCounter As Variant
	Dim varCriteria As Variant
	
	EliminateNulls = 0
	Set db = CurrentDB()
	Set dynTableSrc = db.CreateDynaset(pstrTableName)
	varCounter = DMax(pstrFieldName, pstrTableName)
	If IsNull(varCounter) Or IsEmpty(varCounter) Then
		varCounter = 1
	Else
		varCounter = Val(varCounter) + 1
	End If
	varCriteria = pstrFieldName & " = Null"

	'Iterate over all records in the table, 
	'throw out records with Nulls
	dynTableSrc.FindFirst varCriteria
	Do Until dynTableSrc.NoMatch
		dynTableSrc.Edit
		dynTableSrc(pstrFieldName) = varCounter
		dynTableSrc.Update
		varCounter = varCounter + 1
		dynTableSrc.FindNext varCriteria
	Loop
	EliminateNulls = -1

EliminateNullsDone:     'Jump here to clean up and exit
	dynTableSrc.Close
	db.Close
	On Error GoTo 0
Exit Function

EliminateNullsError:
	Select Case Err 
	  'Handle specific messages here
	Case Else
	  'Generic error handler here
	Resume EliminateNullsDone
	End Select
End Function

Putting standards into practice

Naming conventions never replace the judicious use of comments in your 
table definitions, macro code, or Access Basic routines. Naming 
conventions are an extension of, not a replacement for, good 
program-commenting techniques.

Formulating, learning, and applying a consistent naming style requires 
a significant initial investment of time and energy. However, you'll 
be amply rewarded when you return to your application a year later to 
do maintenance or when you share your code with others. Once implemented, 
you'll quickly grow to appreciate the effort you made to standardize 
the naming of items.

If the entire Access community, including Microsoft, coded to one 
common naming style, we'd all find it easier to share information 
about Access. With this in mind, we submit these revised guidelines 
to the Access community. 

The authors wish to thank the individuals who submitted comments on and
participated in reviews of the standard.

Stan Leszynski is president of Kwery Corp., which produces several 
Access add-on products, including Access To Word and Access Documenter. 
Stan also manages Leszynski Company, Inc., a consulting group active 
in database development, which he founded in 1982. He can be reached at 
206-644-7826 or on CompuServe at 71151,1114.

Greg Reddick is the president of Gregory Reddick & Associates, a 
software consulting company. He worked for four years on the Access 
development team at Microsoft. He's a coauthor of Inside Microsoft 
Access, published by New Riders Publishing and the forthcoming 
Microsoft Access Developer's Handbook, published by Sybex. He also 
developed Access To Word, distributed by Kwery Corp. Greg can be 
reached at 206-881-6879 or on CompuServe at 71501,2564.


--------
Endnotes

1 Having the tag as the only required part may seem counterintuitive, 
but in Access Basic you can have code that deals with a generic form 
passed in as a parameter. In this case you'd use "frm" as the parameter 
name; the base name isn't required except to distinguish it from a 
different form object variable in the code.

2 The module tag "bas" is used to maintain consistency with the file 
name extension used by Visual Basic modules.

3 A look-up table has information used only to populate combo and 
list boxes on forms or validate certain fields in another table. 

4 System objects are items that are part of the development and 
maintenance of an application not used by end-users, such as error logs, development notes, documentation routines, relationship information, and so on. "zs" is a prefix. It causes the system objects to sort toward the bottom of the database container.

5 Level 2 recognizes that an advanced user may place a single 
subform/subreport in several different objects, thus the Level 1 
technique of naming the sub-object with the same base name doesn't 
work.

6 We prefer to create one macro group for each form and report in the 
system, so the naming convention adds an "m" to the front of the form 
or report name to create a hybrid macro name tag.

7 We suggest you use the menu bar name (File, Edit, Help, and so on) as 
a qualifier at the end of menu macro names.

8 The Access engine supports a data type called binary but the Access 
user interface doesn't expose it to the user. It's still possible to 
get a field with the binary data type by importing or attaching certain 
external tables. Also, some of the system table fields use this 
data type.

9 Internally, Access treats a counter data type as a long integer 
with a special property called auto-increment. Because counter fields 
are often referenced by foreign keys and the data type in the other 
table is a long, we use the same tag as a long. Or, if you want to 
distinguish a counter from a long, use the qualifier Cnt.

10 C programmers may prefer "w".

11 C programmers may prefer "dw".

12 In the August 1993 Smart Access, the tag for Single was incorrectly 
 designated as "sgl". We prefer "sng" and have made the correction here.

13 The tag "str" is used as opposed to "txt" because a textbox control 
 uses "txt". C programmers may prefer "sz".

14 C programmers may prefer "f".

15 Our style recognizes that Visual Basic uses the term "shape". 

16 The original standard used "ds".

17 Use "ysn" for a variable that stores the value of a field of data 
 type Yes/No; use "f" to denote a flag variable used to control program 
 flow. "f" is widely used by C and BASIC programmers for true/false 
 variables.

18 In the August 1993 Smart Access, the tag for Single was incorrectly 
 designated as "sgl". We prefer "sng" and have made the correction here.


