Импорт данных в Access с использованием VBA - PullRequest
0 голосов
/ 31 августа 2018

Мне нужно часто генерировать вывод в формате CSV. Этот файл имеет 25 столбцов. Порядок столбцов должен оставаться таким же, как файл будет использоваться в качестве входных данных для процесса ETL. Обратите внимание, что невозможно настроить ETL для поиска заголовков столбцов.

Данные, предоставленные мне, также в формате CSV. Количество столбцов может измениться. Может варьироваться от 15 до 50 столбцов. Порядок столбцов также может измениться. Один файл может иметь Col A, Col B, Col C, а другой может иметь Col B, Col A, Col D.

Входные данные, как показано ниже:

Заголовки:

"Employee","Date","Start","End","Brk","Ord","WEND","TRV","PH200","PH250","T1x5","T1x5P","T2","T2x5","SB2","AL","LL175","COM","LWOP","PERS","PHNW","WCOMP","MKUP","AS","NS","CI","NPAY","COC","KMS","LAFHA","LAFHI","MEAL","MPA","OMA","SMA","Allowances","Approval Status","Branch","Branch Cost Code","Branch Ref. No","Contract","Contract Hours Per Cycle","Detail","Detail Cost Code","Detail Ref. No","Employee Ref. No","Employment Type","Location","Location Cost Code","Location Ref. No","Max Hours Per Period","Pay Group","Pay Level","Role","Role Cost Code","Roster","Shift","Timesheet Comments","Total Bill","Total Cost","Total Hours","Work Type"

Данные:

"Smith, John","04/11/2017","12:00","05:00","",10.00,"","","",,"",,"",,"",,"",,"",,"",,3.00,7.00,"",,"",,"",1.00,"",,"",,"MEAL","Approved","Melbourne","","","Admin Officer","70.00","JX526","","1469","948","AT","Melbourne","633","","70.00","","Base","Admin Officer Level 1","7847000","1900-0500","DS","","0.00","351.95","10.00",""

Как таблица:

| Employee      | Date          | Start     | End       | Brk   | Ord       | WEND  | TRV   | PH200     | PH250     | T1x5  | T1x5P     | T2    | T2x5  | SB2   | AL    | LL175     | COM   | LWOP  | PERS  | PHNW  | WCOMP     | MKUP  | AS    | NS    | CI    | NPAY  | COC   | KMS   | LAFHA     | LAFHI     | MEAL  | MPA   | OMA   | SMA   | Allowances    | Approval Status   | Branch        | Branch Cost Code  | Branch Ref. No    | Contract          | Contract Hours Per Cycle  | Detail    | Detail Cost Code  | Detail Ref. No    | Employee Ref. No  | Employment Type   | Location      | Location Cost Code    | Location Ref. No  | Max Hours Per Period  | Pay Group     | Pay Level     | Role                      | Role Cost Code    | Roster        | Shift     | Timesheet Comments    | Total Bill    | Total Cost    | Total Hours   | Work Type     |
|-------------  |------------   |-------    |-------    |-----  |-------    |------ |-----  |-------    |-------    |------ |-------    |----   |------ |-----  |----   |-------    |-----  |------ |------ |------ |-------    |------ |------ |------ |----   |------ |-----  |-----  |-------    |-------    |------ |-----  |-----  |-----  |------------   |-----------------  |-----------    |------------------ |----------------   |---------------    |-------------------------- |--------   |------------------ |----------------   |------------------ |-----------------  |-----------    |--------------------   |------------------ |---------------------- |-----------    |-----------    |-----------------------    |----------------   |-----------    |-------    |--------------------   |------------   |------------   |-------------  |-----------    |
| Smith, John   | 04/11/2017    | 12:00     | 05:00     |       | 10.00     |       |       |           |           |       |           |       |       |       |       |           |       |       |       |       |           |       | 3.00  | 7.00  |       |       |       |       |           | 1.00      |       |       |       |       | MEAL          | Approved          | Melbourne     |                   |                   | Admin Officer     | 70.00                     | JX526     |                   | 1469              | 948               | AT                | Melbourne     | 633                   |                   | 70.00                 |               | Base          | Admin Officer Level 1     | 7847000           | 1900-0500     | DS        |                       | 0.00          | 351.95        | 10.00         |               |

Поскольку я не могу найти какое-либо готовое решение, я пытаюсь создать небольшой инструмент, используя Access VBA для этого.

В конце импорта я попробовал 2 стандартных метода:

1. DoCmd.TransferText 
2. CurrentDb.Execute "INSERT INTO " & TableName & " SELECT * FROM " _
     & "[TEXT;FMT=Delimited;HDR=YES;database=" & FolderOnly & "].[" & FileOnly & "]")

Оба не очень хорошо работали. Числа округляются до ближайшего десятичного числа. Я не нашел способа принудительно импортировать данные в виде текста. Итак, теперь я генерирую SQL, поэтому у меня есть полный контроль над типом данных. Используя File System Object, я могу прочитать файл. Первым шагом является циклическое выполнение и создание сценария CREATE TABLE. Функция разделения VBA очень хорошо работает с запятой в качестве разделителя:

While Not objTextStream.AtEndOfStream
    strLine = objTextStream.ReadLine
    'regex.pattern =
    If objTextStream.line = 2 And Len(strLine) > 0 Then
        strSQL = "CREATE TABLE " & TableName & " ("
        header = Split(strLine, ",")

        For i = LBound(header) To UBound(header)
            strSQL = strSQL & "[" & Replace(Replace(header(i), Chr(34), ""), ".", "") & "] TEXT(255)"
            headerLine = headerLine & "[" & Replace(Replace(header(i), Chr(34), ""), ".", "") & "]"

            If i <> UBound(header) Then
                strSQL = strSQL & ","
                headerLine = headerLine & ","
            End If
        Next i

        strSQL = strSQL & ")"
        'Debug.Print strSql
        DBEngine(0)(0).Execute strSQL
    End If
Wend

Второй шаг - создание оператора INSERT. Примерно так:

While Not objTextStream.AtEndOfStream
    If objTextStream.line > 2 And Len(strLine) > 0 Then
        strSQL = "INSERT INTO " & TableName & " (" & headerLine & ") VALUES ("
        line = Split(strLine, """,""") 'Regex??

        For i = LBound(line) To UBound(line)
            If Nz(line(i)) <> "" Then
                strSQL = strSQL & "'" & Replace(Replace(line(i), Chr(34), ""), "'", "''") & "'"
            Else
                strSQL = strSQL & "''"
            End If
            If i <> UBound(line) Then strSQL = strSQL & ","
        Next i
        strSQL = strSQL & ")"
        'Debug.Print strSQL
        CurrentDb.Execute strSQL
    End If
Wend

Я застрял здесь, поскольку не могу использовать функцию Split с запятой в качестве разделителя. Некоторые поля, такие как Employee, содержат запятую, поскольку имя выводится в формате Family_Name, First_Name. Я думал о Regex, но не уверен, как использовать это в VBA. Кто-нибудь может предложить решение, пожалуйста?

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

Вот как я это сделал:

Создать файл Schema.ini вручную:

Dim objFS, objTextStream
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objTextStream = objFS.CreateTextFile(GetFolderFromPath(FileName) & "Schema.ini", True)

objTextStream.WriteLine "[" & GetFileNameFromPath(FileName) & "]"
objTextStream.WriteLine "ColNameHeader = True"
objTextStream.WriteLine "Format = CSVDelimited"
objTextStream.WriteLine "MaxScanRows = 0"
objTextStream.WriteLine "CharacterSet = OEM"
objTextStream.Close

Set objTextStream = Nothing
Set objFS = Nothing

Затем добавьте текстовый файл в виде связанной таблицы:

If IsTableExisted(TableName) Then DoCmd.DeleteObject acTable, TableName
Dim tdfNew As TableDef
Set tdfNew = CurrentDb.CreateTableDef(TableName)
tdfNew.Connect = "Text;DATABASE=" & GetFolderFromPath(FileName) & _
    ";TABLE=" & GetFileNameFromPath(FileName) & ";"
tdfNew.SourceTableName = GetFileNameFromPath(FileName)
CurrentDb.TableDefs.Append tdfNew
0 голосов
/ 31 августа 2018

Я настоятельно рекомендую вам исправить один из стандартных вызовов в соответствии с вашими потребностями вместо того, чтобы делать все вручную.

Использование текстового драйвера ISAM является наиболее перспективным из них.

Вы должны увеличить MaxScanRows до числа, достаточно большого, чтобы сканировать достаточно большой раздел, чтобы встретить число с большим количеством десятичных знаков, или до 0, чтобы Access сканировал весь файл. Округление происходит, когда отсканированные строки содержат меньшее количество знаков после запятой, чем импортируемое значение.

Для инициализации текстового драйвера см. эту страницу MSDN . Обратите внимание, что более старые источники могут ссылаться на файл schema.ini, но этот файл больше не существует, настройки управляются в реестре для текущих версий Access.

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