
下記のようなデータがあります。
支店code顧客名属性顧客コード
A01ああああ10123456
A01いいいい10123457
A01うううう2
A01ええええ10123459
A55かかかか1
A55きききき20123461
A55くくくく30123462
B22ささささ40123463
B22しししし10123464
C56たたたた20123465
D88なななな10123466
全部で約800件ほどです。実際には顧客コード以降にも多くのデータがあります。
これを支店コードごとに別ブックに分割し、さらに顧客コードごとにそれぞれ別シートにしたいのです。(シート名は顧客名)
中には顧客コードが未記入のものがあり、その場合はそのデータは無視します。
とても手におえません。お助けいただけると幸いです。
No.8ベストアンサー
- 回答日時:
#4です。
> これには定義はないのでしょうか?
ChDir myPath があるので、ファイルのフォルダ名は省略しました。
ただ、数字だけの支店名で起こるエラーは、以下の方法で解決できそうですが、ファイル名にフォルダ名も含めなければならないようで、ChDir myPath は、削除してもよさそうです。
ブック作成での、
ActiveWorkbook.SaveAs Filename:=myPath & dSheet.Cells(i, 1).Value & ".xls" を
ActiveWorkbook.SaveAs Filename:=myPath & dSheet.Cells(i, 1).Text & ".xls"
に。支店ブックを開く時の、
Workbooks.Open c.Value & ".xls" を
Workbooks.Open myPath & c.Text & ".xls"
に変更してみてください。
あと、気になっていたのですが、最後のほうの
If c.Value = "" Then Exit For
は、いらなかったですね。他にもヘンなところがあるかと思いますが、大目に見てやってください。
この回答への補足
ありがとうございました。
支店コードが数字のみでも出来るようになりました。
あと、
For Each c In dSheet.Range("A1").CurrentRegion
Workbooks.Open c.Value & ".xls"
ですが、この c とはdSheet.Range("A1").CurrentRegion 内のセルという意味ですか?
その場合 Dim c As ~ とかの記述は必要ではないのですかという質問だったのですが。(For Each c In というのは今まで使ったことがないもので。不勉強ですみません)
No.9
- 回答日時:
> その場合 Dim c As ~ とかの記述は必要ではないのですか
必要です。Dim c As Range ですね。
書き忘れてました。(^_^;)
変数を型を指定して宣言しておくと、エラーの原因を見つけやすくなり、変数の型(データ型)の種類によっては処理速度が速くなったりするそうです。
モジュールの先頭で Option Explicit ステートメントを書いておけばいいのですが、ズボラな僕は書かないことが多いので、こういう事になります。
大変ありがとうございました。
おかげでこちらの加工もうまく出来ました。
大変勉強させていただき、またお助けいただき、感謝感激です。
これからもよろしくお願い致します。
No.7
- 回答日時:
続きです。
IDX_R = 1 'インデックスの初期設定
Do Until IDX_R >= UBound(wData, 1) '最終行になったらループを抜ける(条件1)
'---------------------------------------------第1ループ---------------------------------------------
'第1ループ前処理
ShitenKey = wData(IDX_R, 1) '支店キーの設定
Workbooks.Add '新しいブックを作成
Set wNewBook = ActiveWorkbook '新しいブックをwNewBookに設定
Set wCurrentSheet = ActiveSheet '新しいブックのアクティブシートをwCurrentSheetに設定(これが貼り付け対象のシート)
Do Until IDX_R >= UBound(wData, 1) Or _
ShitenKey <> wData(IDX_R, 1) '(条件1)又は、支店が変わったら(条件2)ループを抜ける
'---------------------------------------------第2ループ---------------------------------------------
'第2ループ前処理
KokyakuKey = wData(IDX_R, 4) '顧客コードキーの設定
With wCurrentSheet
.Name = KokyakuKey 'シート名を顧客コードにする
.Range(.Cells(1, 1), .Cells(1, 4)).Value = wTitle '1行目にタイトルを設定
End With
CurrentRow = 2 'データを貼り付ける行の初期値設定 '
Do Until IDX_R >= UBound(wData, 1) Or _
ShitenKey <> wData(IDX_R, 1) Or _
KokyakuKey <> wData(IDX_R, 4) '(条件1)又は、(条件2)又は、顧客コードが変わったら
'---------------------------------------------第3ループ---------------------------------------------
'第3ループ処理
With wCurrentSheet
.Range(.Cells(CurrentRow, 1), .Cells(CurrentRow, 4)).Value = Array( _
wData(IDX_R, 1), wData(IDX_R, 2), wData(IDX_R, 3), wData(IDX_R, 4))
'↑データの貼り付け(1~4カラムに1度に値を設定しています)
'***関数を入れるとしたらこのあたりでしょう***
End With
IDX_R = IDX_R + 1 'データインデックスのカウントアップ
CurrentRow = CurrentRow + 1 'データを貼り付ける行のカウントアップ
'---------------------------------------------第3ループ---------------------------------------------
Loop
'第2ループ後処理
With wNewBook
.Sheets.Add After:=.Sheets(.Sheets.Count) '新しいシートを作成
End With
Set wCurrentSheet = ActiveSheet 'アクティブシートをwCurrentSheetに設定(貼り付け対象シートの切り替え)
'---------------------------------------------第2ループ---------------------------------------------
Loop
'第1ループ後処理
Application.DisplayAlerts = False 'アラートが出ないようにする
wCurrentSheet.Delete '余分なシートの削除
Application.DisplayAlerts = True 'アラートが出るようにする
With wNewBook
.Sheets(1).Activate '1枚目のシートをアクティブにする。
.SaveAs SavePath & wNow & ShitenKey & ".xls" 'ブックの保存(重複しないように、最初に取得した時刻をファイル名に含める)
.Close 'ブックを閉じる
End With
'---------------------------------------------第1ループ---------------------------------------------
Loop
ここの処理は#2の方が説明されている文章をコード化したものです。
1行目から順番に読み込んでキーが変わったら(ブレイクしたら)何らかの
処理をする。といった感じです。
3重のループを使用していて文章で説明するより各行のコメントを参考にした方が
わかりやすいと思います。(手抜き?^^;)
※ここは、特にHTMLソースを見た方がわかりやすいですよ。
というわけで、説明はこれくらいで・・・
わかりにくい説明があったら指摘してくださいね。
では、いい仕事してくださいね!
No.6
- 回答日時:
こんにちは。
コメントなしの読み辛いソースですみませんでした。
ご存知だとはかもしれませんが、ソースはページをそのままコピーするより
ソースから拾い出してエディタでタグとか記号を変換したほうが字下げがある
ので少しは読みやすいですよ。
では、かいつまんで説明しますね。
With Application
.ScreenUpdating = False
wSheetsInNewWorkbook = .SheetsInNewWorkbook
.SheetsInNewWorkbook = 1
End With
ここでは、画面の更新を止めて、新しくブックを開いた時に1つだけ
シートを開くように設定しています。設定の前に、
wSheetsInNewWorkbook = .SheetsInNewWorkbook
としているのは現在の設定を保存して最後に戻す為です。
ただし、エラー処理を考慮していないので途中でエラーになって止まって
しまったときやマクロの実行を強制的に止めた時などは手動で設定し直さ
なければなりません。この点は改善の余地ありです。
Sheets(1).Copy After:=Sheets(1)
Set wSheet = ActiveSheet
ここでは、ソートする為の前処理としてデータのあるシートをコピーして
元のデータが残るようにしています。そして以降ソートするページをわかりやすく
するために、オブジェクト変数のwSheetにSetしています。
ただし(また^^;)、前提として1枚目のシートにデータがあると仮定しているので、
Const wDataSheetName As String = "データシート"
Sheets(wDataSheetName).Copy After:=Sheets(wDataSheetName)
みたいな感じで記述した方がシート名が変わった時もConst宣言を変更するだけでいいので
保守性がよくなると思います。(改善点2)
次はソートの部分です。
最初の投稿時にも書きましたがエクセルらしいやり方です。(と勝手に思ってる^^;)
StartRow = 3
With wSheet
wTitle = .Range(.Cells(2, 1), .Cells(2, 4))
EndRow = .Cells(65536, 1).End(xlUp).Row
Set wDataRange = .Range(.Cells(StartRow, 1), .Cells(EndRow, 4))
wDataRange.Sort _
Key1:=.Cells(StartRow, 4), Order1:=xlAscending, _
Header:=xlNo
EndRow = .Cells(65536, 4).End(xlUp).Row
Set wDataRange = .Range(.Cells(StartRow, 1), .Cells(EndRow, 4))
wDataRange.Sort _
Key1:=.Cells(StartRow, 1), Order1:=xlAscending, _
Key2:=.Cells(StartRow, 4), Order2:=xlAscending, _
Header:=xlNo
wData = .Range(.Cells(StartRow, 1), .Cells(EndRow + 1, 4))
Set wDataRange = Nothing
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
End With
Set wSheet = Nothing
ざっと見てもらったら、わかると思いますが2回ソートしています。
最初のソートはデータの3行目から顧客番号の昇順にソートしています。
これは「顧客コードが未記入のものがあり、その場合はそのデータは無視」
と言う条件があるので、未記入のデータを取り除くためです。
コツは最終行の設定方法で、1回目は
EndRow = .Cells(65536, 1).End(xlUp).Row
として、支店が最後に入力されている行を最終行としているのに対して、2回目は
EndRow = .Cells(65536, 4).End(xlUp).Row
として、顧客番号が最後に入力されている行を最終行としているのです。
途中にソートを入れることによって顧客番号が未入力の行は下の方に集まるので
結果として顧客番号未入力のデータは無視されることになるのです。
そして、2回目のソートでは支店、顧客番号の順番にソートし直しています。
ソートが終わったら、
wData = .Range(.Cells(StartRow, 1), .Cells(EndRow + 1, 4))
バリアント型の変数wDataにソート後の値をすべてぶち込んでいます。
これは、この後の処理でRangeオブジェクトの参照を出来るだけ減らす事によって
処理速度を改善するためです。
ここの注意点は最終行を"EndRow + 1"として1行余分にデータを取り込むことによって
以降の処理でテーブルオーバーを起こさないようにすることです。
----------------------
長いので、いったん投稿します。
No.5
- 回答日時:
おもしろそうなので、作ってみました。
ちょっと、ややこしいですが・・・
でも、処理は早いと思いますよ。
ソートの部分はExcelらしくしましたが、
分割部分はただのコントロールブレイクです。
調子に乗って作ってたら遅くなってしまったので
コメントと解説は省きます。
(フォローできる方がいたらお願いします)
暫くクローズせずにおいといてもらえるなら、
明日か明後日にでも補足します。
-----------------------------------------------
Private Sub XXX()
Dim wNewBook As Excel.Workbook
Dim wCurrentSheet As Excel.Worksheet
Dim wSheet As Excel.Worksheet
Dim wDataRange As Excel.Range
Dim wNow As String
Dim wSheetsInNewWorkbook As Long
Dim wTitle As Variant
Dim wData As Variant
Dim IDX_R As Long
Dim StartRow As Long
Dim EndRow As Long
Dim CurrentRow As Long
Dim ShitenKey As String
Dim KokyakuKey As String
Const SavePath As String = "D:\temp\"
With Application
.ScreenUpdating = False
wSheetsInNewWorkbook = .SheetsInNewWorkbook
.SheetsInNewWorkbook = 1
End With
Sheets(1).Copy After:=Sheets(1)
Set wSheet = ActiveSheet
wNow = Format$(Now, "YYYY-MM-DD-HH-NN-SS_")
StartRow = 3
With wSheet
wTitle = .Range(.Cells(2, 1), .Cells(2, 4))
EndRow = .Cells(65536, 1).End(xlUp).Row
Set wDataRange = .Range(.Cells(StartRow, 1), .Cells(EndRow, 4))
wDataRange.Sort _
Key1:=.Cells(StartRow, 4), Order1:=xlAscending, _
Header:=xlNo
EndRow = .Cells(65536, 4).End(xlUp).Row
Set wDataRange = .Range(.Cells(StartRow, 1), .Cells(EndRow, 4))
wDataRange.Sort _
Key1:=.Cells(StartRow, 1), Order1:=xlAscending, _
Key2:=.Cells(StartRow, 4), Order2:=xlAscending, _
Header:=xlNo
wData = .Range(.Cells(StartRow, 1), .Cells(EndRow + 1, 4))
Set wDataRange = Nothing
Application.DisplayAlerts = False
.Delete
Application.DisplayAlerts = True
End With
Set wSheet = Nothing
IDX_R = 1
Do Until IDX_R >= UBound(wData, 1)
ShitenKey = wData(IDX_R, 1)
Workbooks.Add
Set wNewBook = ActiveWorkbook
Set wCurrentSheet = ActiveSheet
Do Until IDX_R >= UBound(wData, 1) Or _
ShitenKey <> wData(IDX_R, 1)
KokyakuKey = wData(IDX_R, 4)
With wCurrentSheet
.Name = KokyakuKey
.Range(.Cells(1, 1), .Cells(1, 4)).Value = wTitle
End With
CurrentRow = 2
Do Until IDX_R >= UBound(wData, 1) Or _
ShitenKey <> wData(IDX_R, 1) Or _
KokyakuKey <> wData(IDX_R, 4)
With wCurrentSheet
.Range(.Cells(CurrentRow, 1), .Cells(CurrentRow, 4)).Value = Array( _
wData(IDX_R, 1), wData(IDX_R, 2), wData(IDX_R, 3), wData(IDX_R, 4))
End With
IDX_R = IDX_R + 1
CurrentRow = CurrentRow + 1
Loop
With wNewBook
.Sheets.Add After:=.Sheets(.Sheets.Count)
End With
Set wCurrentSheet = ActiveSheet
Loop
Application.DisplayAlerts = False
wCurrentSheet.Delete
Application.DisplayAlerts = True
With wNewBook
.Sheets(1).Activate
.SaveAs SavePath & wNow & ShitenKey & ".xls"
.Close
End With
Loop
With Application
.ScreenUpdating = True
.SheetsInNewWorkbook = wSheetsInNewWorkbook
End With
Set wNewBook = Nothing
Set wCurrentSheet = Nothing
End Sub
-----------------------------------------------
ありがとうございました。
テストデータでやってみたらうまく行きました。
ただ、実際には分割したブックの各シートにそれぞれ数式を埋め込む作業があるので書いていただいたコードを必死で理解しようとしているところです。
なかなかわかりませんので解説していただけると幸いです。
なお、データは支店コードで順番にならんでいますのでソートは必要ないと思うのですが。
No.4
- 回答日時:
#3です。
やっぱり#2さんの方法が、きれいなコードが出来そうですね。
僕のだと顧客コードに重複があると、同じ名前のシートを作ろうとして必ずエラーになります。これを避けようとするとコードが複雑になるし、実行時間も余分にかかることになります。また、同一顧客のデータをシートにまとめるのにも、ソートしてあったほうが楽に出来そうです。
この回答への補足
ありがとうございます。だいぶわかってきました。
ただ、
For Each c In dSheet.Range("A1").CurrentRegion
Workbooks.Open c.Value & ".xls"
のところで変数c (支店コードですよね?)がいきなり出てくるのですが、これには定義はないのでしょうか?
それから支店コードがA01のような文字列の場合は正常にうごきましたが、335のような数字だとエラーになりました。
どう対処すればいいでしょうか?お教えください。
No.3
- 回答日時:
これだけで実用に耐えられるとは思いませんので、ご参考までに。
手を入れやすいように機能別に分けて書いたつもりです。データ中の顧客コードは、重複は無いものとしています。
Sub test()
Dim dSheet As Worksheet, Siten As Range, i As Long, n As Long
Dim Kyaku As Range, Data As Range, mySh As Worksheet, myPath As String
myPath = "C:\Documents and Settings\Owner\デスクトップ\分割\" '-----パス名を環境に合わせて変更してください。
Application.ScreenUpdating = False
Set Data = Worksheets(1).Range("A1").CurrentRegion
'-------------------------------------------------------------------支店の取得
Set Siten = Data.Columns(1)
Set dSheet = Worksheets.Add(After:=Worksheets(1)) '作業用シート
For i = 3 To Siten.Rows.Count
If Application.WorksheetFunction.CountIf(dSheet.Columns(1), Siten.Rows(i).Value) = 0 Then
n = n + 1
dSheet.Columns(1).Rows(n).Value = Siten.Rows(i).Value
End If
Next
'------------------------------------------------------------------ブック作成
For i = 1 To dSheet.Range("A1").CurrentRegion.Rows.Count
Workbooks.Add
ActiveWorkbook.SaveAs Filename:=myPath & dSheet.Cells(i, 1).Value & ".xls"
ActiveWorkbook.Close SaveChanges:=True
Next
'-------------------------------------------------------------------シート作成
Set Kyaku = Data.Columns(2)
ChDir myPath
For Each c In dSheet.Range("A1").CurrentRegion
Workbooks.Open c.Value & ".xls"
For i = 3 To Kyaku.Rows.Count
If Siten.Rows(i).Value = c.Value And Data.Columns(4).Rows(i).Value <> "" Then
Worksheets.Add After:=Worksheets(Worksheets.Count)
ActiveSheet.Name = Kyaku.Rows(i).Value
ActiveSheet.Range(Data.Address).Rows(1).Value = Data.Rows(i).Value
End If
Next
For Each mySh In Worksheets
Application.DisplayAlerts = False
If Left(mySh.Name, 5) = "Sheet" Then '余分なシートの削除
If ActiveWorkbook.Worksheets.Count <> 1 Then mySh.Delete
End If
Next
ActiveWorkbook.Close SaveChanges:=True
If c.Value = "" Then Exit For
Next
dSheet.Delete
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
エクセルの仕様では、ブック中のワークシートの数はメモリに依存すると思いました。数が多くなりそうですが、大丈夫なのでしょうか。
ありがとうございました。
テストデータでやってみたらうまく行きました。
ただ、実際には分割したブックの各シートにそれぞれ数式を埋め込む作業があるので書いていただいたコードを必死で理解しようとしているところです。
なかなかわかりませんが。
No.2
- 回答日時:
これは下記ロジックが単純で、古く(コンピュタ初期から事務計算で)から使われていて最適法と思います。
(1)まず支店コード(第1キー)、顧客コード(第2キー)(必要あれば第3キーを考える)でエクセルでソート
する。(エクセルで幸いソート出来ます。昔はソート・マージプログラムでやりました。)
(2)各行全800行について、直前の行レコードと比べて、A支店コードが変わったか(不等か)
B顧客コードが変わったか(同じでないか)
を見ます(コントロールブレイクという。支店別、顧客別にページ変えをする時必須のテクニックでした)。
直前の行の第1キー、第2キーは変数に記憶します。
(3)支店コードが変わったら、前(現在)のブックはクローズし、新しいブックをオープンします。
行ポインタは、次の第1シートの最初行を指す。
(4)顧客コードが変ったら、別シートに書きに行きます。行ポインタは次のシートの最初行を指す。
(5)骨格だけなら10行ぐらいかなと思います。
ソートが済むと、総なめ比較をしなくても良いのが重宝するのです。「存在するかチェックする」のところで総なめ
が行われ方法が多いです。これを昔は嫌いました。今はCPUのスピードがUPして、平気化してるようです。
ありがとうございます。
今回のデータはソートしなくとも順番にならんでいますのでいいと思うのですが、自分ではとてもとても・・・。
お恥ずかしいです。
No.1
- 回答日時:
単純に支店Codeだけで分割するなら…
まず、データファイルを格納するフォルダを指定しておきます。
※ その配下にファイル名を支店Codeと同じものにしてファイルを作成していきます。
If文の条件で、支店Codeを抜き出します。
抜き出した支店Codeと同じファイル名が存在するかチェックします。
※ 支店Codeと同名のファイル存在する場合それをオープンする。
※ 支店Codeとして同名ファイルが無い場合は作成してオープンする。
あとは、支店Codeを抜き出した行をオープンしたファイルの最終行に書き込めば完了です。
これを元ファイルの最終行まで繰り返す様にループしてください。
参考URL:http://www.eastwest-net.co.jp/vba/
この回答への補足
さっそくありがとうございます。
自分でもなんとかここまでは出来たのですが、顧客名をシート名にして顧客のデータを1シートづつにする方法が分からないのです。
Sub BUNKATSU_2()
Dim wb As Workbook
Dim StartRow As Integer
Dim EndRow As Integer
Dim 新ファイル名 As String
i = 3 '(2行目までタイトルのため)
StartRow = 3
Do
DoEvents
ThisWorkbook.Activate
If Cells(i, 1).Value <> Cells(i + 1, 1).Value Then
EndRow = i
Range("1:2," & StartRow & ":" & EndRow).Copy
Set wb = Workbooks.Add
wb.Activate
wb.Sheets("Sheet1").Range("A1").Select
ActiveSheet.Paste
Application.CutCopyMode = False
新ファイル名 = Cells(3, 1)
ChDir "C:\Windows\デスクトップ\分割"
ActiveWorkbook.SaveAs FileName:="C:\Windows\デスクトップ\分割\" & 新ファイル名 & ".xls"
ActiveWindow.Close
StartRow = i + 1
End If
i = i + 1
Loop Until (Cells(i, 1).Value = "")
End Sub
これで支店コード名のファイルは出来るのですが・・・。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) 指定月分の顧客データファイルを統合して並べ替え、所定の場所に貼り付ける 3 2022/09/10 07:55
- PDF PDFファイルを分割するマクロの作り方を教えてください。 2 2022/06/24 11:09
- Visual Basic(VBA) 指定月分の顧客データファイルを統合して並べ替え、所定の場所に貼り付ける (再質問) 4 2022/09/14 22:51
- Access(アクセス) 対象月の2桁表示について 1 2023/01/07 05:08
- Excel(エクセル) Excel 指定した固有番号で、複数の行を削除する方法は? 2 2022/03/30 15:18
- Visual Basic(VBA) エクセルのマクロについて教えてください。 1 2023/08/03 11:27
- その他(開発・運用・管理) マイクロソフト製品のライセンス販売で困ってます 1 2022/06/30 19:52
- Visual Basic(VBA) VBAコードを張り付け後のエクセルの進め方 2 2023/02/07 18:24
- Visual Basic(VBA) 複数ページあるPDFファイル内の文字列等の情報をキーにPDFをグループ分け分割したい。 2 2022/06/25 09:51
- その他(ソフトウェア) 現在と過去の顧客名簿、新規・解約・更新など作りたいのですが「やよいの顧客管理」なら簡単に扱えますか? 1 2022/05/18 10:44
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
ACCESSのVBAにてExcelのシ...
-
excelのInitializeイベントとAc...
-
教えて下さい
-
配列数式の解除
-
特定のPCだけ動作しないVBAマク...
-
エクセルで特定の列が0表示の場...
-
マクロの連続印刷が突然不可能...
-
UserForm1.Showでエラーになり...
-
多量のSUMIF式を軽くしたい
-
メッセージボックスのOKボタ...
-
Excel_マクロ_現在開いているシ...
-
TERA TERMを隠す方法
-
Excel vbaについての質問
-
マクロで"#N/A"のエラー行を削...
-
お助けください!VBAのファイル...
-
インポート時のエラー「データ...
-
【VBA】ワークブックを開く時に...
-
ダブルクリックで貼り付けた画...
-
一つのTeratermのマクロで複数...
-
マクロ実行時エラー
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
excelのInitializeイベントとAc...
-
ACCESSのVBAにてExcelのシ...
-
同一ブック内・別シートの内容...
-
Excelマクロ 別シートへ連続コ...
-
エクセルVBAでブックの分割
-
エクセル2010の内容を次のシー...
-
ExcelVBA: 5行ごとにテキスト...
-
複数のシートでマクロの実行
-
エクセルマクロ シートの追加
-
excel sheet の整理をしたいです
-
VBAで繰り返し処理の速度を...
-
VBAについて
-
ExcelVBAを使っての振り分け処理
-
オートシェイプの不具合について
-
【VBA】セルとシート操作の繰り...
-
複数シート内容を1 シートに纏...
-
excel
-
配列数式の解除
-
特定のPCだけ動作しないVBAマク...
-
マクロOn Error GoTo ErrLabel...
おすすめ情報