返回列表 上一主題 發帖

[發問] excel vba (插入資料)insert 進 sqlite 緩慢問題

回復 12# koshi0413


    ZA=cells(i,j)

先把CELLS換成陣列
後面的ZA都不用動,就已經快很多了
意思是一樣的

VBA強制轉換文字的指令是CSTR(XXX)
100多個儲存格也是一樣
先一次性轉為陣列
然後跑回圈
妳如果沒有轉陣列用range("A" & i) 大概會慢到想要打人吧!
PKKO

TOP

p大,
('Bob','SHIT','TWN','SHIT2','SHIT3',2016-01-01," & 100 + i & ")"  << 這行是小弟看不懂的地方
恩~~為何看不懂,是因為小弟要逐行120個儲存格皆寫入,
還是要寫成  strSQL = "INSERT INTO customer VALUES (Range("A" & i),Range("B" & i),Range("C" & i),.......共120個.......," & 100 + i & ")"
我好像觀念怪怪的@@
  1. Sub WRITE_SQL() '寫入資料
  2. conn_connect'這是呼叫開啟SQL
  3. For i = 1 To 10000
  4.     strSQL = "INSERT INTO customer VALUES ('Bob','SHIT','TWN','SHIT2','SHIT3',2016-01-01," & 100 + i & ")" '每一列的語法
  5.     If i = 1 Then
  6.            strSQL2 = strSQL
  7.     Else
  8.            strSQL2 = strSQL2 & ";" & strSQL'將語法連接
  9.     End if
  10. Next
  11. Conn.Execute (strSQL2)'執行SQL
  12. End Sub
複製代碼

TOP

本帖最後由 koshi0413 於 2016-12-31 14:34 編輯

回復 10# PKKO

可否請p大協助一下,看小弟的語法是不是有問題  
因為在跑  For j = 3 To rcnt  << 最多會 3 to 10000 迴圈許久
za = cell(j,i) 是為了空格&字串判別,這好像不這樣的話導入日期都錯誤,還是可以這樣  str("2016/03/03") 這樣轉換成字串

至於導入sqlite3 是這行,開關一下就結束了,目前關卡在 迴圈太久 orz.....
Set cn = CreateObject("adodb.connection")
    cn.Open ("Driver={SQLite3 ODBC Driver};database=" & SQLName)
    cn.Close
Set cn = Nothing

ps:小弟是程式白痴,全自學的, python比較順手
  1. Sub SQLite_insert()

  2. Sheets("SQL JOIN").Select
  3. SQLName = "D:\Dropbox\SQLite3\StockAll.sqlite"

  4.     insert = "insert into StockAll values"
  5.     ret = ""
  6.     ret = insert
  7.         et = 114 '導入的標題數
  8.         rcnt = Range("A1").CurrentRegion.Rows.Count '計算所有的行
  9.             For j = 3 To rcnt
  10.                 zc = ""
  11.                     For i = 1 To et
  12.                         za = Cells(j, i)
  13.                             If za = "" Then '空格轉換
  14.                                 za = 0
  15.                                 
  16.                             ElseIf i = 2 Then '日期轉換
  17.                                 If (Len(Split(za, "/")(1)) = 1) And (Len(Split(za, "/")(2)) = 1) Then
  18.                                     za = Split(za, "/")(0) & "-0" & Split(za, "/")(1) & "-0" & Split(za, "/")(2)
  19.                                 ElseIf Len(Split(za, "/")(1)) = 1 Then
  20.                                     za = Split(za, "/")(0) & "-0" & Split(za, "/")(1) & "-" & Split(za, "/")(2)
  21.                                 ElseIf Len(Split(za, "/")(2)) = 1 Then
  22.                                     za = Split(za, "/")(0) & "-" & Split(za, "/")(1) & "-0" & Split(za, "/")(2)
  23.                                 Else
  24.                                     za = Split(za, "/")(0) & "-" & Split(za, "/")(1) & "-" & Split(za, "/")(2)
  25.                                 End If
  26.                                 
  27.                             End If
  28.                         zc = zc & "'" & za & "',"
  29.                     Next i
  30.                 zc = Left(zc, Len(zc) - 1)  '刪除最後一個","
  31.                 rez = "(" & zc & ")"
  32.                 ret = ret & rez & ","
  33.                 DoEvents
  34.             Next j
  35.         'MsgBox "跑完迴圈"
  36.         ret = Left(ret, Len(ret) - 1)  '刪除最後一個","
  37.         SqlImport = ret
  38.         
  39. Set cn = CreateObject("adodb.connection")
  40.     cn.Open ("Driver={SQLite3 ODBC Driver};database=" & SQLName)
  41.     cn.Close
  42. Set cn = Nothing
  43. End Sub
複製代碼

TOP

本帖最後由 PKKO 於 2016-12-28 21:48 編輯

回復 9# koshi0413


   excel 不會慢到哪邊去哦
我的都是一秒多就結束了(一秒是因為要開啟和關閉資料庫)
您的速度慢是因為妳用了ZA=CELLS(I,J)

excel要快最基本的要件就是先轉為陣列
例如
RNG=[A1].RESIZE(100,10).VALUE'取出100列*10欄位的資料
接著把妳的cells換成RNG就可以了
excel讀取儲存格是非常慢的速度
讀取陣列是非常快的,放資料的時候也一樣哦,不能一個一個放,要一次放一整個陣列進去哦!

以及上方先放入運算的程式,避免每一個if都要執行一次SPLIT
PKKO

TOP

回復 8# PKKO

P大
小弟的例子就是用跟您一下的方法
恩   vba跑迴圈是不是比較慢呢?
一次500筆很快
一次7999筆,一分鐘
然後一次性丟入 sqlite3

j大的批次方式,好像就是 7999/500 ,分段的一次性丟入
只是小弟分段丟入都出門,7999/3000 ,也一樣丟不進,
很奇怪,不知道是不是sqlite3反應時間的問題,下次有空, 中間丟個等待好了
不過這樣一來,就跟一次性7999迴圈差不多時間?
要試試~~

TOP

回復 5# joey0415


小弟用EXCEL寫入mysql 和 mssql 以前也遇到相同的問題
但小弟解決的方式不是挺優,您不嫌棄的話可以試試看

用連接符號=";"  
把語法連接起來,EXCUTE的動作等迴圈跑完之後,再給他一次EXCUTE就好了

您的語法主要是慢在數量多,你每一列都打開資料庫連結一次,因此速度慢了
連接在一起就只要打開資料庫一次,一次放入五百筆資料,就非常快了!
  1. Sub WRITE_SQL() '寫入資料
  2. conn_connect'這是呼叫開啟SQL
  3. For i = 1 To 10000
  4.     strSQL = "INSERT INTO customer VALUES ('Bob','SHIT','TWN','SHIT2','SHIT3',2016-01-01," & 100 + i & ")"'每一列的語法
  5.     If i = 1 Then strSQL2 = strSQL Else strSQL2 = strSQL2 & ";" & strSQL'將語法連接
  6. Next
  7. Conn.Execute (strSQL2)'執行SQL
  8. End Sub
複製代碼
PKKO

TOP

回復 6# koshi0413

剛才試了 7983筆,1分鐘
python的 for 好像比較快  哈哈
可是execl 還是有方便計算的地方

TOP

如果大大還有更好的方法,請回文讓小弟多學習,這資料可是花了很久的時間才突破的
joey0415 發表於 2013-8-7 16:10


小弟引用你上述的方式,一直跑到第500筆即失敗
以下是小弟的方法,速度好像還好,範列 4000筆,有比你原來的一筆一筆快,但應該比你的一次500筆慢
  1. Sub SQLite_insert()

  2. Sheets("SQL JOIN").Select
  3. SQLName = "D:\Dropbox\SQLite3\Stock.sqlite"

  4.     insert = "insert into Stock values"
  5.     ret = ""
  6.     ret = insert
  7.    
  8.     et = 113 '導入的標題數
  9.     rcnt = Range("A1").CurrentRegion.Rows.Count '計算所有的行
  10.     xa = 3 '從第三行開始計算

  11.             For j = xa To rcnt - 2
  12.                 zc = ""
  13.                     For i = 1 To et
  14.                         za = Cells(j, i)
  15.                             If za = "" Then '空格轉換
  16.                                 za = 0
  17.                                 
  18.                             ElseIf i = 2 Then '日期轉換
  19.                                 If (Len(Split(za, "/")(1)) = 1) And (Len(Split(za, "/")(2)) = 1) Then
  20.                                     za = Split(za, "/")(0) & "-0" & Split(za, "/")(1) & "-0" & Split(za, "/")(2)
  21.                                 ElseIf Len(Split(za, "/")(1)) = 1 Then
  22.                                     za = Split(za, "/")(0) & "-0" & Split(za, "/")(1) & "-" & Split(za, "/")(2)
  23.                                 ElseIf Len(Split(za, "/")(2)) = 1 Then
  24.                                     za = Split(za, "/")(0) & "-" & Split(za, "/")(1) & "-0" & Split(za, "/")(2)
  25.                                 Else
  26.                                     za = Split(za, "/")(0) & "-" & Split(za, "/")(1) & "-" & Split(za, "/")(2)
  27.                                 End If
  28.                                 
  29.                             End If
  30.                         zc = zc & "'" & za & "',"
  31.                     Next i
  32.                 zc = Left(zc, Len(zc) - 1)  '刪除最後一個","
  33.                 rez = "(" & zc & ")"
  34.                 ret = ret & rez & ","
  35.             Next j
  36.         ret = Left(ret, Len(ret) - 1)  '刪除最後一個","
  37.         SqlImport = ret
  38.         
  39. Set cn = CreateObject("adodb.connection")
  40.     cn.Open ("Driver={SQLite3 ODBC Driver};database=" & SQLName) '開啟sqlite指定資料庫,路徑與檔案名稱要對
  41.     cn.Execute (SqlImport)
  42.     cn.Close
  43. Set cn = Nothing
  44. End Sub
複製代碼

TOP

如果大大還有更好的方法,請回文讓小弟多學習,這資料可是花了很久的時間才突破的

TOP

找到解決的方法一,非正式…

sql語句例如
INSERT INTO "表格名" ("欄位1", "欄位2", ...)VALUES ("值1", "值2", ...);
sqlite它允許
INSERT INTO "表格名" ("欄位1", "欄位2", ...)VALUES ("值1", "值2", ...),("值3", "值4", ...),("值5", "值6", ...);
的方法,一次最多輸入500組數值,超過後一樣會報錯

如果你有1534組要insert進資料庫中,可以分成四組 34  500 500 500 的方法分批加進資料庫中
如果是一組組輸入,上例大概要30秒以上
如果是分四組輸入,估不用2秒

以下是個人程式碼:僅供參考
  1. Sub sqlite批次insert多筆成功()
  2. '最多一次500條,要分段放進去

  3.     Dim x, rcnt, i
  4.     Dim sql_command As String
  5.     Dim connection_string As String
  6.    
  7.     Worksheets(1).Activate
  8.     rcnt = Range("a1").CurrentRegion.Rows.Count
  9.     倍數 = (rcnt \ 500)
  10.     zx = rcnt Mod 500 '找500餘數

  11.      
  12.      j = 0

  13.         If rcnt < 500 Then  '如果小於500時只計算下面資料
  14.         
  15.                         aa = "insert into dbs(yyyymmdd, stockname, tradercode, price, buyamount, sellamount) values"
  16.                         Set x = CreateObject("adodb.recordset")
  17.                         cc = ""
  18.                         cc = aa
  19.                         i = 1

  20.                             For i = 1 To rcnt
  21.                                 bb = "('" & Cells(i, 1) & "','" & Cells(i, 2) & "','" & Cells(i, 3) & "','" & Cells(i, 4) & "','" & Cells(i, 5) & "','" & Cells(i, 6) & "')"
  22.                                 '串接要insert的數值對
  23.                                 cc = cc & bb & ","
  24.                             Next
  25.         
  26.                         cc = Left(cc, Len(cc) - 1)  '取字串並刪除最後一個","
  27.                         sql_command = cc
  28.                         connection_string = ("Driver={SQLite3 ODBC Driver};database=D:\股票資料下載\dbs.sqlite")
  29.                         x.Open sql_command, connection_string
  30.                         Set x = Nothing

  31.         Else '如果大於500時,要算下面兩種資料
  32.         
  33.                         aa = "insert into dbs(yyyymmdd, stockname, tradercode, price, buyamount, sellamount) values"
  34.                         Set x = CreateObject("adodb.recordset")
  35.                         cc = ""
  36.                         cc = aa
  37.                         i = 1
  38.                             For i = 1 To zx
  39.         
  40.                                 bb = "('" & Cells(i, 1) & "','" & Cells(i, 2) & "','" & Cells(i, 3) & "','" & Cells(i, 4) & "','" & Cells(i, 5) & "','" & Cells(i, 6) & "')"
  41.                                 cc = cc & bb & ","
  42.                             Next
  43.                         cc = Left(cc, Len(cc) - 1)
  44.                         sql_command = cc
  45.                         connection_string = ("Driver={SQLite3 ODBC Driver};database=D:\股票資料下載\dbs.sqlite")
  46.                         x.Open sql_command, connection_string
  47.                         Set x = Nothing

  48.                         For j = 0 To 倍數 - 1
  49.         
  50.                         aa = "insert into dbs(yyyymmdd, stockname, tradercode, price, buyamount, sellamount) values"
  51.                         Set x = CreateObject("adodb.recordset")
  52.                         cc = ""
  53.                         cc = aa
  54.                         i = 1
  55.         
  56.                             For i = j * 500 + zx + 1 To (j + 1) * 500 + zx
  57.         
  58.                                 bb = "('" & Cells(i + j * 500, 1) & "','" & Cells(i + j * 500, 2) & "','" & Cells(i + j * 500, 3) & "','" & Cells(i + j * 500, 4) & "','" & Cells(i + j * 500, 5) & "','" & Cells(i + j * 500, 6) & "')"
  59.                                 cc = cc & bb & ","
  60.         
  61.                             Next
  62.         
  63.                         cc = Left(cc, Len(cc) - 1)
  64.                         sql_command = cc
  65.                         connection_string = ("Driver={SQLite3 ODBC Driver};database=D:\股票資料下載\dbs.sqlite")
  66.                         x.Open sql_command, connection_string
  67.                         Set x = Nothing
  68.                     Next
  69.         
  70.         End If

  71. End Sub
複製代碼

TOP

        靜思自在 : 人的眼睛長在前面,只看到別人的缺點,絲毫看不到自己的缺點。
返回列表 上一主題