Я сталкиваюсь с неожиданной ошибкой при запросе разных таблиц с помощью OLEDB + ADODB в Excel VBA. Извините, если некоторые функции / переменные находятся в испанском sh. Я перевел большую часть этого.
Чтобы стабилизировать sh соединение, я создал класс соединения с подпрограммой подключения, как показано ниже.
Option Explicit
Dim cn As ADODB.Connection
Dim rs As ADODB.recordset
Private Sub Connect()
Dim strFile As String
Dim strCon As String
strFile = ThisWorkbook.FullName
strCon = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & strFile & ";Extended Properties=""Excel 12.0 Macro;HDR=Yes"";"
Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")
cn.Open strCon`enter code here`
[...]
End Sub
У меня также есть несколько методов для запроса объектов Excel: Первый, который запускает запрос на выборку
Public Function ExecSQL(Sql As String) As ADODB.recordset
rs.Open Sql, cn, adOpenStatic
Set ExecSQL = rs
End Function
и Второй, чтобы получить адрес таблицы (для ясности я конвертирую диапазоны в таблицы, поэтому получаю адрес таблицы для запроса). Sqls похожи на это: «Выбрать поля из» + GetTableAddress (tableName)
Public Function GetTableAddress(tableName as String) As String
Dim oSh As Worksheet
Dim oLo As ListObject
Dim Direccion As String
Direccion = ""
For Each oSh In ThisWorkbook.Worksheets
For Each oLo In oSh.ListObjects
If oLo.Name = tableName Then
Direccion = Replace(oSh.ListObjects(tableName).Range.AddressLocal, "$", "")
Direccion = oSh.Name + "$" + Direccion
End If
Next
Next
GetTableAddress = "[" + Direccion + "]"
End Function
Но когда я заполняю таблицы, я делаю это из соединения с базой данных в Excel. Итак, у меня есть класс подключения к базе данных, который запрашивает сервер SQL (в этом сценарии):
Основные методы (также возобновленные в качестве примера) здесь:
Public Sub Conecta(Servidor As String, Login As String, Pass As String, Libreria As String, ConSegura As Boolean)
Dim rs As ADODB.recordset
Dim Ini As Single
sError = ""
Server = Servidor
Set Conexion = New ADODB.Connection
Conexion.ConnectionString = strMontarCad(Login, Pass, Server, Libreria, ConSegura)
Conexion.CommandTimeout = 0
Conexion.ConnectionTimeout = 0
Ini = Timer
Conexion.Open
ExecuteQuery "Set transaction isolation level read uncommitted"
ExecuteQuery("Select GetDate()")(0)
Exit Sub
End Sub
Таким образом, чтобы выполнить запросы к классу базы данных, я использую следующие методы. В зависимости от того, нужен ли мне возвращаемый набор записей ...
Public Function ExecuteQuery(Sql As String) As ADODB.recordset
sError = ""
Set InnerRS = New ADODB.recordset
InnerRS.CacheSize = 30
InnerRS.Open Sql, Conexion, adOpenForwardOnly, adLockBatchOptimistic, adAsyncFetch
Set ExecuteQuery = InnerRS
Exit Function
End Function
И этот второй, когда у меня есть временные таблицы, так Я могу получить окончательный SQL как набор записей. Эта функция имеет разницу. Как у меня есть разделитель. Это разделяет sqls, поэтому я могу запустить создание временных таблиц и некоторые другие sqls, а в конце запросить результат из того же соединения. SQL запускаются. Я получаю данные, но. Когда я запрашиваю таблицы позже с помощью OLEDB, как указано выше, происходит сбой.
Public Function ExecuteQueryLectura(Sql As String) As ADODB.recordset
If InStr(Sql, QuerySeparator) > 0 Then
Dim Trozo() As String
Dim Parcial As Integer
Trozo = Split(Sql, QuerySeparator)
For Parcial = LBound(Trozo) To UBound(Trozo) - 1
ExecuteSQL Trozo(Parcial)
Next
sError = ""
Set InnerRS = New ADODB.recordset
InnerRS.CacheSize = 30
InnerRS.Open Trozo(UBound(Trozo)), Conexion, CursorTypeEnum.adOpenStatic, adLockReadOnly, adAsyncFetch
Else
sError = ""
Set InnerRS = New ADODB.recordset
InnerRS.CacheSize = 30
InnerRS.Open Sql, Conexion, CursorTypeEnum.adOpenStatic, adLockReadOnly, adAsyncFetch
End If
ExecuteQueryLectura = InnerRS
Exit Function
End Function
Поэтому, когда мне нужно заполнить таблицу, я делаю это следующим образом:
Private Function FillTabla(Pagina As Worksheet, Fila As Long, Columna As Long, Conexion As ClsConexionSQLServer, OBjSQL As ClsSQLs, PageName As String) As Long
Dim rs As ADODB.recordset
Dim LastCol As Long
Dim cols As Long
Set rs = Conexion.ExecuteQueryLectura(OBjSQL.TextoSQL)
For cols = Columna To rs.Fields.Count + Columna - 1
Pagina.Cells(Fila, cols).value = rs.Fields(cols - Columna).Name
Next
Pagina.Cells(Fila + 1, Columna).CopyFromRecordset rs.Clone
DoEvents
FormatAsTable Fila, Columna, Pagina, PageName & OBjSQL.Sigla
LastCol = Columna + rs.Fields.Count
DoEvents
FillTabla = PosicionColumna
End Function
Итак, я запускаю несколько sqls для SQL Сервера, затем загружаю таблицы Excel набором записей. Excel, который я прочитал снова с sql, чтобы заполнить больше таблиц.
Суть в том, что он отлично работает, когда у SQL нет разделителя. Я заполняю таблицу с SQL сервера. И я могу запросить таблицу Excel с помощью простого выбора. Но когда у sql есть разделитель, и я заполняю таблицу из SQL Server предыдущим запуском SQL (например, для создания временной таблицы) Это не так. Он не может найти данные таблицы. (И лист заполнен этими данными). Кажется, я что-то там упустил, но не могу узнать, что.
Ошибка чтения (Другой пример)
Механизму базы данных Microsoft Access не удалось найти объект 'Presup $ A3: E83945'. Убедитесь, что объект существует, и что вы правильно написали его имя и путь. Если 'Presup $ A3: E83945' не является локальным объектом, проверьте подключение к сети или обратитесь к администратору сервера
Конечно, существует лист и есть данные. Видимый. Но в некоторой степени это не может найти это. Я пытался, Unisisting Listobjects, открытие и закрытие соединения Excel ... Без удачи. При разделении сервера SQL на SQL есть что-то, что мешает корректной загрузке данных позже.
Есть идеи?
В любом случае, спасибо.