У меня проблема с макросом, который я пишу для проекта, где я должен иметь возможность преобразовать запрос в sql-запрос, выполнить его и вернуть на новый лист Excel. У меня проблема с объектом, который я назвал «Результат», который должен выполнять запрос, и, в основном, остальной код, который должен позволить мне извлечь данные и поместить их на лист Excel.
У меня есть пара проблем. Сначала, после долгих исследований по этому вопросу, я добрался до следующего кода, который выдавал ошибку 3021: «Нет текущей записи».
Для небольшого контекста: Result — это объект, соединение — это тоже объект (для соединения), requete — это строка, представляющая собой SQL-запрос, который должен быть выполнен. Вывод - это вариант (если честно, я действительно не понимаю, для чего этот вывод предназначен) Я получаю сообщение об ошибке в строке "Debug.Print Result(i-1)"
Set Result = connection.Execute(requete)
Do
For i = 1 To Result.Fields.Count
Debug.Print Result(i - 1)
Output = Output & Result(i - 1) & ";"
Ws_res.Cells(1, 1).CopyFromRecordset Result
Next i
Output = Output & vbNewLine
Result.MoveNext
Loop Until Result.EOF
Итак, я снова провел небольшое исследование, и это привело меня к тому, что я сначала провел своего рода «тест» с .EOF, а затем написал остальную часть кода, чтобы попытаться получить мой запрос с помощью GetRows().
If not Result.EOF Then
Output = Result.GetRows()
nbcol = UBound(Output, 1) + 1
For i = 1 To Result.Fields.Count
For j = 1 To nbcol
Debug.Print Output(i, j)
Next j
Next i
Ws_res.Cells(1, 1) = Output
Else
MsgBox ("No Data found")
End If
Этот код работает хорошо, но он всегда дает мне «Данные не найдены». Так что я как бы застрял на этом, так как не могу знать, работает ли первый бит или нет.
Так что теперь я немного растерялся, так как не знаю, откуда берется проблема, если она из кода, набора записей или самого запроса?
Вот вся функция (я обновил бит, который вызывает у меня проблему с тем, что было предложено, но у меня снова ошибка 3021):
Function fct_resultat(fichier_type As Integer, Sql As String, rgD As Range) As Variant
Dim connection As Object
Dim Result As Object
Dim SaveName As Variant
Dim Wb_Res As Workbook
Dim Ws_res As Worksheet
Dim i As Integer, j As Integer
Dim nbcol As Integer, nbrow As Integer
Dim requete As String
Set Wb_Res = Workbooks.Add
Set Ws_res = Wb_Res.Worksheets(1)
Set connection = CreateObject("ADODB.Connection")
With connection
.Provider = "Microsoft.ACE.OLEDB.12.0"
.connectionstring = "Data Source = " & ThisWorkbook.Path & "\" & ThisWorkbook.Name & ";" & "Extended Properties = ""Excel 12.0 Xml;HDR=YES"";"
.Open
End With
requete = Sql
Set Result = connection.Execute(requete)
Do
Ws_res.Range("A1").CopyFromRecordset Result
Result.MoveNext
Loop Until Result.EOF
Кроме того, что касается самого запроса (requete), это строка, которая была построена с помощью различных функций (целью является создание запроса из входных данных пользователя). Следовательно, это переменная строка, определенная ранее в коде (у меня есть функция для моей sql_string и функция для выполнения запроса).
Вот пример строки запроса sql (я француз, что объясняет все детали на французском языке):
SELECT bps_codeFonds, Portefeuille, bps_libellePaysEmetteur,
bps_libTypeInstr, bps_libSousTypeInstr, id_inventaire,
bps_pruDevCot
FROM [Donnees$]
WHERE bps_deviseCotation = "DKK" AND
bps_quantite<10000
ORDER BY AuM ASC;
Для большего контекста: я хорошо знаком с vba и sql, но я впервые работаю с объектами, которые должны связывать два языка, поэтому, надеюсь, я не слишком запутан.
NextRecordset
используется только в том случае, если ваш запрос возвращает несколько наборов записей: вы можете игнорировать это направление. Единственный тест, который вам действительно нужен, это If Result.EOF
- если это правда, ваш запрос не дал записей. Если вы используете CopyFromRecordset
, то это считывает весь набор записей за один раз - после того, как вы вызвали, курсор вашего набора записей останется в конце записей, поэтому вы не сможете получить доступ к каким-либо записям, если сначала не вызовете (например) MoveFirst
для переместите курсор. Может быть полезно обновить ваш вопрос, чтобы добавить полный код, включая объявления ваших переменных.
Большое спасибо за быстрый ответ! Для теста с If Result.EOF мой запрос не вернул никакой записи? Если да, то есть ли у вас какие-либо идеи о том, что я сделал неправильно и как я могу изменить код, чтобы получить свои данные?
Этот код работает для меня:
Sub Tester()
fct_resultat "select * from [Donnees$] where false"
End Sub
'Your Function returns no result, so make it a Sub...
Sub fct_resultat(Sql As String)
Dim connection As Object, Result As Object, SaveName As Variant
Dim Wb_Res As Workbook, Ws_res As Worksheet
Set Wb_Res = Workbooks.Add
Set Ws_res = Wb_Res.Worksheets(1)
Set connection = CreateObject("ADODB.Connection")
With connection
.Provider = "Microsoft.ACE.OLEDB.12.0"
.connectionstring = "Data Source = " & ThisWorkbook.FullName & ";" & _
"Extended Properties = ""Excel 12.0 Xml;HDR=YES"";"
.Open
Set Result = .Execute(Sql)
End With
If Not Result.EOF Then
'This copies the content of the entire recordset,
' so there's no need to use it in a loop
Ws_res.Range("A1").CopyFromRecordset Result
Else
Ws_res.Range("A1").Value = "No results"
End If
End Sub
Если ваш конкретный SQL не возвращает никаких результатов, вам нужно проверить свои данные, чтобы убедиться, что в них действительно есть совпадающие записи.
Требуется только одна строка
Ws_res.Range("A1").CopyFromRecordset connection.Execute(requete)