Vba access выполнить запрос: Метод DoCmd.OpenQuery (Access) | Microsoft Learn

Pers.narod.ru. Обучение. Access VBA — редактируем связь многие-ко-многим и программно выполняем запрос с параметрами формы


Pers.narod.ru. Обучение. Access VBA — редактируем связь многие-ко-многим и программно выполняем запрос с параметрами формы

Этот сайт больше не обновляется. Подключите Javascript, чтобы увидеть новый адрес страницы или перейдите к статье


Pers.narod.ru. Обучение. Access VBA — редактируем связь многие-ко-многим и программно выполняем запрос с параметрами формы

Статья написана в учебных целях, хотя в ней есть и пара интересных неучебных нюансов.

Постановка проблемы: мы хотим динамически редактировать в Access связи между 2 таблицами, объединенными
отношением «многие ко многим» (например, теги и слова,
помеченные тегами, студенты и дисциплины, которые они посещают, или просто абстрактные «объекты» и
«категории»). Думаю, понятно, что «многие ко многим» означает, что один объект может относиться к
нескольким категориям и, наоборот, одной категории соответствует несколько объектов.

Классический способ реализации такой связи — промежуточная таблица, хранящая внешние ключи
категорий и объектов и реализующая, таким образом, две связи «один ко многим», на которые мы разложили
наше отношение:

Сама по себе реализация такого редактора в Access несложна, вот весь процесс.

1. Создаем новую базу данных и сохраняем ее.

2. В окне базы данных на вкладке «Таблицы» создаем в режиме конструктора 3 таблицы:

  • таблица «Категории» будет включать поле «Код категории», имеющее тип «Счетчик» и текстовое поле «Категория», служащее для описания; щелкнув правой кнопкой на поле «код», сделаем его ключевым:
  • таблица «Объекты» будет устроена аналогично: она включает ключевое поле-счетчик с именем «Код объекта» и текстовое поле «Объект», предназначенное для данных;
  • наконец, таблица «Связи» состоит из двух числовых полей, показанных ниже:

Обратите внимание, что оба поля я сделал ключевыми — это поможет избежать дублирования связей — например, объект 1 не должен иметь две одинаковых связи с категорией 1.
Чтобы сделать оба поля ключевыми, нужно при нажатой клавише Ctrl выделить их, щелкая по области ключа,
а затем вызвать правой кнопкой пункт меню.

3. Идем Сервис, Схема данных…, добавляем в окно схемы все 3 таблицы и связываем их, перетаскивая поля мышкой так,
чтобы получились связи, показанные на первом рисунке. В появившемся окне «Изменение связей» нужно включить все флажки для
обеспечения целостности данных при добавлении или удалении записей.

4. Закрыв и сохранив схему, вносим по несколько записей в таблицы «Категории» и «Объекты».

5. Формы для работы с категориями и объектами по отдельности или в связке «главная и подчиненная таблица»
сделать легко. Для последнего, например,
достаточно перейти на вкладку Формы, вызвать Мастер форм, добавить для формы все поля таблиц «Категории» и «Объекты»,
а на следующем шаге определить главную и починенную формы. Но нас интересует сейчас не это. Главное, что мы
хотим сделать — спроектировать форму «Связи» для редактирования наших данных.

6. Вызываем Конструктор форм, получаем новую пустую форму. Если окна «Раздел: область данных»
(на самом деле это окно свойств) нет на экране, вызываем его, выбрав в окне формы правой кнопкой мыши
пункт меню Свойства.

7. В выпадающем списке окна свойств выбираем «Форма» и назначаем на вкладке Данные нашей форме источником данных таблицу «Связи».

8. С помощью меню Вид, Панель элементов убеждаемся, что панель с интерфейсными элементами доступна. Находим
на ней элемент «Список» и добавляем его на форму, при этом должен вызваться мастер «Создание списков»:

Если мастера для этого или других элементов не вызываются, причин может быть 2: не нажата кнопка «Мастера»
на Панели элементов или не установлены соответствующие компоненты Access.

Подтверждаем, что список использует данные из таблицы или запроса, на следующем шаге выбираем таблицу «Категории»,
затем включаем в список оба ее поля, на следующем шаге подтверждаем скрытие ключевого столбца,
еще на одном шаге выбираем вариант «Сохранить в поле» и поле «Код категории», наконец,
делаем разумную подпись, например, «Выбор категории». В окне свойств на закладке «Другие» дадим списку
удобное название, например, СписокКатегории.

9. Аналогичным образом создаем список для отображения объектов из таблицы «Объекты», а называться
он будет «СписокОбъекты».

10. В принципе, все готово. Наша форма работает, в чем можно убедиться, открыв ее кнопкой Вид

Проблема состоит в том, что при повторном добавлении связи Access начинает ругаться стандартными
сообщениями («Изменения не были внесены из-за повторяющихся значений в индексе…») и, более того,
не дает сохранить последние внесенные изменения. Напишем небольшую процедуру на VBA для решения проблемы и
лучшей обработки записей.

11. Вернувшись в режим конструктора, добавим на свободное место кнопку и с помощью мастера «Создание кнопок»
назначим ей действие «добавить запись» из категории действий «Обработка записей». Все остальное можно
настроить по вкусу.

12. При выбранной кнопке в окне свойств перейдем на вкладку События и обратимся к коду сгенерированного
нами обработчика:

13. Мы перепишем код сгенерированной Access процедуры так, чтобы он отслеживал ситуацию, когда в списках
категорий и объектов ничего не выбрано, а также не давал повторно добавить уже существующую связь.
Для последнего действия нам понадобиться выполнить из кода на VBA дополнительный запрос по извлечению
выбранных на форме кода категории и кода объекта из таблицы «Связи».
Если этот запрос вернет пустой результат, значит, такой связи еще нет и следует добавить запись.
Сгенерировать такой запрос на вкладке
«Запросы» и потом просто вызвать его, к сожалению, не получится. Дело в том, что Access не видит
взятых из формы параметров запроса, если запрос выполняется программно.
Ошибка, как правило, возникает со следующим текстом «Too few parameters. Expected Число» («Слишком мало параметров. Ожидалось Число»).
Эта ошибка возникает, если команда или один из нижележащих запросов содержит обращения к формам или собственные параметры, —
все эти обращения будут восприняты как параметры, которым не передано значение.

Почему так происходит?
По этому поводу в справке Microsoft MSDN написано примерно следующее:


NOTE: В DAO Вы должны явно присвоить значение параметру.
При использовании DoCmd.OpenQuery Вы этого делать не должны, т.к.
DAO использует операции низкого уровня, что даёт Вам большую свободу
в использовании параметров (т.е. Вы можете сами присвоить параметру
значение переменной, а не использовать ссылку на форму), но Вы должны
выполнить служебные действия, которые Access делает «за кулисами»
при исполнении DoCmd. С другой стороны, DoCmd работает на более
высоком уровне, чем DAO. Выполняя DoCmd, Microsoft Access делает
некоторые предположения о том, как поступить с параметрами, и не дает
Вам никакой свободы в этом отношении.

Попросту говоря, при выполнении запроса непосредственно из окна Access он выполняется с помощью
движка JET, который, будучи встроен в Access, «знает» о наличии форм и пытается найти их поля
и подставить значения. При выполении запроса из кода методом Execute или иным, запрос выполняется с помощью
библиотеки DAO, которая, будучи внешней, ничего «не знает» о формах ACCESS, поэтому все недостающие
значения считает неопределенными.

В Интернете можно встретить советы предварительно обработать все параметры процедурой вида


Dim q As DAO.QueryDef, p As DAO.Parameter 
  Set q = CurrentDb.QueryDefs("ИмяЗапроса") 'как обычного запроса Select,
  'так и INSERT/UPDATE; в запросах на удаление это не помогает
  For Each p In q.Parameters 
    p.Value = Eval(p.Name) 
  Next 
  q.Execute 
  q.close: Set q=Nothing

Однако, для работы этого кода нужно, во-первых, иметь подключенную DAO
(в окне редактора Visual Basic при остановленной программе вызвать Tools, References (или Сервис, Ссылки),
найти и включить в списке библиотеку Microsoft DAO 3.6 Object Library), во-вторых, работа кода все-таки
не гарантируется и в этом случае.

Мы хотим обойтись стандартным кодом


Dim rst As Recordset
CurrentDb.OpenRecordset ("строка запроса")

однако, едва избавившись от ошибок с недостающимим параметрами, получим сообщение о нессответствии типов (type mismatch, ошибка с кодом 13)!

Вся проблема состоит в том, что объект RecordSet есть и в библиотеке DAO, и в используемой
Access по умолчанию библиотеке ADODb! Таким образом, наличие прямой ссылки на DAO, как в показанной выше
процедуре, не гарантирует работоспособность кода — может возникать куча заморочек, связанных с тем,
какая библиотека подключена в данный момент и у какой выше приоритет.

Поискав (и не найдя) ответ по всему Интернету я догадался, наконец, описать RecordSet как Variant,
то есть, без указания типа:


 Dim rs


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


Private Sub КнопкаДобавить_Click()
If ([Forms]![Связи]![СписокКатегории] 

Нам остается отключить для формы встроенную навигацию (свойства "Область выделения" и "Кнопки перехода" со вкладки "Макет" окна свойств формы), добавить с помощью мастера свою навигацию и получить работающее приложение.

Кстати, стандартные сообщения для кнопок навигации, генерируемые Access, можно заменить на свои более осмысленные, например, код


MsgBox Err.Description

на


 MsgBox "Достигнуто начало базы данных", vbOKOnly, "Сообщение" 

Это пример можно скачать и доделать, ведь область применения отношений "многие-ко-многим" так же широка,
как сами эти отношения.

Скачать редактор связи "многие-ко-многим": base_mn.zip, 32 Кб





Запросы на изменение Access — Базы данных Access

В этой статье поговорим про запросы на изменение Access. К запросам на изменение относятся запросы на обновление данных в записях таблицы базы, на добавление и удаление записей из таблицы, а также запросы на создание таблицы из записей, сформированных в нем.
Чтобы создать запросы на изменение Access, используется конструктор. Процесс создания любого запроса на изменение начинается с создания запроса на выборку, который после добавления в него необходимых таблиц преобразуется в нужный запрос на изменение.
По умолчанию Access 2010 в целях обеспечения безопасности, как правило, блокирует выполнение всех запросов на изменение. Если при выполнении запроса на изменение ничего не происходит, проверьте, не появляется ли в строке состояния Access сообщение: «Данное действие или событие заблокировано в режиме отключения».
Если отображается это сообщение и панель сообщений (Message Bar) (рис. 4.39), для включения заблокированных запросов можно нажать на ней кнопку Включить содержимое (Enable content). После этого выполнение запроса будет доступным.

Если панель сообщений была закрыта и больше не отображается, перейдите на вкладку Файл (File) и на открытой странице Сведения (Info) в блоке Предупреждение системы безопасности (Security Warning) нажмите кнопку Включить содержимое (Enable Content) (рис. 4.40).

В открывшемся списке (рис. 4.41) можно Включить все содержимое (Enable All Content) открытой базы данных. Это приведет к тому, что при повторных открытиях базы ни панели сообщения, ни сообщений о невозможности выполнения запроса действия выводиться не будет, т. к. база данных будет отнесена к разряду надежных. То же самое происходит, если была нажата кнопка Включить содержимое (Enable content) на панели сообщений.
Выбор строки Дополнительные параметры (Advanced Otions) открывает окно параметров безопасности Microsoft Office, в котором можно включить опасное содержимое только на время сеанса. При следующем открытии базы данных опять появится панель сообщений и, если не включать содержимое, запросы действия выполняться не будут.

Чтобы вернуть возможность управления содержимым, откройте окно Параметры Access (Access Options) соответствующей командой на вкладке ленты Файл (File), щелкните на строке Центр управления безопасностью (Trust Center) и далее по кнопке Параметры центра управления безопасностью (Trust Center Settings). В окне центра на странице Надежные документы (Trusted Documents) в строке Сбросить пометку о надежности для всех надежных документов (Cliar all Trusted Documents so that they are no longer trusted) нажмите кнопку Очистить (Clear).

ВНИМАНИЕ!
Единое средство вывода предупреждений системы безопасности — панель сообщений — по умолчанию появляется при открытии базы данных Access 2010 вне доверенного расположения. Если точно известно, что можно доверять содержимому базы данных, включите все отключенные потенциально опасные активные компоненты — запросы на изменение, макросы, элементы управления ActiveX, некоторые выражения и программы на VBA — при открытии базы данных, содержащей один или несколько этих компонентов.

Для закрепления смотрим видеоурок:

Далее узнаем про запрос на создание таблицы Access.

Метки: MS Access, MS Access 2010, Видео, Запросы

admin

Проблемы с базой данной Access? Не можете сдать курсовую и получить зачет? Заходите в группу ВКонтакте vk.com/access_community. Поможем!

sql — MS Access — выполнить сохраненный запрос по имени в VBA

спросил

Изменено
2 года, 3 месяца назад

Просмотрено
146 тысяч раз

Как выполнить сохраненный запрос в MS Access 2007 в VBA?

Я не хочу копировать и вставлять SQL в VBA. Я скорее просто выполняю имя запроса.

Это не работает… VBA не может найти запрос.

 CurrentDb.Execute имя_запроса
 
  • sql
  • ms-access
  • vba

Вы можете сделать это следующим образом:

 DoCmd.OpenQuery "yourQueryName", acViewNormal, acEdit
 

ИЛИ

 CurrentDb.OpenRecordset("yourQueryName")
 

4

Вы должны выяснить, почему VBA не может найти имя_запроса .

У меня есть сохраненный запрос с именем qryAddLoginfoRow . Он вставляет строку с текущим временем в мою таблицу loginfo . Этот запрос выполняется успешно при вызове по имени с помощью CurrentDb.Execute .

 CurrentDb.Execute "qryAddLoginfoRow"
 

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

Редактировать :
Вам нужно найти способ признать, что queryname не существует в текущей коллекции QueryDefs базы данных. Добавьте эти две строки в свой код VBA непосредственно перед строкой CurrentDb.Execute .

 Debug.Print "имя_запроса = '" & имя_запроса & "'"
Debug.Print CurrentDb.QueryDefs(имя_запроса).Имя
 

Вторая из этих двух строк вызовет ошибку времени выполнения 3265, « Элемент не найден в этой коллекции. » Затем перейдите в окно «Интерпретация», чтобы проверить имя запроса, который вы задаете CurrentDb От до Выполнить .

2

Чтобы использовать CurrentDb.Execute, ваш запрос должен быть запросом действия И заключен в кавычки.

 CurrentDb.Execute "имя_запроса"
 

Существует 2 способа запуска Action Query в MS Access VBA:


  1. Вы можете использовать оператор DoCmd. OpenQuery . Это позволяет вам контролировать эти предупреждения:

НО! Имейте в виду, что DoCmd.SetWarnings останется установленным даже после завершения функции. Это означает, что вам нужно убедиться, что вы оставляете его в состоянии, которое соответствует вашим потребностям

 Функция RunActionQuery (имя_запроса как строка)
    При ошибке GoTo Hell 'Set Error Handler
    DoCmd.SetWarnings True 'Включить предупреждения
    DoCmd.OpenQuery QueryName 'Выполнить запрос действия
    DoCmd.SetWarnings False 'Включить предупреждения
    Выход из функции
Ад:
    Если Err.Number = 2501, то «Если запрос был отменен
        MsgBox Err.Description, vbInformation
    Остальное 'Все остальное
        MsgBox Err.Description, vbCritical
    Конец, если
Конечная функция
 

  1. Вы можете использовать метод CurrentDb.Execute . Это позволяет вам сохранять ошибки Action Query.
    под контролем. Флаг SetWarnings на это не влияет. Запрос выполняется всегда без предупреждений.
 Функция RunActionQuery()
    'Чтобы поймать ошибку запроса, используйте опцию dbFailOnError
    При ошибке отправляйтесь в ад
    CurrentDb.Execute "Query1", dbFailOnError
    Выход из функции
Ад:
    Debug.Print Err.Description
Конечная функция
 

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

Зарегистрируйтесь или войдите в систему

Зарегистрируйтесь с помощью Google

Зарегистрироваться через Facebook

Зарегистрируйтесь, используя электронную почту и пароль

Опубликовать как гость

Электронная почта

Обязательно, но не отображается

Опубликовать как гость

Электронная почта

Требуется, но не отображается

Метод Database.

Execute (DAO) | Microsoft Узнайте

Редактировать

Твиттер

LinkedIn

Фейсбук

Электронная почта

  • Статья

Применяется к : Access 2013, Office 2013

Запускает запрос действия или выполняет оператор SQL для указанного объекта.

Синтаксис

выражение .Execute( Запрос , Опции )

выражение Переменная, представляющая объект базы данных .

Параметры

Запрос

Обязательно

Строка

Опции

Дополнительно

Вариант

Для параметров можно использовать следующие константы RecordsetOptionEnum .

dbDenyWrite

Отказывает другим пользователям в разрешении на запись (только для рабочих областей Microsoft Access).

дБНепоследовательный

(по умолчанию) Выполняет несогласованные обновления (только для рабочих областей Microsoft Access).

dbConsistent

Выполняет согласованные обновления (только для рабочих областей Microsoft Access).

dbSQLPassThrough

Выполняет сквозной запрос SQL. При установке этого параметра инструкция SQL передается в базу данных ODBC для обработки (только для рабочих областей Microsoft Access).

dbFailOnError

Откат обновлений в случае возникновения ошибки (только для рабочих областей Microsoft Access).

dbSeeChanges

Генерирует ошибку времени выполнения, если другой пользователь изменяет данные, которые вы редактируете (только для рабочих областей Microsoft Access).

дбрунасинк

Выполняет запрос асинхронно (только объекты ODBCDirect Connection и QueryDef).

dbExecDirect

Выполняет оператор без предварительного вызова функции SQLPrepare ODBC API (только для объектов ODBCDirect Connection и QueryDef).

Примечание

Рабочие области ODBCDirect не поддерживаются в Microsoft Access 2013. Используйте ADO, если вы хотите получить доступ к внешним источникам данных без использования ядра базы данных Microsoft Access.

Примечание

Константы dbConsistent и dbInconsistent являются взаимоисключающими. Вы можете использовать один или другой, но не оба в данном экземпляре OpenRecordset . Использование dbConsistent и dbInconsistent приводит к ошибке.

Метод Execute действителен только для запросов действий. Если вы используете Выполнить с запросом другого типа, возникает ошибка. Поскольку запрос действия не возвращает никаких записей, Execute не возвращает Recordset . (Выполнение сквозного запроса SQL в рабочей области ODBCDirect не возвращает ошибку, если набор записей не возвращается.)

Используйте свойство RecordsAffected соединения Connection , Database или QueryDef объект, чтобы определить количество записей, затронутых самым последним методом Execute . Например, RecordsAffected содержит количество записей, удаленных, обновленных или вставленных при выполнении запроса действия. Когда вы используете Выполнить метод для выполнения запроса, свойство RecordsAffected объекта QueryDef установлено на количество затронутых записей.

В рабочей области Microsoft Access, если вы предоставляете синтаксически правильный оператор SQL и имеете соответствующие разрешения, метод Execute не даст сбой, даже если ни одна строка не может быть изменена или удалена. Поэтому всегда используйте параметр dbFailOnError при использовании метода Execute для выполнения запроса на обновление или удаление. Этот параметр генерирует ошибку времени выполнения и откатывает все успешные изменения, если какая-либо из затронутых записей заблокирована и не может быть обновлена ​​или удалена.

В более ранних версиях ядра базы данных Microsoft Jet операторы SQL автоматически внедрялись в неявные транзакции. Если часть оператора, выполненного с ошибкой dbFailOnError , завершилась неудачей, будет выполнен откат всего оператора. Для повышения производительности эти неявные транзакции были удалены, начиная с версии 3.5. Если вы обновляете старый код DAO, обязательно рассмотрите возможность использования явных транзакций вокруг операторов Execute .

Для лучшей производительности в рабочей области Microsoft Access, особенно в многопользовательской среде, вложите Выполнить метод внутри транзакции. Используйте метод BeginTrans для текущего объекта Workspace , затем используйте метод Execute и завершите транзакцию, используя метод CommitTrans для Workspace . Это сохраняет изменения на диске и освобождает любые блокировки, установленные во время выполнения запроса.

Пример

Этот пример демонстрирует метод Execute при запуске как из объекта QueryDef , так и из объекта QueryDef .0057 Объект базы данных . Для запуска этой процедуры необходимы процедуры ExecuteQueryDef и PrintOutput.

 Подпрограмма ExecuteX()

Dim dbsNorthwind как база данных
Dim strSQLChange As String
Dim strSQLRestore As String
Dim qdfChange As QueryDef
Dim rstEmployees как набор записей
Dim errLoop как ошибка

' Определите два оператора SQL для запросов действия.
strSQLChange = "ОБНОВЛЕНИЕ Сотрудники НАБОР Страна = " & _
"'Соединенные Штаты', ГДЕ Страна = 'США'"
strSQLRestore = "ОБНОВЛЕНИЕ Сотрудники НАБОР Страна = " & _
"'США', ГДЕ Страна = 'Соединенные Штаты'"

Установите dbsNorthwind = OpenDatabase("Northwind.mdb")
' Создать временный объект QueryDef.
Установите qdfChange = dbsNorthwind.CreateQueryDef("", _
стрSQLChange)
Установите rstEmployees = dbsNorthwind.OpenRecordset(_
"ВЫБЕРИТЕ Фамилию, Страну ОТ Сотрудников", _
dbOpenForwardOnly)

' Распечатать отчет исходных данных.
Отладка.Печать _
"Данные в таблице "Сотрудники" перед выполнением запроса"
PrintOutput

' Запустить временный QueryDef.
ExecuteQueryDef qdfChange, rstEmployees

' Распечатать отчет о новых данных.
Отладка.Печать _
"Данные в таблице "Сотрудники" после выполнения запроса"
PrintOutput

' Запустить запрос действия для восстановления данных. Ловушка для ошибок,
' проверка коллекции Errors при необходимости.
При ошибке Перейти к Err_Execute
dbsNorthwind.Execute strSQLRestore, dbFailOnError
При ошибке Перейти к 0

' Получить текущие данные, повторно запросив набор записей.
rstEmployees.Requery

' Распечатать отчет о восстановленных данных.
Debug.Print "Данные после выполнения запроса" &_
"восстановить исходную информацию"
PrintOutput

rstEmployees.Close

Выйти из подпрограммы

Err_Execute:

' Уведомлять пользователя обо всех ошибках, возникших в результате
' выполнение запроса.
Если DBEngine.Errors.Count > 0 Тогда
Для каждого errLoop в DBEngine.Errors
MsgBox "Номер ошибки: " & errLoop. Number & vbCr & _
errLoop.Описание
Следующий цикл ошибок
Конец, если

Возобновить Далее

Конец сабвуфера

Sub ExecuteQueryDef (qdfTemp As QueryDef, _
rstTemp как набор записей)

Dim errLoop как ошибка

' Запустить указанный объект QueryDef. Ловушка для ошибок,
' проверка коллекции Errors при необходимости.
При ошибке Перейти к Err_Execute
qdfTemp.Execute dbFailOnError
При ошибке Перейти к 0

' Получить текущие данные, повторно запросив набор записей.
rstTemp.Requery

Выйти из подпрограммы

Err_Execute:

' Уведомлять пользователя обо всех ошибках, возникших в результате
' выполнение запроса.
Если DBEngine.Errors.Count > 0 Тогда
Для каждого errLoop в DBEngine.Errors
MsgBox "Номер ошибки: " & errLoop.Number & vbCr & _
errLoop.Описание
Следующий цикл ошибок
Конец, если

Возобновить Далее

Конец сабвуфера

Sub PrintOutput (rstTemp As Recordset)

' Перечислить набор записей.