[AccessD] Custom autonumbering

Gustav Brock Gustav at cactus.dk
Thu Jul 2 11:28:23 CDT 2009


Hi Asger

As this is Access, why not use DAO which is ultra-fast?

I brushed up a function we used many years ago for a similar purpose. It simply adds 1 to obtain the next number. Of course, it can be modified to use any other calculation for the next sequential number and formatting for string expressions can be applied as well if the sequential number is alpha-numeric.

In general, the use of DMax or the like is fine in a single-user environment but it has the drawback that once the table is read and the number is found, the table is released while you calculate the next number. When you wish to save this, anything can have happened to the table and you may end up with duplicate numbers or cumbersome error handling routines.


<code>
Public Function GetSequentialNo() As Long

' Creates and returns a new sequential number in table tblSequential.
' Works in a multi-user environment as well.
'
' Table schema:
'   Id: AutoNumber, primary key.
'   SequentialNo: Long, unique key.
'
' 2009-07-02. Cactus Data ApS, CPH.

  ' Initial value for the sequential number.
  ' Only used once - when the table is empty.
  Const clngNoInitial As Long = 1000
  
  Dim dbs       As DAO.Database
  Dim rst       As DAO.Recordset
  
  Dim strSQL    As String
  Dim booEmpty  As Boolean
  Dim lngIdLast As Long
  Dim lngIdNext As Long
  Dim lngNo     As Long
  
  strSQL = "Select Top 1 * From tblSequential Order By Id Desc"
  
  Set dbs = CurrentDb
  Set rst = dbs.OpenRecordset(strSQL)
  
  With rst
    booEmpty = Not CBool(.RecordCount)
    If Not booEmpty Then
      ' Read last used Id and sequential number.
      lngIdLast = .Fields("Id").Value
      lngNo = .Fields("SequentialNo").Value
    End If
  ' To demonstrate multi-user behaviour with asynchronous ("overlapping")
  ' creation of records, open two or more instances of the database and
  ' uncomment this line:
  ' Stop
    .AddNew
      If Not booEmpty Then
        ' Calculate next sequential number.
        lngIdNext = .Fields("Id").Value
        lngNo = lngNo + lngIdNext - lngIdLast
      Else
        ' Use initial sequential number.
        lngNo = clngNoInitial
      End If
      ' Store the new sequential number.
      .Fields("SequentialNo").Value = lngNo
    .Update
    .Close
  End With
  
  Set rst = Nothing
  Set dbs = Nothing
  
  GetSequentialNo = lngNo

End Function

</code>

For a high-speed system you would consider making the dbs and rst objects static.

/gustav


>>> ab-mi at post3.tele.dk 02-07-2009 02:13 >>>
David, I always use an AutoNumber as my PKID, and not my generated number.
My original posting was:
/*
Using Autonumber for surrogate primary keys, I often need to manage custom
autonumbering for alternate unique keys, e.g. for order numbers.
I know this subject has been discussed several times before, but I couldn't
find exactly what I was looking for in the archive.
How do you manage custom autonumbering?

I do it this way, which may not be the most efficient, so I'm calling for
other suggestions:
1. On the form I set the property DefaultValue at design-time for the
control holding the custom autonumbering field to:
=DMAX(<field>,<table>) + 1
This will do in single-user environments, but will invite duplicate values
in multi-user environments.
So I use this run-time code in addition to the design-time DefaultValue:
2. Assuming the custom autonumbering field is called OrderNumber in a table
called tblOrders:
Private Sub Form_BeforeUpdate(Cancel As Integer)
   Dim intOrderNumber_Default As Integer
   Dim intOrderNumber_RunTime As Integer
   If NewRecord Then
      intOrderNumber_Default = OrderNumber.Value
      intOrderNumber_Runtine = DMAX("OrderNumber","tblOrders") + 1
      If intOrderNumber_Runtime <> intOrderNumber_Default Then
         OrderNumber.Value = intOrderNumber_Runtime
         MsgBox "Another user has created a new order with the number " & _
                intOrderNumber_Default & vbNewline & _
                "Your order has got the number " & intOrderNumber_Runtime
      End If
   End If
End Sub
Do you think this solution has any pitfalls, or do you just have another
more efficient/intelligent custom autonumbering?
/*

Your suggestion using a second table equals Drew's proposal, but it doesn't
satisfy my requirement of a customisable alternate key, on which I was not
enough explicit in my first posting.

Asger


-----Oprindelig meddelelse-----
Fra: accessd-bounces at databaseadvisors.com 
[mailto:accessd-bounces at databaseadvisors.com] På vegne af David McAfee
Sendt: 2. juli 2009 01:28
Til: Access Developers discussion and problem solving
Emne: Re: [AccessD] Custom autonumbering

Asger, just make sure to use an autonumber as your PKID, not your generated number.

If at some later point in life, the criteria changes for the number, so be it. You PKs & FKs will love you for it.

You can create a table for the sequence number by inserting a value into a record with only an Autonumber PK and some other field.

I had a request where the facility request numbers were the date and a sequence of 3 digits ( 20090701001-20090701999)

I created a sequence table and have a job that truncated that table each night at midnight.

You need to know what happens if a number is in process of being created and a second user creates a new number but the first user/process cancels.

Will you leave a hole?

Will you save the record and flag it as cancelled?

What if user 2 fnishes before user 1, does it matter if they are out of sequence, yet the numbers are sequential?

David





More information about the AccessD mailing list