Эта проблема связана с тем, как механизм ACE
определяет тип поля ADODB
. Драйвер просканирует определенное количество строк, чтобы определить, какой тип должен быть для всего столбца.
Изменение строки подключения
Одна быстрая вещь, которую вы можете попробовать, это изменить MaxScanRows
на 0 в строке подключения. Установка этого значения в 0 будет сканировать все строки, чтобы определить тип, имейте в виду, что это может повлиять на производительность в зависимости от размера вашего набора данных.
";Extended Properties='text;MaxScanRows=0;IMEX=0'"
Это не всегда даст вам желаемый результат. Скажем, у нас есть такой набор данных:
+--------------------------+
| DoubleField |
+--------------------------+
| 1 |
| 2 |
| 3 |
| ...(996 more records...) |
| 1000.01 |
+--------------------------+
Драйвер будет смотреть и видеть 999 записей, которые выглядят как целое число, и 1 запись, которая выглядит как двойное число. Это поле будет определяться на основе MajorityType
, это целое число, а не двойное число. Если честно, я не совсем уверен , как это определение типа выполнено точно, но это что-то в этом роде. Я также видел случаи, когда сработала бы простая замена верхней записи на нужный вам тип. Э.Г.
+--------------------------+
| DoubleField |
+--------------------------+
| 1.00 |
| 2 |
| 3 |
| ...(996 more records...) |
| 1000.01 |
+--------------------------+
Таким образом, другой подход может заключаться в том, чтобы отформатировать исходный файл, чтобы включить десятичные разряды заранее. Это должно быть достаточно легко сделать, если вы управляете исходным файлом, но это не всегда так.
Использовать INI-файл схемы
Если повышение MaxScanRows
не работает, то для получения ожидаемого типа для каждого столбца необходимо использовать файл Schema.ini, как указано Comintern .
Вот ссылка , которая проходит через это.
Суть, создать файл, который явно определяет каждый тип для каждого столбца. Для нашей надуманной таблицы выше это становится:
[MyFileNameGoesHere.csv]
ColNameHeader = True
Format = CSVDelimited
Col1=DoubleField Double
Затем вы сохраните этот файл как Schema.Ini
и поместите его в тот же каталог, где находится файл, который вы хотите импортировать. Хорошая особенность этого подхода в том, что он просто создает текстовый файл, вы даже можете сделать это в VBA без особых проблем. Недостатком этого подхода является то, что если у вас есть много файлов для импорта, может быть сложно управлять всеми файлами Schema.ini.
Подход чисто VBA
Вы можете создать таблицу в памяти в ADODB
и заполнить ее данными из файла csv. Вот небольшой пример кода, с которого можно начать.
Option Explicit
Private Function getTypedRS() As ADODB.Recordset
Set getTypedRS = New ADODB.Recordset
With getTypedRS
'Add your other fields here
.Fields.Append "DoubleField", adDouble
End With
End Function
Public Sub CSVToADODB()
Dim myTimer As Double
Dim FileNumber As Long
Dim FilePath As String
Dim FileData As String
Dim CSVArray As Variant
Dim i As Long
Dim rs As ADODB.Recordset
myTimer = Timer
Set rs = getTypedRS()
FilePath = "C:\Users\Ryan\Desktop\Example.csv"
'Get the CSV
FileNumber = FreeFile()
Open FilePath For Binary Access Read As FileNumber
FileData = Space$(LOF(FileNumber)) 'Create a buffer first, then assign
Get FileNumber, , FileData
Close FileNumber
'My CSV is just a list of Doubles, should be relatively easy to swap out to process with ','
CSVArray = Split(FileData, vbCrLf)
'Add data
rs.Open
For i = LBound(CSVArray) + 1 To UBound(CSVArray) '+1 to skip header
rs.AddNew
rs.Fields("DoubleField").Value = CSVArray(i)
Next
rs.UpdateBatch
rs.MoveLast
Debug.Print rs.Fields("DoubleField").Value, "Processed 1000 records in: " & Timer - myTimer
End Sub
Хорошая сторона этого подхода в том, что он все еще довольно быстр. Мне удалось загрузить 1000 дублей за ~ 0,03 секунды, поскольку большинство действий, выполняемых здесь, выполняются в памяти. Это также устраняет необходимость в файле Schema.ini, однако есть больше кода для поддержки, так что это компромисс.
Рекомендация
Я бы попробовал изменить MaxScanRows
, если это не сработает, создайте файл Schema.ini.