Hi Bob,
It gets a little involved to prevent duplicates over more than one
quarter. The following will do so until it cannot prevent them, then it will
prevent them to the extent it can. So if you already have 12 quarters worth
of data (840 numbers) it will prevent for the prior 11 quarters. I am
presuming that by three digits you want to use only 100-999. If that is not
the case, you can adjust the following as needed. This assumes the presence
of SurveyYear, SurveyQuarter and SurveyNumber fields in your table.
=====================================
Public Sub GenerateSurveyNumbers(ByVal intSurveyYear As Integer, ByVal
intSurveyQuarter As Integer, ByVal intNumbersToGenerate)
Const cintLowerBound As Integer = 100
Const cintUpperBound As Integer = 999
Const cintMaximumNumbers As Integer = cintUpperBound - cintLowerBound + 1
Dim cnnCurrent As ADODB.Connection
Dim rstSurveyInfo As New ADODB.Recordset
Dim boolarrNumberUsed(cintLowerBound To cintUpperBound) As Boolean
Dim intIndex As Integer
Dim intNumberCount As Integer
Dim intNumbersUsed As Integer
Dim intSurveyNumber As Integer
Dim strWhere As String
Set cnnCurrent = CurrentProject.Connection
If intNumbersToGenerate >= 1 And intNumbersToGenerate <=
cintMaximumNumbers Then
' Remove any existing records for the specified year and quarter;
allows rerunning of process
cnnCurrent.Execute _
"delete from 64EmpSurveyNumbers " & _
"where SurveyYear = " & intSurveyYear & " and SurveyQuarter =
" & intSurveyQuarter, , adCmdText
' Figure out how many surveys' information to preload so as to avoid
the same numbers, at least for a time
With rstSurveyInfo
.Open _
"select SurveyYear, SurveyQuarter, count(*) as NumberCount "
& _
"from 64EmpSurveyNumbers " & _
"where SurveyNumber between " & cintLowerBound & " and " &
cintUpperBound & " " & _
"group by SurveyYear, SurveyQuarter " & _
"order by SurveyYear desc, SurveyQuarter desc", _
cnnCurrent, adOpenStatic, adLockReadOnly, adCmdText
intNumbersUsed = intNumbersToGenerate
Do While Not .EOF
intNumberCount = .Fields("NumberCount").Value
If intNumbersUsed + intNumberCount > cintMaximumNumbers Then
Exit Do
End If
intNumbersUsed = intNumbersUsed + intNumberCount
.MoveNext
Loop
If .EOF Then
' Plenty of numbers left; preload all survey numbers
strWhere = ""
Else
.MovePrevious
If .BOF Then
' Only one survey, which did not leave enough numbers
for this one; do not preload any
strWhere = "SurveyYear is null and "
Else
' Only preload surveys after this year and quarter
strWhere = _
"(SurveyYear > " & .Fields("SurveyYear").Value & "
or (SurveyYear = " & _
.Fields("SurveyYear").Value & " and SurveyQuarter
= " & .Fields("SurveyQuarter").Value & ")) and "
End If
End If
.Close
' Initialize the array
For intIndex = cintLowerBound To cintUpperBound
boolarrNumberUsed(intIndex) = False
Next intIndex
' Block out the existing numbers
.Open _
"select SurveyYear, SurveyQuarter, SurveyNumber " & _
"from 64EmpSurveyNumbers " & _
"where " & strWhere & "SurveyNumber between " &
cintLowerBound & " and " & cintUpperBound, _
cnnCurrent, adOpenDynamic, adLockOptimistic, adCmdText
Do While Not .EOF
boolarrNumberUsed(.Fields("SurveyNumber").Value) = True
.MoveNext
Loop
' Now generate random numbers until the needed unique quantity
has been reached
Randomize Now()
intNumberCount = 0
Do Until intNumberCount >= intNumbersToGenerate
' Use the handy formula from help on Rnd() function
' To produce random integers in a given range, use this
formula:
' Int((upperbound - lowerbound + 1) * Rnd + lowerbound)
intIndex = Int((cintUpperBound - cintLowerBound + 1) * Rnd()
+ cintLowerBound)
If Not boolarrNumberUsed(intIndex) Then
' An unused number
.AddNew
.Fields("SurveyYear").Value = intSurveyYear
.Fields("SurveyQuarter").Value = intSurveyQuarter
.Fields("SurveyNumber").Value = intIndex
.Update
boolarrNumberUsed(intIndex) = True
intNumberCount = intNumberCount + 1
End If
Loop
.Close
End With
Set rstSurveyInfo = Nothing
MsgBox "Numbers generated."
Else
MsgBox "Bad input."
End If
Set cnnCurrent = Nothing
End Sub
=============================================
To use it, copy the code to a new module or an existing one that is not
a form or report module. Then on a form create an On Click event for a
button and that event's VBA code call the routine. Something like:
Private Sub cmdGenerateSurveyNumbers_Click()
GenerateSurveyNumbers 2008, 4, 70
End Sub
Obviuosly you will want to replace the 2008 and 4 and maybe the 70 with
text boxes from the form; into which the user would specify the values to use.
Hope that helps,
Clifford Bass