ExcelからODBCドライバをインストールせずにSQLite3へアクセスする方法
準備(64bit環境の場合)
- Releases · govert/SQLiteForExcel · GitHub からSQLite For Excelの最新版を入手(現時点ではSQLiteForExcel-1.0.zip)しアーカイブの中から、SQLiteForExcel_64.xlsmをとりだして使用する。32bit環境では同梱されているSQLite3_StdCall.dllを同じ場所に置く必要があるようですが64bit環境では不要の様です。
- SQLite Home Pageからsqlite3.dllを入手して別途コピーする。(現時点の最新は、sqlite-dll-win64-x64-3260000.zip)
動作確認
sqlite3.dllの置き場所に注意
#If Win64 Then
' I put the 64-bit version of SQLite.dll under a subdirectory called x64
InitReturn = SQLite3Initialize(ThisWorkbook.Path + "\x64")
#Elseして、SQLiteForExcel_64.xlsmのSqlite3Demoモジュール中の AllTestsプロシージャを実行する。結果はDebug.Printでイミディエイトウィンドウに表示されるのでエラーが無ければOK
SQLite4Excelクラスの作成
ODBC版と似たような使い勝手にするためにクラス化してみる(32bit版では、LongPtr型をLongに変更する)
SQLiteForExcel_64.xlsmのSqliteモジュールのあるブックに以下のクラスモジュールを作成する。
Option Explicit
'SQLite4Excel.cls
Dim mDbh As LongPtr
Dim mSth As LongPtr
Dim mFile As String
Dim mSQL As String
Dim mRecords As Variant
Dim mIdx As Long
Private Sub Class_Initialize()
Dim ret As Long
ret = SQLite3Initialize(ThisWorkbook.Path)
If ret <> SQLITE_INIT_OK Then
Err.Raise 999, "Error Initializing SQLite. Error: " & Err.LastDllError
End If
End Sub
Private Sub Class_Terminate()
Dim ret As Long
ret = SQLite3Close(mDbh)
If ret <> SQLITE_OK Then
Err.Raise 999, "DB File Close" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
End Sub
'レコードセット読み取り
Property Get RS() As Variant
RS = mRecords(mIdx)
End Property
'レコード数
Property Get RecordCount() As Long
RecordCount = UBound(mRecords) - LBound(mRecords) + 1
End Property
'レコード終端か否か
Property Get EOF() As Boolean
If mIdx = Me.RecordCount Then
EOF = True
Else
EOF = False
End If
End Property
'次のレコード
Public Function MoveNext()
mIdx = mIdx + 1
End Function
'最初のレコード
Public Function MoveFirst()
mIdx = 0
End Function
'初期化
Public Sub Prepare(ByVal file As String)
Dim ret As Long
mFile = file
ret = SQLite3Open(mFile, mDbh)
If ret <> SQLITE_OK Then
Err.Raise 999, "DB File Open" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
End Sub
'通常SQL発行
Public Sub Execute(ByVal sql As String)
Dim ret As String
ret = SQLite3PrepareV2(mDbh, sql, mSth)
If ret <> SQLITE_OK Then
Err.Raise 999, _
"SQLite3DB.Eecute" & vbCrLf & _
"SQL: " & sql & vbCrLf & _
"SQLite3PrepareV2" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
ret = SQLite3Step(mSth)
If ret <> SQLITE_DONE Then
Err.Raise 999, _
"SQLite3DB.Eecute" & vbCrLf & _
"SQL: " & sql & vbCrLf & _
"SQLite3Step" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
ret = SQLite3Finalize(mSth)
If ret <> SQLITE_OK Then
Err.Raise 999, _
"SQLite3DB.Eecute" & vbCrLf & _
"SQL: " & sql & vbCrLf & _
"SQLite3Finallize" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
End Sub
'SELECT文を発行し、レコード値をmRecordsに格納
' mRecordsの型は、Array( Array( ), ……)
Public Sub Query(ByVal sql As String)
Dim ret As Long
Dim i As Long
Dim rc As Variant
Dim cnt As Long
Dim colType As Long
Dim colValue As Variant
mRecords = Array()
mIdx = 0
ret = SQLite3PrepareV2(mDbh, sql, mSth)
If ret <> SQLITE_OK Then
Err.Raise 999, _
"SQLite3DB.Query" & vbCrLf & _
"SQL: " & sql & vbCrLf & _
"SQLite3PrepareV2" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
ret = SQLite3Step(mSth)
Do While ret = SQLITE_ROW
rc = Array()
cnt = SQLite3ColumnCount(mSth)
For i = 0 To cnt - 1
'colName = SQLite3ColumnName(sth, i)
colType = SQLite3ColumnType(mSth, i)
colValue = ColumnValue(mSth, i, colType)
ReDim Preserve rc(UBound(rc) + 1)
rc(UBound(rc)) = colValue
Next
ReDim Preserve mRecords(UBound(mRecords) + 1)
mRecords(UBound(mRecords)) = rc
ret = SQLite3Step(mSth)
Loop
If ret <> SQLITE_DONE Then
Err.Raise 999, _
"SQLite3DB.Query" & vbCrLf & _
"SQL: " & sql & vbCrLf & _
"SQLite3Step" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
ret = SQLite3Finalize(mSth)
If ret <> SQLITE_OK Then
Err.Raise 999, _
"SQLite3DB.Query" & vbCrLf & _
"SQL: " & sql & vbCrLf & _
"SQLite3Finallize" & vbCrLf & _
"Error: " & SQLite3ErrMsg(mDbh)
End If
End Sub
' 以下はSqlite3Demoモジュールから借用
Private Function ColumnValue(ByVal stmtHandle As LongPtr, ByVal ZeroBasedColIndex As Long, ByVal SQLiteType As Long) As Variant
Select Case SQLiteType
Case SQLITE_INTEGER:
ColumnValue = SQLite3ColumnInt32(stmtHandle, ZeroBasedColIndex)
Case SQLITE_FLOAT:
ColumnValue = SQLite3ColumnDouble(stmtHandle, ZeroBasedColIndex)
Case SQLITE_TEXT:
ColumnValue = SQLite3ColumnText(stmtHandle, ZeroBasedColIndex)
Case SQLITE_BLOB:
ColumnValue = SQLite3ColumnText(stmtHandle, ZeroBasedColIndex)
Case SQLITE_NULL:
ColumnValue = Null
End Select
End Function
作成したクラスの使用例
Sub test()
On Error GoTo Err_handler
Dim file As String
Dim db As SQLite4Excel
Dim i As Long
file = ThisWorkbook.Path & "\" & "testSQ3ForExcel.db"
Set db = New SQLite4Excel
db.Prepare file
db.Execute "CREATE TABLE IF NOT EXISTS aaa(tt TEXT,ii INTEGER)"
db.Execute "BEGIN TRANSACTION"
For i = 1 To 10000
db.Execute "INSERT INTO aaa VALUES('abc" & i & "', " & i & ")"
Next
db.Execute "COMMIT TRANSACTION"
db.Execute "UPDATE aaa SET tt='zzz' WHERE ii=9995"
db.Execute "DELETE FROM aaa WHERE ii = 9996"
db.Execute "UPDATE aaa SET tt=NULL WHERE ii=10000"
Dim r As Range
Set r = Range("A1")
db.Query "SELECT COUNT(*) FROM aaa"
r.Value = db.RS(0)
Set r = r.offset(1)
db.Query "SELECT * FROM aaa WHERE ii>9990"
If db.EOF Then
MsgBox "MSG : RecordSet Empty"
Else
Do Until db.EOF = True
r.Value = db.RS(0)
r.offset(0, 1).Value = db.RS(1)
Set r = r.offset(1)
db.MoveNext
Loop
End If
GoTo Finally
Err_handler:
MsgBox Err.Number & vbCrLf & _
Err.Description & vbCrLf & _
Err.Source
Finally:
Set db = Nothing
End Sub