- ベストアンサー
エクセルで表の変換
- エクセルで表の変換を行う際に、伝票・納品処理の省力化を目指しています。
- 具体的には、修理表から納品一覧を関数やマクロを使用して作成したいです。
- VBA初心者にとっては難しい処理ですが、過去ログなどを検索しても解決策は見つかりませんでした。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
1行に付き納品日が1個しか無いならピボットテーブル一発なんですけどね・・・。 メインルーチンであるNouListのトップのコメント欄を確認の上、定数定義部を適宜修正の上、以下コードをお試しください。 また、インデント保持の為、インデントを全角スペースに変換していますので、これを戻してから利用ください。 ハードコーディングをできるだけ避けたのと、コードの使いまわしのせいで、多少長くなっています。すみません。 +++++++ Option Explicit Option Base 1 Sub NouList() ' (注番,) 製番, 品名, 総数量, 納品日1, 納品数1, 納品日2, 納品数2 .... 'のフォーマットのリストを集計し '{strNOut}シートの ' 製番, 品名, 納品日1数量, 納品日2数量 .... 'の体裁に変換します '製番(品番)マスタは、{strNNum}({strNName})シートの{strADNum}({strADName})を先頭 '(ラベル除く)とする、空き行無しの列データとする 'ラベルを先頭行として、注番列を含めて元データを選択した状態で、マクロを実行する Const iCurY As Integer = 2005 '処理する年指定 Const iCurM As Integer = 10 '処理する月指定 Const strNNum As String = "Number" '製番マスタのシート名 Const strADNum As String = "B2" '製番マスタデータの先頭(ラベル除く)アドレス Const strNName As String = "Name" '品名マスタのシート名 Const strADName As String = "B2" '品番マスタデータの先頭(ラベル除く)アドレス Const strNOut As String = "Output" '出力先のシート名 Const strADOut As String = "B2" '出力先データの先頭アドレス Dim vBuf '元データセル範囲を格納 Dim lRN As Long, lCN As Long '元データセル範囲行数および列数 Dim rngNum As Excel.Range '製番マスタデータのセル範囲 Dim rngName As Excel.Range '品番マスタデータのセル範囲 Dim NLT() '日別納品数格納 Dim ND(31) As Boolean 'd日に納品が有ったかどうかのフラグ Dim ND2(31) As Integer '納品が有った日の一覧 Dim lNND2 As Integer '納品が有った日の数 Dim flgAri As Boolean '製番i品名jの納品が有ったかどうかのフラグ Dim vCurNum As Variant '現在処理中の製番またはその通し番号 Dim vCurName As Variant '現在処理中の品名またはその通し番号 Dim vCurItem As Variant '現在処理中のアイテム Dim i As Long, j As Long, k As Long, l As Long 'ループカウンタ With ThisWorkbook Set rngNum = ExpRngS(.Sheets(strNNum).Range(strADNum)) Set rngName = ExpRngS(.Sheets(strNName).Range(strADName)) ReDim NLT(rngNum.Rows.Count, rngName.Rows.Count, 31) End With If TypeName(Selection) = "Range" Then With Selection lRN = .Rows.Count lCN = .Columns.Count End With vBuf = Selection For i = 2 To lRN On Error GoTo InvData With Application.WorksheetFunction vCurItem = vBuf(i, 2) vCurNum = .Match(vCurItem, rngNum, 0) vCurItem = vBuf(i, 3) vCurName = .Match(vCurItem, rngName, 0) End With On Error GoTo 0 For j = 5 To lCN Step 2 If vBuf(i, j) = "" Then Exit For Else If Month(vBuf(i, j)) = iCurM Then NLT(vCurNum, vCurName, Day(vBuf(i, j))) = _ NLT(vCurNum, vCurName, Day(vBuf(i, j))) + vBuf(i, j + 1) ND(Day(vBuf(i, j))) = True End If End If Next j Next i With ThisWorkbook.Sheets(strNOut).Range(strADOut) .Offset(0, 0) = "品番" .Offset(0, 1) = "品名" i = 1 For k = 1 To 31 If ND(k) Then .Offset(0, i + 1) = DateSerial(iCurY, iCurM, k) ND2(i) = k i = i + 1 End If Next k lNND2 = i - 1 l = 1 For i = 1 To 5 For j = 1 To 5 flgAri = False For k = 1 To lNND2 If NLT(i, j, ND2(k)) <> "" Then .Offset(l, k + 1) = NLT(i, j, ND2(k)) flgAri = True End If Next k If flgAri Then .Offset(l, 0) = Application.WorksheetFunction.Index(rngNum, i, 1) .Offset(l, 1) = Application.WorksheetFunction.Index(rngName, j, 1) l = l + 1 End If Next j Next i End With Else MsgBox "集計範囲が選択されていません" End If Exit Sub InvData: MsgBox vCurItem & "がマスタに見つかりません" & Chr(10) & "集計を終了します" End Sub Function ExpRngS(ByVal TrgtRng As Range) As Range '対象範囲を下方向に拡張 '引数 ' TrgtRng: 処理対象範囲 Dim TrgtSht As Variant '処理対象シート格納 Dim LstRow As Long '最終行行番号格納用 Const xlMaxRow As Long = 65536 'ブック最終行を指定(97以降の時) '5,95では16384に変更する '初期化 Set TrgtSht = TrgtRng.Parent With TrgtRng '処理対象範囲が1セルのみのとき、拡張処理を実施 If .Cells.Count = 1 Then '一度下方向にEnd(xlDown)を計算 LstRow = .End(xlDown).Row '求めたLstRowまで範囲を拡張 Set ExpRngS = .Resize(LstRow - .Row + 1, 1) '対象範囲が複数セルなら拡張せずに返す Else Set ExpRngS = TrgtRng End If End With End Function
その他の回答 (2)
- Raistlin
- ベストアンサー率63% (65/102)
さらに追記 {納品月/日}データは、Excelが日付データと認識するデータ(日付シリアルであり、文字データとかではない)で、年も正しく入力されていることを前提としています。
- Raistlin
- ベストアンサー率63% (65/102)
以下明記すべきと思っていたのですが、書き忘れておりました。 ・オリジナルのデータでは、納品1の日付と数量が同じセルのように見えますが、集計処理を簡略化するため、別セルとしています(コメント行参照-ここで列はカンマで区切られており、これ以外の列や、空列は無いものとする)。 ・「選択範囲列がラベル行を含む」が守られなかった場合をチェックしていません。 >何と、私のやりたかった事って、こんな長い行数になるのですね。 自由度やエラーチェックを無視すれば、そんなに長くならないと思います。 例えば、マスタデータの範囲を決め打ちにして、毎回定数を書き直すようにすれば、Function ExpRngS()以下はいりませんし、最初の選択範囲のミスでエラーが出ようが知ったこっちゃ無いとかいうのであれば、エラーメッセージ部も要りません。 ですが、そこをおろそかにしすぎると、マクロがエラーを吐くたびに、オペレーターから呼び出しを食らう羽目になりますので・・・ >なかなかコメントをいただけないなぁ 1個アドバイスすれば終わり、というネタじゃありませんからね。 自由度とか考えてちょっと時間をかけたのでさらに・・・
お礼
おぉ~っ! 回答、うれしうございます。 早速貼り付けてあれこれ動作確認しておりますが、途中までは何とかいけるものの、エラーでダウン。もうちょっと当方が作成したテストデータ自体の調整が必要なようです。 残念ながら今日は時間がなく、明日職場で試してみます。結果は補足のほうででも…(^^)。 関数だけではどうあがいても解決できそうになかった(半月以上あーでもないこーでもない、と悩んでました(^^;)ので、Qを書き込みましたが、なかなかコメントをいただけないなぁ、やっぱり自分で汗を流すしかないか、とやむなくホコリをかぶっていたVBAの参考書を引っ張り出し、付け焼刃をしかけてましたが、何と、私のやりたかった事って、こんな長い行数になるのですね。 せっかくご回答いただいたのでこれを参考に何とかものにしたいと思います。とりあえず中間報告まで。
補足
Raistlinさん、お礼が遅くなりました。 おかげさまで、無事出荷担当宛てにリリースすることが出来ました。何とか使ってもらえているようです。 あれから頂いたサンプルを元にヘルプやVBAハンドブックを駆使(?)して自分なりに咀嚼しながらアレンジして行ったもので、ずいぶん時間がかかりましたが、少しは私自身のVBA経験値があがったかな(^^)?と喜んでいます。 ともあれ、大変お世話になりました。また何かありましたらよろしくお願いします。