2015-09-27 111 views
4

我在下面的VBA代碼中將許多文本文件關聯到Access表。但是,包含帶雙引號的文本的.TXT文件的情況存在問題,因此會使用空值打破此記錄的所有其他字段。在Access VBA中換掉雙引號 - INSERT INTO ... SELECT

我試圖在產品字段的選擇中放置替換功能,但不適用於雙引號。與其他字符,它的工作原理,但雙引號(不)...

你推薦哪些調整?任何建議,將不勝感激。

*注:實際數據超過100萬條記錄...

SCHEMA.INI
[Test_temp.csv]
ColNameHeader =假
格式=(;)分隔
COL1 = 「產品」 文本
col2的= 「價格」 雙

文本文件,CSV:test01.txt
電視SAMSUNG 21" 寬屏LED; 170
電視PHILIPS 27" 寬屏LED; 200
HD SEAGATE 1TB 7200RPM; 150次


代碼VBA訪問:

Sub TableImport() 

    Dim strSQL As String 
    Dim db As DAO.Database 

    Dim strFolder As String 
    strFolder = CurrentProject.Path 

    Set db = CurrentDb 

    strSQL = "DELETE FROM tbTest" 
    db.Execute strSQL, dbFailOnError 

    Dim strFile As String 
    strFile = Dir(strFolder & "\test*.txt", vbNormal) 

    Do Until strFile = "" 

     FileCopy strFolder & "\" & strFile, strFolder & "\Test_temp.csv" 

     strSQL = "" 

     strSQL = " INSERT INTO tbTEST(product,price)" 
     strSQL = strSQL & " SELECT fncReplace(product),price" 
     strSQL = strSQL & " FROM [Text;HDR=no;FMT=Delimited;DATABASE=" & strFolder & "].Test_temp.csv" 

     db.Execute strSQL, dbFailOnError 

     strFile = Dir 

    Loop 

    db.Close 

End Sub 


Public Function fncReplace(varStr As Variant) As String 
    If IsNull(varStr) Then 
     fncReplace = "" 
    Else 
     fncReplace = Replace(Trim(varStr), """", "''") 
    End If 
End Function 


更新 - 它的工作原理 - 建議者:Andre451

Sub TableImport() 

    Dim strSQL As String 
    Dim db As DAO.Database 

    Dim strFolder As String 
    strFolder = CurrentProject.Path 

    Set db = CurrentDb 

    strSQL = "DELETE FROM tbTest" 
    db.Execute strSQL, dbFailOnError 

    Dim strFile As String 
    strFile = Dir(strFolder & "\test*.txt", vbNormal) 

    Do Until strFile = "" 

     FileCopy strFolder & "\" & strFile, strFolder & "\Test_temp.csv" 

     DoCmd.TransferText acLinkDelim, "specIMPORTAR", "linkData", strFolder & "\Test_temp.csv", False 

     strSQL = "" 
     strSQL = " INSERT INTO tbTEST(product,price)" 
     strSQL = strSQL & " SELECT product,price" 
     strSQL = strSQL & " FROM linkData" 

     db.Execute strSQL, dbFailOnError 

     strFile = Dir 

     DoCmd.DeleteObject acTable, "linkData" 

    Loop 

    db.Close 

End Sub 

回答

1

當讀取csv文件,雙引號被解釋爲文字分隔符。在SCHEMA.INI中似乎沒有辦法明確告訴Access「沒有文本分隔符!」。

所以我建議使用導入規範。您可以通過文本導入嚮導手動導入csv文件來創建導入規範,然後將其保存,例如作爲「產品導入規範」。有關詳細信息,請參見this answer中的1.。

在規範中,您將「none」設置爲文本分隔符。在德國訪問:

enter image description here

然後你從中鏈接的文本文件,並導入數據:

Public Sub ImportProducts() 

    Dim S As String 

    ' Link csv file as temp table 
    DoCmd.TransferText acLinkDelim, "Product import specification", "linkData", "D:\temp\Test01.csv", False 

    ' Insert from temp table into product table 
    S = "INSERT INTO tbProduct (product, price) SELECT product, price FROM linkData" 
    CurrentDb.Execute S 

    ' Remove temp table 
    DoCmd.DeleteObject acTable, "linkData" 

End Sub 

編輯:

我創建了一個CSV文件與1.000.000行(36 MB)並將其用作導入文件:

Const cFile = "G:\test.csv" 

Public Sub CreateCSV() 

    Dim S As String 
    Dim i As Long 

    Open cFile For Output As #1 
    For i = 1 To 1000000 
     Print #1, "Testing string number " & CStr(i) & ";" & CStr(i) 
    Next i 
    Close #1 

End Sub 

Public Sub ImportProducts() 

    Dim S As String 
    Dim snTime As Single 

    snTime = Timer 

    ' Clean up product table 
    CurrentDb.Execute "DELETE * FROM tbProduct" 
    Debug.Print "DELETE: " & Timer - snTime 

    ' Link csv file as temp table 
    DoCmd.TransferText acLinkDelim, "Product import specification", "linkData", cFile, False 
    Debug.Print "TransferText: " & Timer - snTime 

    ' Insert from temp table into product table 
    S = "INSERT INTO tbProduct (product, price) SELECT product, price FROM linkData" 
    CurrentDb.Execute S 
    Debug.Print "INSERT: " & Timer - snTime 

    ' Remove temp table 
    DoCmd.DeleteObject acTable, "linkData" 

End Sub 

結果:

TransferText: 0,6640625 
INSERT: 8,023438 

8秒是不是真的那麼慢:

DELETE: 0 
TransferText: 0,6640625 
INSERT: 4,679688 

添加自動編號字段作爲主鍵來tbProduct後。
確保Access數據庫和導入的CSV文件都位於本地磁盤上,而不是網絡驅動器上。如果可能,在SSD上。

+0

它工作。但是代碼太慢了。想象一下,當使用100萬條記錄時。看到你建議的上面的代碼,它是讓它更快?爲什麼代碼很慢? –

+0

@RalphMacLand:見編輯。對於100萬條記錄,對於我來說,只有兩個字段運行4.5秒,另外一個自動編號主鍵字段爲8秒。 – Andre

+0

@RalphMacLand:P.S.你可以省略'FileCopy'並直接鏈接test * .txt文件。導入規格相對於schema.ini的另一個優勢。 ---除非文件位於網絡驅動器上,否則最好先將它們複製到本地磁盤。 – Andre

1

因爲你是從複製的test01.txt文件temp_test.csv,何不趁此機會來破解它的開放和替換使用Unicode「智能引號」無用引號字符(例如)這是不會污染CSV閱讀?

Sub TableImport() 

    Dim strSQL As String, f As Long, strm As String, ln as long 
    Dim db As DAO.Database, rs As DAO.Recordset 

    Dim strFolder As String 
    strFolder = Environ("TEMP") 'CurrentProject.Path 

    Set db = CurrentDb 

    strSQL = "DELETE FROM tbTest" 
    db.Execute strSQL, dbFailOnError 

    Dim strFile As String 
    strFile = Dir(strFolder & "\test*.txt", vbNormal) 

    Do Until strFile = "" 

     strm = vbNullString 
     f = FreeFile 
     Open strFolder & "\" & strFile For Binary Access Read As #f 
     strm = Input$(LOF(f), f) 
     Close #f 
     strm = Replace(strm, Chr(34), ChrW(8221)) '<~~ replace double-quote character with Unicode right smart quote character 
     'optionally strip off the first 5 lines 
     for ln = 1 to 5 
      strm = mid$(strm, instr(1, strm, chr(10)) + 1) 
     next ln 
     Kill strFolder & "\Test_temp.csv" 
     f = FreeFile 
     Open strFolder & "\Test_temp.csv" For Binary Access Write As #f 
     Put #f, , strm 
     Close #f 

     strSQL = vbNullString 
     strSQL = "INSERT INTO tbTEST(product,price)" 
     strSQL = strSQL & " SELECT F1, F2" 
     strSQL = strSQL & " FROM [Text;HDR=no;FMT=Delimited(;);DATABASE=" & strFolder & "].[Test_temp.csv]" 

     db.Execute strSQL, dbFailOnError + dbSeeChanges 

     strFile = Dir 

    Loop 

    db.Close 

End Sub 

INSERT text field with Quote Character

+0

有趣的代碼片段!我有個疑問。使用您的代碼片段,並且還可以在將其餘數據導入到表格之前排除CSV文件的前5行? –

+0

如果是SQL,我會將源表分區,但由於您正在讀取輸入並將其重寫爲不同的名稱,因此可能最簡單的方法是跳過讀取或寫入的前5行。 – Jeeped

0

所有你需要的是在單引號包裹雙引號:

Public Function fncReplace(varStr As Variant) As String 
    fncReplace = Replace(Trim(Nz(varStr)), Chr(39), Chr(34) & Chr(39)) 
End Function 

這就是說,我會覺得更容易地將文件第一鏈接爲一個表,然後使用鏈接表源。

+0

使用Andrea451代碼不需要替換功能。代碼工作時不使用替換(雙引號)。謝謝! –