#ms-access #vba
#ms-access #vba
Вопрос:
У меня есть отчет, который извлекает контактную информацию (имя, адрес и т.д.). Каждый контакт может быть связан с одним или несколькими округами. При разработке приложения каждый округ представляет собой поле «да» / «нет». Их примерно 70.
Чтобы этот отчет не был громоздким, вместо добавления в него 70 полей я хочу иметь текстовое поле со списком строковых значений, разделенных запятыми, для каждого из применимых округов, где значение Boolean равно true.
Я уже выполнял условное форматирование IIF раньше.
IIf([County]="True", "CountyName", "")
Но я выполнил их только в соотношении 1 к 1 (одно условие для одного поля, для одного текстового поля). Как мне применить 70 условий для 70 полей к одному текстовому полю?
РЕДАКТИРОВАТЬ: После дальнейшего обсуждения (ниже), похоже, мне нужна пользовательская функция VBA, которая перебирает поля и создает условную строку значений.
Я новичок в VBA. Я был бы признателен за любую помощь в создании функции, которая перебирает соответствующие округа в записи и создает список, разделенный запятыми.
Комментарии:
1. 70 полей — это слишком много для одного выражения. Потребуется пользовательская функция VBA. Действительно следует нормализовать структуру данных. Вместо 70 полей должна быть связанная зависимая таблица с записью для каждого округа, связанного с клиентом.
2. Я понимаю, каким это «должно» быть. Но нормализация этого приложения сейчас не обсуждается.
Ответ №1:
В этом примере предполагается, что единственными полями YesNo являются поля округа «примерно 70». Процедура может находиться в модуле отчета и вызывать функцию из текстового поля или в общем модуле и вызываться из любого места: MakeList([ID])
. В текстовом поле перед выражением поставьте знак =.
Function MakeList(intID As Integer) As String
Dim rs As DAO.Recordset
Dim strList As String
Dim x As Integer
Set rs = CurrentDb.OpenRecordset("SELECT * FROM Contacts WHERE ID=" amp; intID)
For x = 0 To rs.Fields.Count - 1
If rs(x).Type = dbBoolean Then
If rs(x) = True Then strList = strList amp; rs(x).Name amp; ","
End If
Next
If strList <> "" Then MakeList = Left(strList, Len(strList) - 1)
rs.Close
Set rs = Nothing
End Function
Альтернативой является расширение If Then
инструкции condition для исключения полей по имени, если их всего несколько. Другой способ — ссылаться на поля по индексу. Если все поля округа имеют, скажем, индекс 10-80, то For x = 10 To 80
и тест на логический тип можно исключить. Индекс начинается с 0, поэтому первое поле имеет индекс 0. Поля извлекаются в том порядке, в котором они перечислены в дизайне таблицы при использовании подстановочного знака *.
Повысьте производительность, создав объект запроса, который включает только поля ID и county, и сохраните его, а затем откройте recordset из этого запроса (или скопируйте / вставьте очень длинную инструкцию в VBA). Используйте индекс для ссылки на поля.
Комментарии:
1. Для меня это ОТЛИЧНАЯ основа! Я начну работать над этим сейчас и продолжу, как только смогу.
2. Это сработало ВЕЛИКОЛЕПНО! Однако было подчеркнуто, что полей «да» / «нет» больше, чем просто округов. Однако могу ли я просто изменить инструкцию Select? Да, это означало бы ввести 70 округов вручную — если только нет другого варианта.
3. Имеется примерно 20 дополнительных полей. Я думаю, что индекс будет работать. Я собираюсь попробовать это сейчас! Все округа расположены рядом друг с другом, так что это должно сработать. Скоро я прокомментирую обновление. Спасибо!
4. Сработало как по волшебству! Спасибо!
5. Я должен был упомянуть вариант создания объекта запроса, который извлекает только поля ID и county. Затем VBA открывает набор записей из этого запроса вместо таблицы.