Неожиданное поведение с запросами ADO в Excel (сложный вопрос) - PullRequest
0 голосов
/ 26 февраля 2020

Я сталкиваюсь с неожиданной ошибкой при запросе разных таблиц с помощью 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 есть что-то, что мешает корректной загрузке данных позже.

Есть идеи?

В любом случае, спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...