#excel #vba #ms-access #ms-access-2010 #dao
#excel #vba #ms-access #ms-access-2010 #dao
Вопрос:
Я нахожусь в Excel 2010 VBA, используя ADO 2.8 для запроса базы данных Access 2010. Я не владею базой данных и не имею никаких полномочий вносить в нее какие-либо изменения. Я много лет работаю с Excel VBA, но мои знания Access отрывочны.
Используя тот же SQL, что и один из запросов в базе данных (скопированный из запроса Access и вставленный в Excel VBA), я получаю в некоторых полях результаты, отличные от результатов, полученных этим запросом в базе данных.
Для затронутых полей я вижу, что в Access эти поля определены как поисковые запросы. Вот пример поиска из свойства источника строки одного из затронутых полей:
SELECT [Signers].[SignerID], [Signers].[SignerName] FROM Signers ORDER BY [SignerID], [SignerName];
В базе данных Access, где инструкция SQL ссылается на это поле, запрос возвращает SignerName.
Но в моем коде ADO, где тот же самый оператор SQL ссылается на это поле, запрос возвращает SignerID, а не SignerName.
Могу ли я что-нибудь сделать из своего кода ADO, чтобы получить SignerName вместо SignerID из того же оператора SQL? Или мне нужно изменить инструкцию SQL?
Спасибо,
Грег
Обновить:
На стороне доступа, я думаю, теперь я понимаю, почему отображается только имя входа. На вкладке поиска поля свойство Ширины столбца:
0″;1.2605″
Итак, я предполагаю, что SignerID присутствует в результате запроса Access, но с шириной столбца 0.
К сожалению, это не помогает мне на стороне ADO. Есть предложения по получению имени пользователя вместо SignerID в результате запроса ADO?
Обновление2:
Вот пример инструкции SQL, которая возвращает разные поля в зависимости от того, находится ли она в Access или в ADO:
SELECT MasterAccount.[SignerKey1]
FROM MasterAccount ;
По запросу Preet вот код ADO в Excel VBA:
strDatabasePath = rgDatabasePathCell.Value 'rgDatabasePathCell is a worksheet cell object.
strPWD = DATABASE_PASSWORD
Set cnn = New ADODB.Connection
cnn.Provider = "Microsoft.ACE.OLEDB.12.0"
cnn.ConnectionString = "Data Source='" amp; strDatabasePath amp; "';Jet OLEDB:Database Password='" amp; strPWD amp; "';"
cnn.Open
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnn
cmd.CommandType = adCmdText
cmd.CommandText = strSQL
Set rst = New ADODB.Recordset
rst.Open cmd.Execute
shMA.Cells(2, 1).CopyFromRecordset rst 'shMA is a worksheet object.
Обновление 3:
Мне пришло в голову, что из того, что я сказал до сих пор, может показаться, что я мог бы просто изменить это:
SELECT MasterAccount.[SignerKey1]
FROM MasterAccount ;
to this:
SELECT [Signers].[SignerName]
FROM MasterAccount ;
Но есть 13 затронутых полей поиска, все с точно таким же текстом свойства «Источник строки», как показано выше, и все возвращают разные элементы SignerName для каждой строки. Я не знаю, почему все они возвращают разные элементы в строке; Я не смог найти никакой разницы в том, как они определены. Мне было поручено получить тот же результат в Excel, что и в запросе Access.
Обновление 4:
VBlades — Спасибо, я нашел форму, в которой есть вкладка с выпадающими списками для каждого из 13 полей SignerKey-n. Если я щелкну правой кнопкой мыши по этой форме и выберу Свойства формы, свойство RecordSource будет:
SELECT MasterAccount.*, Bank.BankRating FROM Bank INNER JOIN MasterAccount ON Bank.BankID = MasterAccount.Bank;
Однако я не понимаю, как это будет означать выбор другого элемента SignerName для каждого из 13 полей SignerKey-n или что делать с этой информацией, чтобы получить те же результаты в ADO, что и в запросе Access. Есть предложения?
Обновление 5:
Возможно, я близок к обходному пути. Если я сделаю это, я получу поле имени входа для SignerKey1:
SELECT Signers.SignerName
FROM Signers RIGHT JOIN MasterAccount ON Signers.SignerID = MasterAccount.SignerKey1.Value;
И если я это сделаю, я получу разные элементы имени входа для каждого поля в каждой строке:
SELECT Signers.SignerName, Signers_1.SignerName, Signers_2.SignerName
FROM Signers AS Signers_2 INNER JOIN (Signers AS Signers_1 INNER JOIN (Signers RIGHT JOIN MasterAccount ON Signers.SignerID = MasterAccount.SignerKey1.Value) ON Signers_1.SignerID = MasterAccount.SignerKey2.Value) ON Signers_2.SignerID = MasterAccount.SignerKey3;
Это работает как в запросе Access, так и в ADO. Следующим шагом я попытаюсь добавить эти объединения в основной оператор SQL.
Обновление 6:
Ну, когда я пытаюсь добавить хотя бы одно из этих 13 соединений к основному оператору SQL, оно отлично работает в запросе Access, но в ADO я получаю ошибку:
Все дескрипторы строк должны быть освобождены, прежде чем можно будет получить новые.
Итак, я застрял. Есть предложения?
Я поднял проблему с владельцем базы данных, но они не знают, почему свойство источника строк затронутых полей включает SignerID, поэтому я не уверен, поможет ли это.
Комментарии:
1. Есть ли шанс, что вы можете поместить оба набора кода здесь, пожалуйста?
2. Привет, Прит — вы имеете в виду инструкцию SQL? Я добавил пример выше.
3. Привет, Прит. Я добавил код ADO из Excel VBA. Кода DAO нет. На стороне Access нет кода; это просто запрос в Access.
4. Спасибо. Интересно… возможно, если бы вы попробовали следующее: напишите некоторый код DAO в vba и убедитесь, что вы получаете те же данные в каждой строке / столбце, что и Ado? Тогда, возможно, повторите тест из другого приложения Vba — скажем, другого экземпляра Access? Я думаю, что это не проблема DAO / ADO, а скорее что-то в том, как Access внутренне выдает запрос. Также я вижу, что вы добавили еще один запрос. Можете ли вы повторить ошибку со свежей базой данных Access и указать примерные данные?
5. Привет, Прит — Спасибо, но я не понимаю, какое это имеет отношение к DAO. Кода DAO нет. В Excel VBA есть код ADO и есть запрос Access (никакого кода, кроме инструкции SQL; просто запрос в Access). Вместо того, чтобы тратить время на переписывание кода ADO как устаревшего кода DAO, я собираюсь попробовать переписать инструкцию SQL, чтобы избежать столбцов поиска.
Ответ №1:
Вы можете сделать следующее (самый простой способ)
Исключить [Signers].[SignerID]
из запроса
SELECT [Signers].[SignerName] FROM Signers ORDER BY [SignerID], [SignerName];
Или создайте составное поле, содержащее оба [SignerID]
, [Имя пользователя] и извлеките любую часть с помощью VBA, с которой вы знакомы:
SELECT ([SignerID] amp; "_" amp; [SignerName]) As Composite FROM Signers ORDER BY [SignerID], [SignerName]
С уважением,
Комментарии:
1. Алекс — спасибо, но у меня нет контроля над базой данных Access, поэтому я не могу исключить [подписантов]. [SignerID], который находится в свойстве «Источник строки» затронутых полей поиска в базе данных Access. Я могу управлять оператором SQL, который я использую в своем коде ADO, из Excel VBA, но [Подписчики]. [Идентификатор подписи] там не отображается.
Ответ №2:
Хорошо, я решил проблему, получив отдельный набор записей полей SignerID и SignerName из таблицы подписантов.
Затем я перебрал все строки каждого затронутого поля, нашел идентификатор подписи во 2-й таблице и заменил имя подписи на идентификатор подписи в исходной таблице.
Я попытался сделать это в ADO, но получил сообщение об ошибке «Запрос НА ОБНОВЛЕНИЕ или УДАЛЕНИЕ не может содержать многозначное поле». Поэтому вместо этого я произвел замены после копирования набора записей на лист Excel.
Я хотел бы знать, как справиться со всем этим в ADO, но это работает. Теперь все хорошо.