Auto Generate Primary Field Value

M

mc2882

Rather than use Auto Number I would like Access to automatically generate
unique customer ID's as the primary field in a customer table I'm designing.

The format for these customer ID's is: the date they were entered as a
customer + a sequentially numbered three digit extension (001, 002...999).
The final format is: MMDDYYXXX.

How is this accomplished?
 
J

John Spencer

A possible slight modification to Ken Sheridan's response.

IF you want to the sequential numbers to be sequential within a date, then

Me.[CustomerNumber] =
Nz(DMax(""CustomerNumber", "Customers","CustomerDate =Date())",0)+1

This would give you values like
092209001
092209002
...
092209055
...
092309001
092309002
092309003

John Spencer
Access MVP 2002-2005, 2007-2009
The Hilltop Institute
University of Maryland Baltimore County
Firstly I'd suggest that you have separate columns for the date and serial
number, the latter as the primary key. It’s a trivial task to concatenate
them into one computed column in a query, or a computed control in form or
report with an expression such as:

Format([DateEntered],"mmddyy") & Format([CustomerNumber],"000")

To automatically insert the current date into the DateEntered column when a
row is inserted into the table set its DefaultValue property to Date(). To
compute the next CustomerNumber in sequence data must be entered via a form.
In a single user environment simply put:

Me.[CustomerNumber] = Nz(DMax(""CustomerNumber", "Customers"),0)+1

in the form's BeforeInsert event procedure. In a multi-user environment,
however, this can cause conflicts if two or more users are adding a new
customer simultaneously. Roger Carlson has a simple solution to this at:

http://www.rogersaccesslibrary.com/...?TID=395&SID=83z7c11zc7b721d2a1e51989c53d7ffb


or there's a slightly more complex one of mine at:

http://community.netscape.com/n/pfx...yMessages&tsn=1&tid=23839&webtag=ws-msdevapps


which also allows for the next number to be used in the sequence to be
'seeded'.

I've assumed above that the CustomerNumber values will be distinct. If,
however, you want a separate sequence per DateEntered value, starting at 1
for each date, then you'd need to make the primary key a composite one of
both columns, and compute the next number for the date in question. In a
single user environment the code would be:

Dim strCriteria As String

srCriteria = "DateEntered = #" & Format(Me.DateEntered,"yyyy-mm-dd") & "#"

Me.[CustomerNumber] = _
Nz(DMax(""CustomerNumber", "Customers", strCriteria),0)+1

In a multi user environment, using my method the function to get the next
number would be:

Public Function GetNextNumberForDate(strCounterDb As String, dtmDate As Date)
As Long

' Returns next number in sequence for specified date
' if external database can be opened and number obtained.
' Returns zero if unable to get next number.

Const NOCURRENTRECORD As Integer = 3021
Dim dbs As DAO.Database, rst As DAO.Recordset
Dim n As Integer, I As Integer, intInterval As Integer
Dim strSQL As String

strSQL = "SELECT * FROM tblCounter WHERE DateEntered = #" & _
Format(dtmDate,"yyyy-mm-dd") & #""

' make 10 attempts to open external database exclusively
DoCmd.Hourglass True
SysCmd acSysCmdSetStatus, "Attempting to get new number"
On Error Resume Next
For n = 1 To 10
Err.Clear
Set dbs = OpenDatabase(strCounterDb, True)
If Err = 0 Then
Exit For
Else
intInterval = Int(Rnd(Time()) * 100)
For I = 1 To intInterval
DoEvents
Next I
End If
Next n
SysCmd acSysCmdClearStatus
DoCmd.Hourglass False

If Err <> 0 Then
GetNextNumberForDate = 0
Exit Function
End If

Err.Clear

Set rst = dbs.OpenRecordset(strSQL)

With rst
.Edit
' insert new row if no existing record for this date
If Err = NOCURRENTRECORD Then
.AddNew
!DateEntered = dtmDate
!NextNumber = 1
.Update
GetNextNumberForDate = 1
Else
' update row and get next number in sequence
!NextNumber = !NextNumber + 1
.Update
GetNextNumberForDate = rst!NextNumber
End If
.Close
End With

End Function

You'd then call it in the form's BeforeInsert event procedure with:

Dim strCounterDb As String, lngID As Long

strCounterDb = <get path to external counter database form somewhere>

lngID = GetNextNumberForDate(strCounterDb, Me!DateEntered)

If lngID > 0 Then
Me!CustomerNumber = lngID
Else
MsgBox "Unable to get customer number at present.", vbInformation,
"Error"
Me.Undo
End If

Ken Sheridan
Stafford, England
Rather than use Auto Number I would like Access to automatically generate
unique customer ID's as the primary field in a customer table I'm designing.

The format for these customer ID's is: the date they were entered as a
customer + a sequentially numbered three digit extension (001, 002...999).
The final format is: MMDDYYXXX.

How is this accomplished?
 
M

mc2882

Thank you John & Ken. I have created a new field "CustomerNumber" and pasted
the code: " Me.[CustomerNumber] = Nz(DMax(""CustomerNumber",
"Customers"),0)+1 " into the validation rule for the new field and now have
an error "The expression you entered contains invalid syntax... you may have
entered an operand without an operator."

The fields (so far):
CustID* (the one I want to generate as mentioned)
CustomerNumber
FirstName
LastName
(other personal data fields follow)

What is causing the error and where do I insert the other code you have
kindly provided? Thanks.

John Spencer said:
A possible slight modification to Ken Sheridan's response.

IF you want to the sequential numbers to be sequential within a date, then

Me.[CustomerNumber] =
Nz(DMax(""CustomerNumber", "Customers","CustomerDate =Date())",0)+1

This would give you values like
092209001
092209002
...
092209055
...
092309001
092309002
092309003

John Spencer
Access MVP 2002-2005, 2007-2009
The Hilltop Institute
University of Maryland Baltimore County
Firstly I'd suggest that you have separate columns for the date and serial
number, the latter as the primary key. It’s a trivial task to concatenate
them into one computed column in a query, or a computed control in form or
report with an expression such as:

Format([DateEntered],"mmddyy") & Format([CustomerNumber],"000")

To automatically insert the current date into the DateEntered column when a
row is inserted into the table set its DefaultValue property to Date(). To
compute the next CustomerNumber in sequence data must be entered via a form.
In a single user environment simply put:

Me.[CustomerNumber] = Nz(DMax(""CustomerNumber", "Customers"),0)+1

in the form's BeforeInsert event procedure. In a multi-user environment,
however, this can cause conflicts if two or more users are adding a new
customer simultaneously. Roger Carlson has a simple solution to this at:

http://www.rogersaccesslibrary.com/...?TID=395&SID=83z7c11zc7b721d2a1e51989c53d7ffb


or there's a slightly more complex one of mine at:

http://community.netscape.com/n/pfx...yMessages&tsn=1&tid=23839&webtag=ws-msdevapps


which also allows for the next number to be used in the sequence to be
'seeded'.

I've assumed above that the CustomerNumber values will be distinct. If,
however, you want a separate sequence per DateEntered value, starting at 1
for each date, then you'd need to make the primary key a composite one of
both columns, and compute the next number for the date in question. In a
single user environment the code would be:

Dim strCriteria As String

srCriteria = "DateEntered = #" & Format(Me.DateEntered,"yyyy-mm-dd") & "#"

Me.[CustomerNumber] = _
Nz(DMax(""CustomerNumber", "Customers", strCriteria),0)+1

In a multi user environment, using my method the function to get the next
number would be:

Public Function GetNextNumberForDate(strCounterDb As String, dtmDate As Date)
As Long

' Returns next number in sequence for specified date
' if external database can be opened and number obtained.
' Returns zero if unable to get next number.

Const NOCURRENTRECORD As Integer = 3021
Dim dbs As DAO.Database, rst As DAO.Recordset
Dim n As Integer, I As Integer, intInterval As Integer
Dim strSQL As String

strSQL = "SELECT * FROM tblCounter WHERE DateEntered = #" & _
Format(dtmDate,"yyyy-mm-dd") & #""

' make 10 attempts to open external database exclusively
DoCmd.Hourglass True
SysCmd acSysCmdSetStatus, "Attempting to get new number"
On Error Resume Next
For n = 1 To 10
Err.Clear
Set dbs = OpenDatabase(strCounterDb, True)
If Err = 0 Then
Exit For
Else
intInterval = Int(Rnd(Time()) * 100)
For I = 1 To intInterval
DoEvents
Next I
End If
Next n
SysCmd acSysCmdClearStatus
DoCmd.Hourglass False

If Err <> 0 Then
GetNextNumberForDate = 0
Exit Function
End If

Err.Clear

Set rst = dbs.OpenRecordset(strSQL)

With rst
.Edit
' insert new row if no existing record for this date
If Err = NOCURRENTRECORD Then
.AddNew
!DateEntered = dtmDate
!NextNumber = 1
.Update
GetNextNumberForDate = 1
Else
' update row and get next number in sequence
!NextNumber = !NextNumber + 1
.Update
GetNextNumberForDate = rst!NextNumber
End If
.Close
End With

End Function

You'd then call it in the form's BeforeInsert event procedure with:

Dim strCounterDb As String, lngID As Long

strCounterDb = <get path to external counter database form somewhere>

lngID = GetNextNumberForDate(strCounterDb, Me!DateEntered)

If lngID > 0 Then
Me!CustomerNumber = lngID
Else
MsgBox "Unable to get customer number at present.", vbInformation,
"Error"
Me.Undo
End If

Ken Sheridan
Stafford, England
Rather than use Auto Number I would like Access to automatically generate
unique customer ID's as the primary field in a customer table I'm designing.

The format for these customer ID's is: the date they were entered as a
customer + a sequentially numbered three digit extension (001, 002...999).
The final format is: MMDDYYXXX.

How is this accomplished?
 
J

John W. Vinson

Thank you John & Ken. I have created a new field "CustomerNumber" and pasted
the code: " Me.[CustomerNumber] = Nz(DMax(""CustomerNumber",
"Customers"),0)+1 " into the validation rule for the new field and now have
an error "The expression you entered contains invalid syntax... you may have
entered an operand without an operator."

Wrong place. A validatation rule checks whether a *manually entered* value is
correct or not.

Put the code in the Form's BeforeInsert event or its BeforeUpdate event. The
latter has the advantage that it makes it less likely that two users will
overlap and get the same ID; the disadvantage is that you don't see the
customer number while editing the record.
 
M

mc2882

Thanks John, still not working. I placed the code in "Before Update" as
suggested. Nothing happens. If I don't enter data in the field, it remains
blank. If I enter data (e.g. "1") that remains. The goal is to have Access
automatically generate these number (no user interface). What am I missing?
Thanks again.
Mike

John W. Vinson said:
Thank you John & Ken. I have created a new field "CustomerNumber" and pasted
the code: " Me.[CustomerNumber] = Nz(DMax(""CustomerNumber",
"Customers"),0)+1 " into the validation rule for the new field and now have
an error "The expression you entered contains invalid syntax... you may have
entered an operand without an operator."

Wrong place. A validatation rule checks whether a *manually entered* value is
correct or not.

Put the code in the Form's BeforeInsert event or its BeforeUpdate event. The
latter has the advantage that it makes it less likely that two users will
overlap and get the same ID; the disadvantage is that you don't see the
customer number while editing the record.
 
J

John W. Vinson

Thanks John, still not working. I placed the code in "Before Update" as
suggested. Nothing happens. If I don't enter data in the field, it remains
blank. If I enter data (e.g. "1") that remains. The goal is to have Access
automatically generate these number (no user interface). What am I missing?
Thanks again.

You should not be editing this field.

Try the BeforeInsert event, my first suggestion:

Private Sub Form_BeforeInsert(Cancel as Integer)
Me!ID = NZ(DMax("ID", "tablename")) + 1
End Sub

When you "dirty" the record on the form by editing any other field on the new
record, this value will fill in.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top