- ベストアンサー
VBAで複数Excelの複数条件を満たすもの抽出
- VBAを使用して複数のExcelファイルから複数の条件を満たすデータを抽出する方法について質問があります。
- 具体的には、「1月顧客別商品別.xls」と「顧客別管理.xlsx」の2つのExcelファイルにおいて、顧客コードと商品コードの双方が一致しているデータの売上高と粗利を、「顧客別管理.xlsx」の対応する欄に入力するVBAを作成したが、正しく動作しているかどうか分からないとのことです。
- 質問者は大量のデータがあるため、Dictionaryを使用してデータを管理していますが、コードが重たくなってしまっているようです。もし修正ポイントがあれば教えて欲しいとのことです。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
ごめんなさい、注3の位置を間違えたので差し替えます。 SQLを一部で使ったコードとしてみました。 よかったら試してみてください。 ただし、 顧客コードが文字列の場合は注1を生かし、注2をコメントアウトしてください。 また、 顧客別管理.xlsxのA9,B9以下とA39,B39以下が上詰めではない場合は 注3をコメントアウトしてください。 なお >"1月顧客別商品別.xls":”集計”シートのA~E列に >”顧客コード”、”顧客名”、”商品コード”、”売上高”、”粗利”が2行目以降並んでいます。 これは、顧客コードと商品コード組み合わせでは重複がないということでいいですよね? これを前提としたコードです。 それとも、重複があり、"顧客別管理.xlsx"に合計転記しますか? また、課題のブック2つとは別にマクロブック専用ブックを使うことを想定しています。 更に、 "1月顧客別商品別.xls"、こちらにあって、 "顧客別管理.xlsx"にない商品コードは想定していません。 つまり、マッチングしなかったものは、無視しています。 想定するのであれば、どのように扱えばいいのかを説明してみてください。 Option Explicit Const SRowA = 9 Const ERowA = 32 Const SRowB = 39 Const ERowB = 62 Dim cn As Object Dim rs As Object Dim wb As Workbook Sub MainJob() Dim ShCnt As Long Dim KCode As String Set wb = Workbooks.Open(ThisWorkbook.Path & "\" & "顧客別管理.xlsx") 'SQL環境を準備 Set cn = CreateObject("ADODB.Connection") Set rs = CreateObject("ADODB.Recordset") cn.Provider = "Microsoft.ACE.OLEDB.12.0" cn.Properties("Extended Properties") = "Excel 12.0;HDR=Yes;IMEX=1" cn.Open ThisWorkbook.Path & "\1月顧客別商品別.xls" For ShCnt = 4 To wb.Sheets.Count - 2 KCode = wb.Sheets(ShCnt).Name Call Tenki(KCode, 11) '11列目に出力 Next ShCnt Set rs = Nothing '以下後処理 cn.Close Set cn = Nothing End Sub Sub Tenki(KCode As String, PutCol As Long) Dim SQL As String Dim i As Long 'SQL全文を組み立てて実行 SQL = "SELECT *" & vbCrLf SQL = SQL & "FROM [" & "集計$A1:E1000]" & vbCrLf 'SQL = SQL & "Where [顧客コード] = " & "'" & KCode & "'" & vbCrLf '注1 SQL = SQL & "Where [顧客コード] = " & KCode & vbCrLf '注2 rs.Open SQL, cn With wb.Sheets(KCode) 'マッチングして売上げ、粗利を転記 If Not rs.EOF Or Not rs.Bof Then rs.MoveFirst Do If rs.EOF = True Then Exit Do For i = SRowA To ERowA If .Cells(i, 1).Value = "" Then Exit For '注3 If .Cells(i, 1).Value = rs("商品コード") Then .Cells(i, PutCol).Value = rs("売上高") End If Next i rs.MoveNext Loop rs.MoveFirst Do If rs.EOF = True Then Exit Do For i = SRowB To ERowB If .Cells(i, 1).Value = "" Then Exit For '注3 If .Cells(i, 1).Value = rs("商品コード") Then .Cells(i, PutCol).Value = rs("粗利") End If Next i rs.MoveNext Loop End If End With rs.Close '後処理 End Sub
その他の回答 (5)
- chayamati
- ベストアンサー率41% (260/624)
>2つのExcelファイル(1月顧客別商品別.xlsと顧客別管理.xlsx)で 顧客コードと商品コードの双方が一致しているものの売上高と粗利を 顧客別管理.xlsxの対応欄(商品別になっている) ★どのように回答するのか、分りませんが以下がヒントに成りませんか >印があなたの分で、★印が回答です >(1月の売上高の入力欄:K9~K32、粗利の入力欄:K39~62)に入力 させるVBAを作りたく ★入力の制御はVBAでなくセルの書式の保護のロックと 書式の保護ツールです (1月の売上高の入力欄:A1に「売上高」、B1に「粗利」と入力して 「A2~A22」に1月の売上高の入力欄 「B2~B22」に1月の粗利の入力欄 >なお、前提条件として、 1月顧客別商品別.xls:集計シートのA~E列に顧客コード、 顧客名、商品コード、売上高、粗利が2行目以降並んでいます。 顧客別管理.xlsx:左から4枚目~最後から数えて3ページ目までの シートがそれぞれ顧客別のシートで、それぞれシート名が 顧客コードになっていて、B列に売上高の商品一覧(B9~B32)・粗利の 商品一覧(B39~B62)が並んでおり、検索しやすくなるために それぞれ対応する行のA列に商品コードを入力してあります。 ★これもVBAでなく、文字列結合(=C2&B2)とSUMIF()関数で 処理します。添付をご覧ください 何れにしろ他の回答者様の仰る通り、私もAccessをお勧めします。 利用料も他の宛名作成ソフト、セキュリティーソフトと大差有りません
- HohoPapa
- ベストアンサー率65% (455/693)
SQLを一部で使ったコードとしてみました。 よかったら試してみてください。 ただし、 顧客コードが文字列の場合は注1を生かし、注2をコメントアウトしてください。 また、 顧客別管理.xlsxのA9,B9以下とA39,B39以下が上詰めではない場合は 注3をコメントアウトしてください。 なお >"1月顧客別商品別.xls":”集計”シートのA~E列に >”顧客コード”、”顧客名”、”商品コード”、”売上高”、”粗利”が2行目以降並んでいます。 これは、顧客コードと商品コード組み合わせでは重複がないということでいいですよね? これを前提としたコードです。 それとも、重複があり、"顧客別管理.xlsx"に合計転記しますか? また、課題のブック2つとは別にマクロブック専用ブックを使うことを想定しています。 更に、 "1月顧客別商品別.xls"、こちらにあって、 "顧客別管理.xlsx"にない商品コードは想定していません。 つまり、マッチングしなかったものは、無視しています。 想定するのであれば、どのように扱えばいいのかを説明してみてください。 Option Explicit Const SRowA = 9 Const ERowA = 32 Const SRowB = 39 Const ERowB = 62 Dim cn As Object Dim rs As Object Dim wb As Workbook Sub MainJob() Dim ShCnt As Long Dim KCode As String Set wb = Workbooks.Open(ThisWorkbook.Path & "\" & "顧客別管理.xlsx") 'SQL環境を準備 Set cn = CreateObject("ADODB.Connection") Set rs = CreateObject("ADODB.Recordset") cn.Provider = "Microsoft.ACE.OLEDB.12.0" cn.Properties("Extended Properties") = "Excel 12.0;HDR=Yes;IMEX=1" cn.Open ThisWorkbook.Path & "\1月顧客別商品別.xls" For ShCnt = 4 To wb.Sheets.Count - 2 KCode = wb.Sheets(ShCnt).Name Call Tenki(KCode, 11) '11列目に出力 Next ShCnt Set rs = Nothing '以下後処理 cn.Close Set cn = Nothing End Sub Sub Tenki(KCode As String, PutCol As Long) Dim SQL As String Dim i As Long 'SQL全文を組み立てて実行 SQL = "SELECT *" & vbCrLf SQL = SQL & "FROM [" & "集計$A1:E1000]" & vbCrLf 'SQL = SQL & "Where [顧客コード] = " & "'" & KCode & "'" & vbCrLf '注1 SQL = SQL & "Where [顧客コード] = " & KCode & vbCrLf '注2 rs.Open SQL, cn With wb.Sheets(KCode) 'マッチングして売上げ、粗利を転記 If Not rs.EOF Or Not rs.Bof Then rs.MoveFirst Do If rs.EOF = True Then Exit Do For i = SRowA To ERowA If .Cells(i, 1).Value = "" Then Exit For '注3 If .Cells(i, 1).Value = rs("商品コード") Then .Cells(i, PutCol).Value = rs("売上高") End If Next i rs.MoveNext Loop rs.MoveFirst Do If rs.EOF = True Then Exit Do '注3 For i = SRowB To ERowB If .Cells(i, 1).Value = "" Then Exit For If .Cells(i, 1).Value = rs("商品コード") Then .Cells(i, PutCol).Value = rs("粗利") End If Next i rs.MoveNext Loop End If End With rs.Close '後処理 End Sub
- HohoPapa
- ベストアンサー率65% (455/693)
他の方のコメントに同意であり、 さすがに厳しいデータ構成と思いますし、 DBを使った仕組みが望ましいものの、 簡単に移行できるわけではないでしょう。 なので、現データ構成まま、若干泥臭いものの、 また、実用に耐えるかどうかはわかりませんが 若干効率のよさそうなコードを提示したいと思っています。 そこで、コーディングするにあたり、以下を教えてください。 ・1月顧客別商品別.xlsにはどの程度のレコード数がありますか? ・顧客別管理.xlsxにはどの程度のシート数がありますか? ・顧客コード、商品コードは数値ですか?、文字列ですか? ・顧客別管理.xlsxのA9,B9以下とA39,B39以下には、 上詰めでコードと商品名が埋まっていますか? それとも、空行が途中に含まれますか?
- imogasi
- ベストアンサー率27% (4737/17069)
(1)アクセスで処理されることを勧めます。SQLが使えるソフトを使うことですね。 >2つのExcelファイル("1月顧客別商品別.xls"と"顧客別管理.xlsx")においてをキーで結合し、結合したものを処理する。データをアクセスにエクスポートやエクセルにインポートは各1行で済むだろう。 そのキーは「顧客コードと商品コード」の2つでしょう。 こういうことに頭が行かないのは、エクセルしかやってなくて、データベースの処理の本途を知らないからです。見聞を広く持つべきです。 ーー (2)VBAで、SQL無しで、やるなら、両ファイルを、2つのキーでMatching(俗語の意味でなく、コンピュターの昔から使われたアルゴリズムの1つの名称)して、両ファイルの2つのキーが一致した、レコード(行データ)を捉えて項目(売上高と粗利)をどちらかファイルに、情報追加(項目追加)します。 このアルゴリズムは、情報処理の試験のアルゴリズムに出てきます。 マッチングはファイル情報結合の1つのやり方なのです。 ーー これは両ファイル(=両シートのデータ)をキー(顧客コード+商品コード(列))でソートしておいて処理に入ります。 そのためDictionary的なものを作らなくても済みます。昔は内部メモリーが少なく、Dictionary作成は 避けられた。効率のよい、ソートのソフトだけは、マシン・メーカーが全力で開発してくれていた。 ==== どちらかに考え直すことを、質問者の将来の仕事のため、スキルの拡充のために、勧める。 Googleで「マッチング アルゴリズム フローチャート」などで照会してみて。
- bardfish
- ベストアンサー率28% (5029/17766)
まず大前提。 ExcelではVBAを使用した対利用のデータ処理は不向きです。 データベースみたいにキーやインデックスがないんだからサーチはもの凄く遅い。改善の余地はない。 改善できるとしたら作業用のシートに処理しやすい形でデータを整理したモノを事前に作っておきそれを対象とする。 似たようなことで単純な内容(でもないけどw)をVBAでやったことありますが、本番データでのテストに時間がかかりすぎて、でも与えられた時間は少ないためぶち切れそうになったのでAccessで作り直しました。 処理にかかる時間が10分の1以下に短縮。 数百万行のデータ処理だったのでExcelだけでは(*>д<*)ムリー! Excelはデータを眺める目的なら最高のツールですけど、VBAを使用したデータ処理には剥いていない、と言うのをExcel95の時に悟りました。 Access2.0が出たら早速乗り換え。 Access95?だったかな、の頃にはOracleとSQL Serverに乗り換えました。 VBAが使えたのでプログラミング言語はVisual Basic。 VBは今なら無料で使えるモノがダウンロードできます。だけどマニュアルはない。ないけど普通に使ってSQLServerと組み合わせてデータ処理してます。 SQLServerも無料で使えるモノがダウンロードできる。もちろん説明書はない。だけどSQLServer4の時に覚えたことが今でも使えるのはある意味凄い。