У меня есть данные, хранящиеся в файлах Excel, и я пытаюсь выполнить SQL запросов к ним с помощью VBA. Проблема в том, что данные, с которыми я работаю, довольно грязные, и, к сожалению, мой контроль над их содержимым очень ограничен. Из-за этого Excel сходит с ума и постоянно присваивает столбцам неверный тип данных.
Лучше всего я предполагал, что тип определяется значением в первой строке таблицы. Но, к сожалению, поведение действительно непредсказуемо, и это не всегда так. Вот пример:
![enter image description here](https://i.stack.imgur.com/iaSAn.png)
У меня есть столбцы со строками и пустыми значениями, нулями или ошибками. Эти столбцы обрабатываются как двойной вместо текста. И из-за этого каждое не числовое значение в этом столбце стирается после выполнения CopyFromRecordset
. У меня также есть столбцы с числами и случайными пустыми значениями, а затем столбец обрабатывается как текст.
Он связывается с запросами SQL с предложениями WHERE
или JOIN
. Потому что, если я сделаю сравнение строк в столбце с типом double, это не сработает. То же самое, если это происходит в обратном порядке, если я пытаюсь сравнить числа в строковом столбце.
Иногда проблемы можно избежать, задав правильное форматирование для проблемных c столбцов, иногда записав что-то еще в первой строке , Но, как я уже сказал, это действительно непредсказуемо, а иногда и не работает.
Пробовал что-то вроде этого (после таблица типов ):
dbRecordset.Fields(2).Type = 200
Но я получаю Operation is not allowed when the object is open
.
Я также пытался выполнить ручное преобразование внутри запроса SQL, но мне кажется, что он намного медленнее, а синтаксис действительно грязный. Например, здесь утверждается тип double (и это только один столбец, у меня есть еще пара десятков):
Cdbl(IIf(IsNull(c.[Column4]), 0, c.[Column4])) > 0
Итак, есть ли способ сообщить Excel, какой тип данных находится внутри каждого столбца? ИЛИ как избежать моих проблем?
Вот мой код:
Option Explicit
Sub RunCopy()
Dim dbConnection As Object
Dim dbRecordset As Object
Dim strSQL As String
Dim dbField As Variant
Dim fieldCounter As Long
Dim src_wks As Worksheet
Dim dst_wks As Worksheet
Set src_wks = Worksheets("Src")
Set dst_wks = Worksheets("Dst")
Set dbConnection = CreateObject("ADODB.Connection")
Set dbRecordset = CreateObject("ADODB.Recordset")
' CONNECTION WITH EXCEL ODBC DRIVER
dbConnection.Open "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" _
& "DBQ=" & ThisWorkbook.FullName & ";"
' OPEN RECORDSET
dst_wks.UsedRange.Clear
dbRecordset.Open "SELECT d.* FROM [Src$] d WHERE d.[Column4] > 0", dbConnection
dbRecordset.Fields(2).Type = 200
With dst_wks
' HEADERS
fieldCounter = 0
For Each dbField In dbRecordset.Fields
fieldCounter = fieldCounter + 1
.Cells(1, fieldCounter).Value = dbField.name
Next dbField
' DATA ROWS
.Range("A2").CopyFromRecordset dbRecordset
End With
dbRecordset.Close
dbConnection.Close
Set dbRecordset = Nothing: Set dbConnection = Nothing
End Sub