MS Access VBA - отображение динамически построенных результатов SQL в подформе таблицы данных

у меня есть несколько лет опыта работы с VBA в приложениях MS Office (для автоматизации и процессов ETL), но до недавнего времени у меня не было необходимости возиться с формами в MS Access. Я разрабатываю дизайн для некоторых простых форм извлечения данных для базы данных, которую я разработал, и зависаю от того, что кажется простой задачей.

цель: мне нужна подформа datasheet для отображения записей, возвращаемых из динамически построенного оператора SQL из элементов управления на главном форма.

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

независимо от того, что я делаю, я не могу заставить это работать. Я продолжаю получать (большую часть времени в любом случае) ошибку времени выполнения microsoft visual basic "2467": введенное выражение относится к объекту, который закрыт или нет существовать."Это ошибка, которую я получаю с кодом, показанным ниже. Я не могу понять, нужно ли мне как-то инициировать подформу, как только какой-либо код запускается или что. Я пробовал некоторые другие варианты кода, которые также не работали с других форумов кода, но я, похоже, нашел несколько потоков форума, включая некоторые из переполнения стека, которые предполагают, что код, который я ниже, должен работать.

прикрепленное изображение показывает, как выглядит основная основная форма. Я обозначил кнопку, которую пользователь щелкните (btnDisplaySWData), чтобы скомпилировать SQL, который получает create из еще не включенных элементов управления, но это не проблема. Я просто жестко кодирую инструкцию SQL, как показано в фрагменте кода, пытаясь выяснить эту проблему. Как уже упоминалось, я хочу, чтобы записи отображались в подформе с именем dataDisplaySubform. "Мусор" - это таблица в базе данных Access, которую я могу законно запросить с помощью кода SQL ниже, который я просто использую для тестирования, пока не выясню это. Весь код в показанная форма данных (с именем frmDataExtract) состоит из того, что находится в окне кода ниже. enter image description here

Option Compare Database
Option Explicit
Public Sub btnDisplaySWData_Click()
    Dim pSQL As String
    pSQL = "SELECT JUNK.agency_ID, JUNK.agency_desc FROM JUNK"
    Me.dataDisplaySubform.Form.RecordSource = pSQL
End Sub

форма называется dataDisplaySubform, как показано на приведенном ниже скриншоте свойств с выбранной подформой.

enter image description here

вот как выглядит общий макет формы

enter image description here

Я просмотрел несколько сайтов форума, а также попробовал все варианты терминов с поиском переполнения стека, чтобы найти потенциальные решения для моей проблемы, но никто не работал, даже когда исходный поток был помечен как решенный человеком, который его разместил. Я потратил слишком много времени, около 2 РАБОЧИХ дней, пытаясь понять, что я делаю неправильно, и еще не смог.

Я ценю всех, кто может помочь направить меня в правильном направлении, это сводит меня с ума.

спасибо, -- ТБ

РЕШЕНИЕ РЕДАКТИРОВАТЬ TURKISHGOLD

Ну, я думаю, я понял это сам по себе, хотя HansUp помог мне спуститься по пути с упоминанием исходного объекта subform, не имеющего ничего назначенного ему. В моем случае назначение исходного объекта форме не было правильным решением, которое предлагал HansUp. Вместо этого сохраненный запрос, похоже, заставляет его делать то, что я хочу.

не уверен, что есть лучший способ сделать это, но кажется, что вам нужно настроить фиктивный, почти заполнитель запроса, чтобы вы могли установить исходный объект subform в VBA. Такой запрос-заполнитель:

SELECT * FROM JUNK WHERE JUNK.agency_ID ="_";

вышеуказанный запрос доступа сохраняется как имя "TESTQUERY". Он ничего не отображает, но удовлетворяет потребности в назначении исходного объекта чему-либо, по существу, создавая экземпляр подформы при просмотре основной формы в виде формы. Таким образом, с сохраненным запросом-заполнителем вы можете переназначить RecordSource на любую строку SQL, собранную с помощью элементов управления пользовательского интерфейса в основной форме, например это:

Public Sub btnDisplaySWData_Click()
    Dim pSQL As String
    pSQL = "SELECT JUNK.agency_ID, JUNK.agency_desc FROM JUNK"
    Me.dataDisplaySubform.SourceObject = "Query.TESTQUERY"
    Me.dataDisplaySubform.Form.RecordSource = pSQL
    Me.dataDisplaySubform.Requery
End Sub

который, когда форма находится в производстве, показанная жестко закодированная инструкция SQL, хранящаяся в строковой переменной pSQL, будет собрана с помощью пользовательского ввода на элементах управления в основной форме.

Итак, теперь, когда btndisplayswdata нажата, она делает то, что я пытался сделать, и отображает записи. enter image description here

4 ответов


если "объект, который закрыт или не существует" ошибка возникает на Me.dataDisplaySubform.Form.RecordSource line, скорее всего, ваш subform управления не назван dataDisplaySubform.

вы можете проверить имена всех элементов управления подформы вашей формы с этим временным изменением кода ...

'Me.dataDisplaySubform.Form.RecordSource = pSQL
Dim ctl As Control
For Each ctl In Me.Controls
    If TypeName(ctl) = "SubForm" Then
        Debug.Print ctl.Name, TypeName(ctl)
    End If
Next
Stop

на Stop оператор вызовет режим отладки (break) и приведет вас к немедленному окну, где вы можете просмотреть имена вашей формы управление(ы) подформы.

скриншот, добавленный к вопросу, подтверждает, что вы используете правильное имя для элемента управления подформы. Однако эта подформа не имеет ничего в своем Источник собственность. Поскольку там нет формы, вторая часть сообщения об ошибке,"нет", относится. Нет формы, на которую можно ссылаться Me.dataDisplaySubform.Form


некоторые уточняющие моменты для других читателей:

свойство sourceobject подформы подробного представления определяет, какие столбцы / поля отображаются. Таким образом, вы можете установить его в таблицу или запрос, а затем использовать фильтр для возврата записей (Если вы хотите, чтобы набор записей был изначально пустым) или в качестве альтернативы использованию recordSource для пользовательского SQL.

источником записей может быть любая таблица, запрос или SQL, но подформа будет отображать только поля с именами, соответствующими поля sourceObject. Это может привести к путанице, если, например, вы установите sourceObject в таблицу, а recordSource в запрос с частично перекрывающимися именами полей (Access отобразит все столбцы, но только перекрывающиеся будут иметь данные в них).

чтобы иметь форму, которая отображает произвольный оператор SELECT или позволяет пользователю выбирать, какую таблицу(ы) выбрать, можно сохранить их ввод в качестве нового запроса (или иметь существующий именованный для перезаписи), а затем установить sourceObject для этого (форма должна быть закрыта, а затем снова открыта для отображения новых столбцов, поэтому вы можете открыть всплывающую или новую вкладку для отображения результатов).


использовать CreateQueryDef а то
Me.dataDisplaySubform.SourceObject = "Query.NewqueryName"
NewQueryName - это имя, данное при создании с помощью createQueryDef


коротким и сладким. Вот код кнопки, которая создает динамическую строку sql, закрывает текущий объект (на случай его открытия), удаляет временное определение запроса (потому что оно нам нужно), создает новое определение запроса с новым sql, изменяет recordsource и Ваш дядя Боба.

Private Sub btnRunSQL_Click()
  'my subform is called datasheet, i know -- dumb name.
  'a dynamic sql needs to be saved in a temporoary query. I called my qtemp
  Dim sql As String
  sql = "select * from client order by casename asc"
  'in case there is something kicking around, remove it first, otherwise we can't delete the temp query if it is still open
  Me!Datasheet.SourceObject = ""
  'delete our temporary query. Note, add some err checking in case it doesn't exist, you can do that on your own.
   DoCmd.DeleteObject acQuery, "qtemp"
  'lets create a new temporary query
  Dim qdf As QueryDef

  Set qdf = CurrentDb.CreateQueryDef("qtemp", sql)
  'set the subform source object
  Me!Datasheet.SourceObject = "query.qtemp"
  'and it should work.
End Sub