#VBA100本ノック 96本目
エクセルの神髄 の中の人がツイッターで行っている VBA100本ノック の96本目の解答記事です。
#VBA100本ノック 96本目
— エクセルの神髄 (@yamaoka_ss) February 26, 2021
DB1.accdbから以下の出力項目と抽出条件でデータを取得しシートに出力する。
■出力項目
取引先CD,取引先名,商品CD,商品名,単価,数量,金額
金額は単価*数量
■抽出条件
2021年以降(2021/01/01~)
金額が100万以上
※テーブルは画像とサンプルにて
※シートは任意 pic.twitter.com/8A1Bz1aFqy
自分が見た範囲の解答ではADODB.Command
によるパラメータ挿入を使っている例を見なかったので、自身の確認も兼ねての解答です。
Public Sub VBA100Knock66() '配布されているデータを、同じ場所に保存している前提です。 'https://twitter.com/yamaoka_ss/status/1365174893566849025 Dim dbFullName As String dbFullName = ThisWorkbook.Path & "\DB1.accdb" '出力先を事前にきれいにしておきます。 Dim outputSheet As Excel.Worksheet Set outputSheet = ThisWorkbook.Worksheets.Item(1) outputSheet.Cells.Delete 'ADODB の接続部分の設定。 Dim conn As ADODB.Connection Set conn = VBA.Interaction.CreateObject("ADODB.Connection") conn.Provider = "Microsoft.ACE.OLEDB.16.0" With conn.Properties .Item("Data Source").Value = dbFullName .Item("Extended Properties").Value = GuessIsamType(dbFullName) & ";" End With conn.Open 'ADODB.Command で SQL を設定する。 Dim cmd As ADODB.Command Set cmd = VBA.Interaction.CreateObject("ADODB.Command") Set cmd.ActiveConnection = conn cmd.CommandType = adCmdText Dim sqlCmd As String sqlCmd = _ "SELECT " & _ "[T売上].[取引先CD], " & _ "[M取引先].[取引先名], " & _ "[T売上].[商品CD], " & _ "[M商品].[商品名], " & _ "[T売上].[単価], " & _ "[T売上].[数量], " & _ "[T売上].[単価] * [T売上].[数量] AS [金額]" & _ "FROM (" & _ "([T売上] LEFT JOIN [M取引先] ON [T売上].[取引先CD] = [M取引先].[取引先CD]) " & _ "LEFT JOIN [M商品] ON [T売上].[商品CD] = [M商品].[商品CD]" & _ ")" & _ "WHERE " & _ "[T売上].[日付] >= [以降を抽出したい売上日] AND " & _ "[T売上].[単価] * [T売上].[数量] >= [最低金額]" cmd.CommandText = sqlCmd 'https://twitter.com/yamaoka_ss/status/1365174782161952775 '■抽出条件 '2021年以降(2021/01/01~) '金額が100万以上 cmd.Parameters.Append cmd.CreateParameter("以降を抽出したい売上日", adDate, Value:=VBA.DateTime.DateSerial(2021, 1, 1)) cmd.Parameters.Append cmd.CreateParameter("最低金額", adInteger, Value:=10 ^ 6) Dim rs As ADODB.Recordset Set rs = cmd.Execute() 'Excel へ出力する用に各種情報を取得。 Dim headerNames() As Variant ReDim headerNames(0 To rs.Fields.Count - 1) Dim i As Long i = LBound(headerNames) Dim f As ADODB.Field For Each f In rs.Fields headerNames(i) = f.Name i = i + 1 Next f Dim dbData() As Variant dbData = outputSheet.Application.WorksheetFunction.Transpose(rs.GetRows(Fields:=headerNames)) 'ここで DB との接続は切っておく。 rs.Close conn.Close 'Excel にテーブルとして出力。 With outputSheet.ListObjects.Add(xlSrcRange, outputSheet.Cells.Item(1)) .HeaderRowRange.Resize(, UBound(headerNames) - LBound(headerNames) + 1).Value() = headerNames .HeaderRowRange.Offset(1).Resize(UBound(dbData, 1) - LBound(dbData, 1) + 1) = dbData .Range.Columns.AutoFit End With End Sub 'ファイルの拡張子から、ISAM 形式を類推する(簡易版)。 Private Function GuessIsamType(ByVal inFileName As String) As String Dim dotPos As Long dotPos = VBA.Strings.InStrRev(inFileName, ".") If dotPos = 0 Then Exit Function Dim ext As String ext = VBA.Strings.LCase$(VBA.Strings.Mid$(inFileName, dotPos + 1)) Select Case ext Case "accdb": Let GuessIsamType = "" Case "xlsx": Let GuessIsamType = "Excel 12.0 Xml" End Select End Function