SQL用クラスモジュール

使用例

Sub sqlclass()
    Dim sql As DataExcelSQL: Set sql = New DataExcelSQL
    Dim ws As Worksheet: Set ws = Sheet2
    
    Dim strSQL As String: strSQL = _
    "SELECT SC,名称,市場,業種,株価 FROM [Sheet1$] WHERE 株価>2000;"

    sql.mRead (strSQL)
    If Not sql.pDataExists Then Exit Sub
    ws.Cells.Clear
    sql.mOutput ws, "A1", True
End Sub

メソッドとプロパティ

メソッド

名称return説明
Class_Initialize無し初期化処理
mRead無しSQLのSELECT文を実行する。
引数1(必須):SQL文をString型で渡す
mCrud無しSQLのINSERT/UPDATEを実行する(めったに使わない)
引数1(必須):SQL文をString型で渡す
mOutput無しSQLで取得したデータをワークシートに出力する 
引数1(必須):Worksheetオブジェクトを渡す
引数2(必須):セル番地をString型で渡す "A1″ など
引数3(任意):ヘッダー有無をTrue/Falseで指定 省略したらTrue
mPrintTableInfo無しSQLで取得したデータの列数と行数をイミディエイトウィンドウにprintする
printError無しデバッグ用 エラーメッセージをprintする
引数1(必須):String型でエラーが発生した関数名など渡す
引数2(必須):String型のエラー文を自分で書くかerr.Descriptionで渡す
引数3(任意):Long型のエラー番号 err.Number でOK

プロパティ

名称return説明
pDataExistsBoolean型SQLで取得したデータが存在するか返す
pArrDataBodyVariant型SQLで取得したデータを二次元の配列変数で返す
引数1(任意):ヘッダー有無をTrue/Falseで指定 省略したらTrue
pArrColumnsVariant型SQLで取得したデータのヘッダーを一次元配列で返す
pStrColumnsString型SQLで取得したデータのヘッダーをカンマ区切りの文字列で返す

クラスモジュール

オブジェクト名:DataExcelSQL

Option Explicit
'=============================================================================
'参照設定「Microsoft ActiveX Data Objects 2.8 Library」(6.1でもOK、2.7以下は未検証)
'参照設定「Microsoft Scripting Runtime」
'=============================================================================

Private cn As ADODB.Connection
Private rs As ADODB.Recordset
Private colIndex As Scripting.Dictionary
Private dataBody() As Variant
Private dataExists As Boolean

Private Sub Class_Initialize()
    Set colIndex = New Scripting.Dictionary
    Set cn = New ADODB.Connection
    Set rs = New ADODB.Recordset
    cn.Provider = "MSDASQL"
    cn.ConnectionString = _
    "Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};" & _
    "DBQ=" & ThisWorkbook.FullName & "; ReadOnly=True;"
End Sub

'SELECT用
Public Sub mRead(strSQL As String)
    cn.Open 'DB接続
    
    'SQL実行
    On Error GoTo omg
        rs.Open strSQL, cn, adOpenStatic
    On Error GoTo 0
    
    ' レコードの取得 Transposeで向き変更
    Dim tmp As Variant
    If Not rs.EOF Then tmp = rs.GetRows
    dataBody = WorksheetFunction.Transpose(tmp)
    dataExists = True
    
    ' 列のIndex作成
    ' countプロパティは1ベースなのにコレクションは0ベースっぽいので-1必要
    Dim i As Long
    For i = 0 To rs.Fields.Count - 1
        colIndex.Add rs.Fields(i).Name, i + 1
    Next i
    
    rs.Close: cn.Close 'DB切断
    Exit Sub
'-----------------------------------------------------------------
'エラー処理
omg:
    If Not rs.State = 0 Then rs.Close
    Set rs = Nothing
    cn.Close: Set cn = Nothing
    Debug.Print Time() & " SQL失敗"
    Debug.Print strSQL
    Call printError("mRead", Err.Description, Err.Number)
End Sub

'デバッグ用 エラーメッセージをprintする
Private Sub printError(errWhere As String, errDescription As String, Optional errNumber As Long)
    Debug.Print String("50", "-")
    
    If errNumber = 0 Then
        Debug.Print errWhere & ": " & errDescription
    Else
        Dim str As String: str = Replace(errDescription, "。", "。\n")
        Dim arr: arr = Split(str, "\n")
        
        Debug.Print errWhere & ":ERROR NUMBER " & Err.Number
        
        Dim i As Long
        For i = 0 To UBound(arr) - 1
            Debug.Print arr(i)
        Next i
    End If
    
    Debug.Print String("50", "-")
End Sub

'INSERT/UPDATE用
Public Sub mCrud(ByVal strSQL As String)
    cn.Open 'DB接続
    
    'SQL実行
    On Error GoTo omg
        rs.Open strSQL, cn, adOpenStatic
    On Error GoTo 0
    
    'DB切断
    If Not rs.State = 0 Then rs.Close
    cn.Close
    Exit Sub
'-----------------------------------------------------------------
'エラー処理
omg:
    If Not rs.State = 0 Then rs.Close
    Set rs = Nothing
    cn.Close: Set cn = Nothing
    Call printError("mCrud", Err.Description, Err.Number)
End Sub

'テーブルをワークシートに出力する headerがTRUEならヘッダーを含む
Public Sub mOutput(ws As Worksheet, rng As String, Optional header As Boolean = True)
    If Not dataExists Then
        Call printError("mOutputエラー", "出力できるデータがありません。")
        Exit Sub
    End If
    
    Dim arr: arr = Me.pArrDataBody(header)
    ws.Range(rng).Resize(UBound(arr), UBound(arr, 2)) = arr
End Sub

'テーブルの行数と列数をイミ窓にprintする
Public Sub mPrintTableInfo()
    Debug.Print String("50", "-")
    Debug.Print "mPrintTableInfo"
    
    If dataExists Then
        Debug.Print "行数:" & UBound(dataBody) & " (※ヘッダーは含まない数)"
        Debug.Print "列数:" & UBound(colIndex.Keys) + 1 & Replace(" (?)", "?", Me.pStrColumns)
    Else
        Debug.Print "まだ取得したデータはありません"
    End If
    Debug.Print String("50", "-")
End Sub

'返すデータ型:Boolean|内容:SQLで取得したデータがあったらTrue、無いならFalse
Public Property Get pDataExists() As Boolean
    pDataExists = dataExists
End Property

'返すデータ型:一次元配列(起点0)|内容:列名の文字列
Public Property Get pArrColumns() As Variant
    If Not dataExists Then
        Call printError("pArrColumns", "出力できるデータがありません。")
        Exit Property
    End If
    pArrColumns = colIndex.Keys
End Property

'返すデータ型:String|内容:列名をカンマ区切りした文字列
Public Property Get pStrColumns() As String
    If Not dataExists Then
        Call printError("pStrColumns", "出力できるデータがありません。")
        Exit Property
    End If
    
    Dim arr: arr = colIndex.Keys
    Dim i As Long, tmp As String
    For i = 0 To UBound(arr)
        tmp = tmp & CStr(arr(i)) & ","
    Next i
    pStrColumns = Left(tmp, Len(tmp) - 1)
End Property

'返すデータ型:二次元配列(起点1)|内容:保有中のテーブル|HeaderがTrueならヘッダー込み、Falseならデータ部分のみ
Public Property Get pArrDataBody(Optional header As Boolean = True) As Variant
    If Not dataExists Then
        Call printError("pArrDataBody", "出力できるデータがありません。")
        Exit Property
    End If
    
    If Not header Then
        pArrDataBody = dataBody
    Else
        Dim i As Long, j As Long, hd: hd = Me.pArrColumns
        Dim arr() As Variant
        ReDim arr(1 To UBound(dataBody) + 1, 1 To UBound(dataBody, 2))
        'ヘッダー部分
        For i = 1 To UBound(arr, 2)
            arr(1, i) = hd(i - 1)
        Next i
        'データ部分
        For i = 1 To UBound(dataBody)
            For j = 1 To UBound(arr, 2)
                arr(i + 1, j) = dataBody(i, j)
            Next j
        Next i
        pArrDataBody = arr
    End If
End Property

Posted by rafavba