Мне нужно часто генерировать вывод в формате 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. Кто-нибудь может предложить решение, пожалуйста?