Access VBA, вложенный в цикл, работает только в первой записи - PullRequest
0 голосов
/ 21 декабря 2018

У меня есть база данных Access 2010, где в одной из таблиц есть список бенефициаров и посредников.Для контроля качества мне нужно рассчитать долю владения всеми бенефициарами и опустить владение объектами, которые действуют как связи между нижними бенефициарами и высшими посредниками.Итак, у меня есть таблица с 4 столбцами посредников.Я хочу, чтобы выполнялись следующие шаги:

  1. начните со столбца "IMY_Up1", выберите номер первого промежуточного идентификатора
  2. , просмотрите второй столбец "IMY_Up2" и посмотрите, существует ли этот идентификатортам.
  3. Если это так - отредактируйте столбец «Связанный IMY» на «Да», если его нет в этом столбце - отредактируйте столбец «Связанный IMY» на «Нет».

Проблема, с которой я сталкиваюсь: Текущий код - проходит через все точно (в окне «Местные жители» отображаются «i» и «j», как и ожидалось).Но только в первой строке значение «Linked_IMy» обновлено до «Нет».

Попытка исправить: вставьте в циклы «делать, пока».Но это приводит к тому, что цикл продолжает работать, и в окне «Locals» не достигается значение «i» или «j».

Мой окончательный вопрос: как я могу изменить свой код, чтобы он выполнялся и работал как нужно?Нужно ли переделывать всю конструкцию, и если да, то как мне начать?

snippet of table structure (fake data for proprietary reasons)

Вот код VBA:

Option Compare Database
Option Explicit

Public Sub modFieldlengthRegulate()

Dim i As Integer            'set "i" as integer for IMY_Up1 loop
Dim j As Integer            'set "j" as integer for IMY_Up2 loop
Dim db As DAO.Database          'imy database
Dim rs As DAO.Recordset         'QC_LoopTestTable as recordset


Set db = CurrentDb                              'imy database
Set rs = db.OpenRecordset("QC_LoopTestTable")   'QC_LoopTestTable as recordset

For i = 0 To rs.RecordCount - 1                 'set up for IMY_Up1 loop

rs.MoveFirst                                    'always start at first row

'Do While Not rs.EOF

    'Set rs.Fields("IMY_Up1").Value = refSelect             'wanted to see what value it was assigning, but causes errors, so comment out

    For j = 0 To rs.RecordCount - 1         'set up for IMY_Up2 loop
    rs.MoveFirst
        'Do While Not rs.EOF
        'Set rs.Fields("IMY_Up2").Value = compareSelect     'wanted to see what value it was assigning, but causes errors, so comment out
            If (rs.Fields("IMY_Up2").Value = rs.Fields("IMY_Up1").Value) Then
                rs.Edit
                rs.Fields("Linked_IMY") = "Yes"
                rs.Update

            Else:
                rs.Edit
                rs.Fields("Linked_IMY") = "No"
                rs.Update
            End If
        'Loop
    Next j

'Loop
Next i


rs.Close                    'close the recordset as part of the last step
Set rs = Nothing            'close the recordset as part of the last step
db.Close                    'close the database as part of the last step

End Sub

1 Ответ

0 голосов
/ 21 декабря 2018

Использование возможностей SQL

Простой

SELECT QC_LoopTestTable.ID
    ,QC_LoopTestTable.IMY_Up1
    ,QC_LoopTestTable.IMY_Up2
    ,IIf(IsNull([QC_LoopTestTable_1].[id]), "No", "Yes") AS Linked_IMY
FROM QC_LoopTestTable
LEFT JOIN QC_LoopTestTable AS QC_LoopTestTable_1 
ON QC_LoopTestTable.IMY_Up2 = QC_LoopTestTable_1.IMY_Up1;

делает то же самое намного чище и быстрее (если индексируются IMY_Up1 и IMY_Up2).

Получает QC_LoopTestTable и присоединяется к себе (QC_LoopTestTable AS QC_LoopTestTable_1), где Up2 = Up1.Если совпадений нет, результат для скопированной таблицы (QC_LoopTestTable_1) равен NULL, что можно проверить (Iif-Statement), и используется соответствующее значение (Да / Нет).

Если выЕсли вы хотите сохранить результат Linked_IMY, вы можете использовать аналогичный запрос UPDATE, но это не рекомендуется (обычно не храните вычисленные значения), потому что если вы редактируете запись, ее нужно обновить снова.

Если IMY_Up2 совпадает с несколькими IMY_Up1, эти значения будут двойными, но при необходимости их можно отфильтровать

Почему ваш код не работает

  • Ваш код обновляетсятолько первая строка, потому что вы не указываете набор записей, чтобы перейти к следующей записи.

  • Тогда вам понадобятся два независимых набора записей, чтобы зациклить один в другом (Внутренний цикл с rs.MoveFirst также установит внешний цикл rs на первую строку (та же переменная rs))

  • После того, как вы нашли совпадение, внутренний цикл должен выйти (Exit Do), или следующий ряд вызовет возврат, поскольку он закончится Else частичной записью в Linked_IMY.

Избегайте Integer переменных, поскольку они выходят из строя выше 2 ^ 15-1, используйте Long вместо.

Используйте Do Until rs.eof ... Loop для циклического перебора наборов записей.

Код может быть таким (просто для демонстрации, не использовать ):

Dim db As DAO.Database        
Dim rs1 As DAO.Recordset         
Dim rs2 As DAO.Recordset  

Set db = CurrentDb                              
Set rs1 = db.OpenRecordset("QC_LoopTestTable")   
Set rs2 = db.OpenRecordset("QC_LoopTestTable") 

Do Until rs1.eof
  Do Until rs2.eof
    If rs1.Fields("IMY_Up2").Value = rs2.Fields("IMY_Up1").Value Then 

    ...

    End If
    rs2.MoveNext
  Loop
rs1.MoveNext
rs2.MoveFirst
Loop
...