2015-04-29 2 views
0

Я пытаюсь устранить существующее приложение базы данных Access, которое должно генерировать случайное число от 1 до количества записей в таблице. Это делается для двух разных таблиц с различным количеством записей. Таблицы с меньшим количеством записей отображают повторяющиеся числа из 10, которые должны отображаться и записываться в отдельную таблицу. Я предполагаю, что то же самое произойдет с большими таблицами, но с большим количеством номеров на выбор, я просто не смог дублировать проблему.Создать случайное число без дублирования

Вот примеры кода с обработкой ошибок удалены:

Dim db As DAO.Database 
Dim rstRecords As DAO.Recordset 
Dim rs As DAO.Recordset 
Dim tdfNew As TableDef 
Dim fldNew As Field 
Dim i As Integer 
Dim K As Integer 
Dim Check As String 

Set db = CurrentDb 
Set rstRecords = db.OpenRecordset("customer_table") 

    rstRecords.MoveLast 
    FindRecordCount = rstRecords.RecordCount 
    i = rstRecords.RecordCount 
DoCmd.DeleteObject acTable, "Unique_numbers" 

'--- create the table 
Set tdfNew = db.CreateTableDef("Unique_numbers") 
'--- add text field (length 20) 
Set fldNew = tdfNew.CreateField("customer_table", dbLong) 
'--- save the new field 
tdfNew.Fields.Append fldNew 

'--- save the new table design 
db.TableDefs.Append tdfNew 

'---Initialize your recordset 
Set rs = CurrentDb.OpenRecordset("Unique_numbers", dbOpenDynaset) 


'Dim i As Integer 
'Dim K As Integer 
'Dim Check As String 

'i = TxtInput 
    TxtInput = i 
    K = 0 
    Check = T 

Do 
    Do While K < 11 
    'K = K + 1 
     Randomize 
      If K = 0 Then 
      TxtOutput = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput 
      rs.Update 
      K = K + 1 
      ElseIf K = 1 Then 
      TxtOutput2 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput2 
      rs.Update 
      K = K + 1 
      ElseIf K = 2 Then 
      TxtOutput3 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput3 
      rs.Update 
      K = K + 1 
      ElseIf K = 3 Then 
      TxtOutput4 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput4 
      rs.Update 
      K = K + 1 
      ElseIf K = 4 Then 
      TxtOutput5 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput5 
      rs.Update 
      K = K + 1 
      ElseIf K = 5 Then 
      TxtOutput6 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput6 
      rs.Update 
      K = K + 1 
      ElseIf K = 6 Then 
      TxtOutput7 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput7 
      rs.Update 
      K = K + 1 
      ElseIf K = 7 Then 
      TxtOutput8 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput8 
      rs.Update 
      K = K + 1 
      ElseIf K = 8 Then 
      TxtOutput9 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput9 
      rs.Update 
      K = K + 1 
      ElseIf K = 9 Then 
      TxtOutput10 = Fix(i * Rnd) + 1 
      rs.AddNew 
      rs.Fields(0).Value = TxtOutput10 
      rs.Update 
      K = K + 1 
      Check = f 
      Exit Do 
      End If 
    Loop 
Loop Until Check = f 
+0

Что означает 'Check = T'?Определяется ли 'T' где-то? – HansUp

+0

Почему цикл с структурой If/ElseIf, которая делает что-то уникальное для каждого индекса цикла? Я полагаю, что это стилистический вопрос, но он делает код намного дольше, чем нужно. –

+0

Самый честный ответ, который я могу вам дать, это «Я не знаю, я его не писал». Я просто пытаюсь исправить проблему случайного числа без воссоздания колеса. Если это нужно изменить, я изменю его, но я не чувствую необходимости делать это по причинам стиля. – Scottdg

ответ

1

Обратите внимание, что функция Randomize VBA повторно инициализирует случайное число семян генератора. Без презервативов он использует системный таймер в качестве семени.

Вы повторно инициализируете его каждую итерацию цикла, перед каждым вызовом Rnd. Учитывая, что между вызовами Randomize может быть не так много времени, вы можете снова и снова перезапускать генератор случайных чисел в одной и той же точке, что приводит к повторным номерам.

Попробуйте вызвать Randomize один раз в верхней части вашего кода.

+0

Спасибо Jeff - Я пробовал это, и он все еще не работает. – Scottdg

+0

Хм ... Сколько дубликатов за запуск? Всегда существует хорошая вероятность дублирования, поскольку Rnd не обеспечивает уникальность (и это особенно ясно, когда вы умножаете небольшое число строк и обрезаете целое число). Вам нужно произвольно выбирать без замены (например, перетасовку колоды карт) вместо того, чтобы делать то, что вы делаете сейчас (это как выбор карты, замена ее в колоде и повторное рисование)? –

+0

Мне нужно случайно выбрать без замены. Но только для каждого прогона. При следующем нажатии кнопки число может быть выбрано снова. – Scottdg

0

Создание случайного числа не является проблемой. Создание случайного уникального номера также не является проблемой. Однако выбор случайного числа из диапазона, который не был выбран, уже требует отслеживания используемых чисел. Проблема заключается в том, когда дело доходит до производительности, особенно если вы хотите читать/обновлять значения из таблицы и проверять, был ли ID уже использован.

У вас есть два варианта. (возможно, больше того, о чем я не могу сейчас думать)

  • Если вы используете VBA для обновления таблицы. Вы можете создать публичную функцию с открытым массивом, содержащий список используемых и неиспользуемых номеров.
  • Если вы используете SQL-запрос для обновления таблицы снова, вы можете использовать открытую функцию для получения случайного числа, но вместо массивов вы будете выполнять случайный выбор, если идентификатор условия, который еще не используется в новой таблице.

Первый способ будет выглядеть так: Вы отправляете минимальные и максимальные значения из своего диапазона и получаете значение обратно, которое еще не используется. Массив или держатель будут использоваться для отслеживания используемых вами и неиспользуемых номеров. Я использовал словарь, но вы можете использовать массивы или массивы со словарем.

Option Compare Database 
Option Explicit 

Private mNumbers As Object 
Private mSession_ID As Long 

Public Function FN_GET_RANDOM_NO(iMin As Long, iMax As Long) As Long 
    FN_GET_RANDOM_NO = Int((iMax - iMin + 1) * Rnd + iMin) 
End Function 

Public Function FN_RANDOM_INIT_COLLECTION(iSession_id As Long, iMin As Long, iMax As Long) As Object 
    Set mNumbers = CreateObject("Scripting.Dictionary") 
    Dim i, J As Long 
    mSession_ID = iSession_id 
    J = 0 
    For i = iMin To iMax 
     J = J + 1 
     mNumbers.Add J, i 
    Next i 
End Function 

Public Function FN_RANDOM_READ_UNUSED_NO() As Long 
    Dim ID As Long 
    ID = FN_GET_RANDOM_NO(1, mNumbers.count) 
    FN_RANDOM_READ_UNUSED_NO = mNumbers(ID) 
    If mNumbers.exists(ID) Then mNumbers.Remove ID 

    Dim tmpDic As Object 
    Set tmpDic = CreateObject("Scripting.Dictionary") 

    Dim item As Variant 
    Dim i As Long 
    i = 0 
    For Each item In mNumbers 
     i = i + 1 
     tmpDic.Add i, mNumbers(item) 
    Next item 

    Set mNumbers = tmpDic 

End Function 
Public Function FN_GET_UNUSED_NO(iSession_id As Long, iMin As Long, iMax As Long) As Long 
    If mSession_ID = iSession_id Then 
     If Not mNumbers Is Nothing Then 
READ_AFTER: 
      FN_GET_UNUSED_NO = FN_RANDOM_READ_UNUSED_NO 
     Else 
INIT: 
      'initialize the table 
      FN_RANDOM_INIT_COLLECTION iSession_id, iMin, iMax 
      GoTo READ_AFTER: 
     End If 
    Else 
     'new session reload the used number collection 
     Set mNumbers = Nothing 
     GoTo INIT 
    End If 
End Function 

получить случайный уникальный идентификатор образуют диапазон просто:

FN_GET_UNUSED_NO(1,10, 50) 

session_id есть, чтобы определить, вы получаете доступ к коллекции в течение одной сессии. Другой идентификатор будет инициализировать неиспользуемую таблицу. Разверните код, если вы хотите управлять несколькими коллекциями. Может быть, с массивом.

он вернет 0, если числа больше не возвращаются.

результат будет выглядеть следующим образом:

?FN_GET_UNUSED_NO(1,10, 50) 
0 
10 
50 
11 
16 
40 
18 
25 
22 
33 
30 
14 
26 
49 
45 
39 
20 
35 
17 
15 
38 
27 
48 
12 
43 
24 
46 
37 
41 
28 
31 
34 
19 
47 
29 
13 
21 
44 
36 
32 
23 
42 

второй метод достаточно прост: Вы прочтете случайное значение, проверьте, если значение уже назначен в новой таблице.

+0

Поскольку данные записываются в таблицу каждый раз в цикле, мне интересно, как бы я попросил его проверить столбец, чтобы увидеть, существует ли новое назначенное значение, прежде чем записывать его в таблицу. – Scottdg

Смежные вопросы