• 締切済み

マクロの処理速度が遅い コピペ→削除→名前付保存

マクロの処理速度が遅いため、大変困っています。お忙しいところ恐縮ですが、アドバイスいただけませんでしょうか。よろしくお願い致します。 作業は、30行×54列のデータの、コピペ→削除(ここまで4~5秒)→名前を付けて保存(トータル9~10秒)です。 30行はテストで、本当は500~1000行のデータを処理したいのですが、とても時間がかかり、PCが動かなくなってしまうこともあります。 ご指摘、いろいろあるかと思うのですが、細かな点でも教えてください。どうぞよろしくお願い致します。 詳細は、 元ファイルの"シート(1)”のデータ(●行×54列)を ファイル(原紙)を開き、ファイル(原紙)の"貼り付け”のシートに貼り付けます。 元ファイルの"シート(1)”のデータ(●行×54列)は、元ファイルの"シート(2)”に移動します。 元ファイルの"シート(1)”のデータ(●行×54列)を削除します。 ファイル(原紙)に、日付ー■(通し番号)をつけて、保存します。 ■は、保存先フォルダを確認し、通し番号にしています。 元ファイルは、他のシートにもいろいろデータがあり、7MBほどです。 時間測定の部分は、本番では不要です。 Sub test5() Dim startTime As Double Dim endTime As Double Dim processTime As Double '開始時間取得 startTime = Timer Dim s1 As Worksheet Set s1 = ActiveSheet Dim nPasteRow As Double Dim sHozon As String Dim sFilename As String '画面描画を静止 Application.ScreenUpdating = False '自動再計算の停止 Application.Calculation = xlManual '警告メッセージを非表示 Application.DisplayAlerts = False '***************************************** ' 元ファイルのシート(1) から ファイル.xls へ移動 '***************************************** 'ファイルを開く Workbooks.Open "C:\Users\yyy\OneDrive\デスクトップ\フォルダー\ファイル.xls" Sheets("貼り付け").Select Set wbData = ActiveWorkbook '最終行へ移動 If Range("A5").Value = "" Then nPasteRow = 5 ElseIf Range("A6").Value = "" Then nPasteRow = 6 Else nPasteRow = Range("A5").End(xlDown).Row + 1 End If Dim i As Long Dim m As Long For i = 5 To s1.Range("A4").End(xlDown).Row For m = 1 To 54 wbData.Sheets("貼り付け").Cells(nPasteRow + i - 5, m).Value = s1.Cells(i, m).Value Next m Next i '*************************** ' 元ファイルのシート(1) から シート(2)へ移動 '*************************** Workbooks("元ファイル.xlsm").Activate Dim s2 As Worksheet Set s2 = ActiveSheet '最終行へ移動 If Range("A3").Value = "" Then nPasteRow = 3 ElseIf Range("A4").Value = "" Then nPasteRow = 4 Else nPasteRow = Range("A3").End(xlDown).Row + 1 End If Dim n As Long Dim o As Long For n = 5 To s1.Range("A4").End(xlDown).Row For o = 1 To 54 s2.Cells(nPasteRow + n - 5, o).Value = s1.Cells(n, o).Value Next o Next n '***************** ' 移動した行削除 '***************** Sheets("シート(1)").Rows("5:" & Range("A4").End(xlDown).Row).Delete ActiveWorkbook.Save '******************** ' 行削除後の処理 '******************** Dim str1 As String Dim str2 As String Dim nCnt As Integer 'ファイルを開いた場合、名前をつけて保存を行う Workbooks("ファイル.xls").Activate '保存場所を指定 sHozon = "C:\Users\yyy\OneDrive\デスクトップ\フォルダー" For nCnt = 1 To 20 'ファイル名を設定 sFilename = "ファイル" & Replace(Date, "/", "") & "-" & nCnt & ".xls" Range("D2").Value = "ファイル" & Replace(Date, "/", "") & "-" & nCnt 'ファイルが存在しているか確認 str1 = sHozon & "\" & sFilename str2 = Dir(str1) If (str2 <> sFilename) Then 'ファイルが存在しない場合、保存 '名前をつけて保存 ActiveWorkbook.SaveAs Filename:= _ sHozon & "\" & sFilename, _ FileFormat:=xlNormal, Password:="", WriteResPassword:="", _ ReadOnlyRecommended:=False, CreateBackup:=False Sheets("処理(1)").Select Application.Goto Reference:=Range("E1"), Scroll:=True Exit For End If Next '自動再計算の再開 Application.Calculation = xlAutomatic '画面描画を開始 Application.ScreenUpdating = True '警告メッセージを表示 Application.DisplayAlerts = True '終了時間取得 endTime = Timer '処理時間表示 processTime = endTime - startTime MsgBox "処理時間:" & processTime End Sub

みんなの回答

  • HohoPapa
  • ベストアンサー率65% (455/693)
回答No.5

他の方々からアドバイスがあるように、 Dim i As Long Dim m As Long For i = 5 To s1.Range("A4").End(xlDown).Row For m = 1 To 54 wbData.Sheets("貼り付け").Cells(nPasteRow + i - 5, m).Value = s1.Cells(i, m).Value Next m Next i や、 Dim n As Long Dim o As Long For n = 5 To s1.Range("A4").End(xlDown).Row For o = 1 To 54 s2.Cells(nPasteRow + n - 5, o).Value = s1.Cells(n, o).Value Next o Next n のような繰り返しの処理ではなく 複数セル範囲を1回で複写したほうが効率的と思います。 前者を例にすれば、私だったら '//-------------------------------- Dim fsr As Long '複写元範囲開始行 Dim fsc As Long '複写元範囲開始列 Dim fer As Long '複写元範囲終了行 Dim fec As Long '複写元範囲終了列 fsr = nPasteRow fer = nPasteRow + s1.Range("A4").End(xlDown).Row - 5 fsc = 1 fec = 54 Dim tsr As Long '複写先範囲開始行 Dim tsc As Long '複写先範囲開始列 Dim ter As Long '複写先範囲終了行 Dim tec As Long '複写先範囲終了列 tsr = 5 tsc = 1 ter = s1.Range("A4").End(xlDown).Row tec = 54 Range(wbData.Sheets("貼り付け").Cells(fsr, fsc), wbData.Sheets("貼り付け").Cells(fer, fec)).Value = _ Range(s1.Cells(tsr, tsc), s1.Cells(ter, tec)).Value '//-------------------------------- といったコードにします。 (動作確認していませんので、参考にするときはしっかりチェックしてください。 一方、この部分が原因で >とても時間がかかり、PCが動かなくなってしまうこともあります。 ここまで悲惨な状況にはならないように思います。 たかだか1000行ですから。 気になるのは、 > Workbooks.Open "C:\Users\yyy\OneDrive\デスクトップ\フォルダー\ファイル.xls" この部分です。 課題マクロブックなどをOneDrive、あるいは OneDriveと同期をとったフォルダーに配置している場合 いらぬ同期やi/oが起き、指摘の症状になる可能性があるものと思います。 先に説明したコードの改修に加え、 OneDriveとは無縁な場所で実行してみてください。

kometoshi555
質問者

お礼

ありがとうございます。 1回の複写、間違えていました。 まとめてイコールということですね。 間違い→Range("A3:BD" & Range("A2").End(xlDown).Row).Select Selection.Copy Range("A" & nPasteRow & ":BD" & nPasteRow).Select Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks:=False, Transpose:=False ファイルの保存先についての助言もありがとうございます。実環境で確認してみたいと思います。 終盤に2か所、ファイルの保存を入れているのですが、F8で見ていったときに保存のところで時間がかかるように思います。こちらも実環境で改めて確認してみたいと思います。 まずはお礼申し上げます。

全文を見る
すると、全ての回答が全文表示されます。
  • kon555
  • ベストアンサー率51% (1776/3417)
回答No.4

 多分ですが、他のプログラムなどの経験はあるためVBA自体は構築可能なものの、エクセル操作自体には詳しくない感じですね?  貴方の今のコードは、セルを一つコピーしてペーストして、次のセルをコピーしてペーストして・・・、という処理になっています。  30行×54列程度なら、範囲で選択してコピーする形にすれば実用に耐える速度が実現できますよ。  ここまで組めるなら、この辺りを参考にすればすぐに分かると思います。 http://officetanaka.net/excel/vba/cell/cell10.htm  もっと大量のデータになるなら、一旦配列としてデータを取り込む事も出来ますが、1000行×54列程度なら不要だとは思います。  ただ求めている速度次第でもあるので、参考ページを紹介しておきます。 http://officetanaka.net/excel/vba/speed/s11.htm http://officetanaka.net/excel/vba/tips/tips124.htm  vbaで何かする場合、基本的には「セルを操作する回数を減らす」のが速度アップに有効です。  VBAはよく『遅い』と言われがちですが、かなりの量のデータでも、今のPCならコード次第で充分な速度になります。そもそも事務処理にゼロコンマ数秒の速度差は実質無意味ですからね。  ただそのためには『プログラムの知識』だけでなく『Excelの操作方法の知識』と『vbaの仕様』を覚える必要があるため、ちょっと誤解されやすいのかなぁ、と思っていますが。

kometoshi555
質問者

お礼

ありがとうございます。 必要に駆られて、調べながら、助けていただきながらという状況です。 参考ページ、ありがとうございます。 配列もわかっていないのですが、2次元配列でできるのでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • bardfish
  • ベストアンサー率28% (5029/17765)
回答No.3

COMオブジェクトとして処理しているように見えますが、意識はしていないでしょうね。 WindowsのCOMオブジェクトというのはレガシィテクノロジで今となっては処理速度では最低レベルです。 COMを使っている限り今より爆速になることはないでしょう。 私もExcel VBAを使用して10万行規模のシートをと処理するVBAを扱いましたがとてもじゃないけどおそすぎて我慢できなくなったのでAccessで作り直しました。 その御蔭で10分近くかかっていた処理が90秒で完了するまでに高速化。 最近ではAccessでも別の問題が浮上してきたためにSQL ServerとVisualBasic .NETでさらに作り直そうかと考えています。 Excel VBAが.NETに対応すれば今以上の高速化が期待できるんですけどね。VB.netでエクセルワークシートを使用するプログラムを作っても、ものすごく遅いです。改めて使いたくないと思いました(笑) ということで、Excel VBAの処理というのは・・・ちょっとしたことをやらせるなら便利でしょうが、大量のデータ処理には向かないと思っています。Excelが登場したときからそういう印象を持っていたのでExcelはかなり便利な電卓以上には考えたことがないです。 ちなみに、SQL Server、VisualBasicは無料でDownload、インストール、使用できます。 VisualStudio Codeというエディターもありますが、JavaやPythonなどの開発/実行も可能。環境を正しく構築できていればリアルタイム構文チェックもやってくれます。

kometoshi555
質問者

お礼

ありがとうございます。 エクセルの関数からスタートして、限界を感じVBAをかじっています。 新しいことに取り組むことも考えたいと思います。

全文を見る
すると、全ての回答が全文表示されます。
noname#245936
noname#245936
回答No.2

補足で、うろ覚えですがcells関数で座標軸はA1などではなく数学で指示可能。 Rangeで矩形選択できたかと。

kometoshi555
質問者

お礼

ありがとうございます! まとめてイコールするということですね。 やってみようと思います。

全文を見る
すると、全ての回答が全文表示されます。
noname#245936
noname#245936
回答No.1

画面の更新をOFFに、と言いたいところでしたがすでにできていますので。 あとはコピペの部分を1セルごとにループさせないで矩形範囲選択でコピー貼り付けさせると爆速になると思います

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • VBAエラー

    下のもので、 rangeクラスのselectメソッドが失敗しました がでてしまいます。 ★★★のところで止まってしまいます。 1つ目のエクセルで、ファイル名を入力、検索して開き、8行目でオートフィルタをするマクロです。 オートフィルタのところで止まります。 どこが悪いのか、ご教授いただけませんでしょうか。 よろしくお願い致します。 Sub ファイルを開く()  Dim str As String   Dim nCnt As Integer  Dim sHozon As String  Dim sFilename As String Dim Grp As String If Range("B2").Value <> "バーコード読み取り" Then '保存場所を指定 sHozon = "※※※" Grp = Right(Range("B2"), Len(Range("B2")) - InStr(Range("B2"), "F")) 'ファイル名を設定 sFilename = "AA" & Left(Range("B2"), 10) & ".xls" 'ファイルが存在しているか確認 str = sHozon & "\" & sFilename str = Dir(str) If (str <> sFilename) Then 'ファイルが存在しない場合、エラー MsgBox ("ファイルが存在しません") Else 'ファイルを開く Range("B2").Select Workbooks.Open sHozon & "\" & sFilename End If End If Workbooks(sFilename).Activate Sheets("B").Select ActiveSheet.Unprotect Workbooks(sFilename).Activate Rows("8:8").Select   ★★★ Selection.AutoFilter ActiveSheet.Range("$A$8:$BL$1008").AutoFilter Field:=58, Criteria1:=Grp

  • VBA マクロ処理時間の短縮について

    下記のコードを作りましたが、マクロを実行すると砂時計マークが表示されて、処理が終了するまでに30秒くらいかかります。 コードを変更して、マクロ処理時間を短縮する事はできないでしょうか? Sub A列のコピー() Dim rw2 As Long Dim rw1 As Long Dim newdate As Date With Worksheets("sheet1") rw2 = .cells(.Rows.Count, "c").End(xlUp).Row newdate = .Range("c" & rw2).value For rw1 = rw2 - 1 To 1 Step -1 If .Range("c" & rw1).value <> newdate Then Exit For Next rw1 .Range(.cells(rw1 + 1, 1), .cells(rw2, 1)).Copy Worksheets("sheet2").Range("v6").PasteSpecial xlValue If rw1 + 26 <= rw2 Then .Range(.cells(rw1 + 26, 1), .cells(rw2, 1)).Copy Worksheets("sheet2").Range("v40").PasteSpecial xlValue Application.CutCopyMode = False End If Application.CutCopyMode = False End With End Sub 各セルは、6000行くらいまで表示されています。  よろしくお願いします。

  • 参照元を削除したい

    参照元シートのA列で参照先のA列を検索し、参照先に参照元の内容があれば参照元を行削除しようとしています。 現在下記ソースの状態ですが、参照元を削除するとSETで保持しているアドレスと実際削除するアドレスが違ってしまうようで正しく動作しません。 参照元と参照先の関係を逆にすれば意図することが実現できますが、データ数の関係でそれは考えていません。(参照元が500未満、参照先が数万) どうすれば参照元が削除可能になるでしょうか。 Sub DeleteRow() Dim 参照元 As Range Dim 検索CD As Variant Dim 最終行 As Integer Dim S As Variant Set 参照元 = Sheets("参照元").Range("A2:A" & Sheets("参照元").Range("A2").End(xlDown).Row) 最終行 = Sheets("参照先").Range("A3").End(xlDown).Row For Each S In 参照元 Set 検索CD = Sheets("参照先").Range("A4:A" & 最終行).Find(S) If Not 検索CD Is Nothing Then S.EntireRow.Delete End If Next S End Sub

  • Match関数がうまく機能していない??

    すみません。また教えて下さい。 過去ログを見てシート1にあったデータをシート4にあるデータと照らし合わせてすでにあれば書き換え、なければ追加というようにできるようにしたく過去ログを参考にしてやったのですが、どうしてもエラーが出てしまいます。 Private Sub aa() Dim intlastrow1 As Integer Dim strb As String Dim longlastrow1 As Long intlastrow1 = Sheets(1).Range("A7").End(xlDown).Row longlastrow1 = Sheets(4).Range("A1").End(xlDown).Row Dim c As Object Dim rtn As Variant Dim d As Integer With Sheets(4) .Select For Each c In .Range("A1", "A" & longlastrow1) rtn = Application.Match(c.Value, Sheets(1).Range("A7:A" & intlastrow1), 0) d = c.Row strb = Cells(d, "A").Value If IsError(rtn) Then With Sheets(4).Cells(longlastrow1 + 1, "A") .Value = strb With .Font .Name = "MS Pゴシック" .Bold = False .Size = 8 End With End With Sheets(4).Cells(longlastrow1 + 1, "B").Value = Sheets(1).Range("A2").Value Sheets(4).Cells(longlastrow1 + 1, "F").Value = ShowFormula(Sheet1.Range(Cells(d, "J"), Cells(d, "N"))) longlastrow1 = longlastrow1 + 1 End If If Not IsError(rtn) Then Exit Sub End If Next c End With End Sub 以上のように組んだのですがうまくいきません。 具体的に言うとシート1のA7よりしたに名前が並んでいる(山田、鈴木・・・)とお考え下さい(シート4のA2以下にも同様に名前が並んでいる)。字数の関係で判定後の処理が不十分になっています。

  • 複数行を最終行に転記

    ブックから他ブックへの複数行を最終行に転記したいと考えております。 1日1行であれば転記出来るものの、1日が複数行となると1日の最終行のみが転記され困っております。 縦カレンダー仕様 ・月初ではなく日曜始まりの為前月含むこともあり ・1日につき各4行づつ ・4行すべて毎日データーが入るわけではなく時々入る程度 スケジュール表仕様 ・日曜始まりの一週間毎のシート ・1日につき9行分 1か月分だと長いので1週目分だけですが… Activ bookを縦カレンダー(入力用シート) Thisbookをスケジュール表(転記先シート) Sub 転記_Click() Dim WBK1 As Workbook,WBK2 As Workbook Dim SH1 As Worksheet,SH2 As Worksheet Dim myRow1 As Long,myRow2 As Long,myRow3 As Long,myRow4 As Long_ myRow5 As Long,myRow6 As Long,myRow7 As Long Set WBK1 = ThisWorkbook '縦カレンダー Set WBK2 = ActiveWorkbook 'スケジュール表 Set SH1 = WBK1.Worksheets("1週目") 'スケジュール表 Set SH2 = WBK2.Worksheets("3月") '縦カレンダー Set SH3 = WBK1.Worksheets("2週目") 'スケジュール表 Set SH4 = WBK1.Worksheets("3週目") 'スケジュール表 Set SH5 = WBK1.Worksheets("4週目") 'スケジュール表 Set SH6 = WBK1.Worksheets("5週目") 'スケジュール表 Set SH7 = WBK1.Worksheets("6週目") 'スケジュール表 With SH1 myRow1 = SH1.Range("C1").End(xlDown).Row '日 myRow2 = SH1.Range("C12").End(xlDown).Row '月 myRow3 = SH1.Range("C23").End(xlDown).Row '火 myRow4 = SH1.Range("C34").End(xlDown).Row '水 myRow5 = SH1.Range("C45").End(xlDown).Row '木 myRow6 = SH1.Range("C56").End(xlDown).Row '金 myRow7 = SH1.Range("C67").End(xlDown).Row '土 SH1.Range("C" & myRow1 + 1 & ":J" & myRow1 + 1).Value = SH2.Range("C3:J6").Value '日 SH1.Range("C" & myRow2 + 1 & ":J" & myRow2 + 1).Value = SH2.Range("C7:J10").Value '月 SH1.Range("C" & myRow3 + 1 & ":J" & myRow3 + 1).Value = SH2.Range("C11:J14").Value '火 SH1.Range("C" & myRow4 + 1 & ":J" & myRow4 + 1).Value = SH2.Range("C15:J18").Value '水 SH1.Range("C" & myRow5 + 1 & ":J" & myRow5 + 1).Value = SH2.Range("C19:J22").Value '木 SH1.Range("C" & myRow6 + 1 & ":J" & myRow6 + 1).Value = SH2.Range("C23:J26").Value '金 SH1.Range("C" & myRow7 + 1 & ":J" & myRow7 + 1).Value = SH2.Range("C27:J30").Value '土   End With End Sub

  • 処理速度を早くする

    処理速度を早くする よろしくお願いします。 下の構文で処理するのに5,6秒掛かります。 もっと早く処理をさせる方法をお教えください。 Private Sub 消去_Click() Application.ScreenUpdating = False Dim k As Integer Dim s As Integer With Worksheets("予定情報") k = 1 ActiveCell.Offset(0, k).Value = Temp For s = 0 To 30 ActiveCell.Offset(0, 0 + s).Delete Shift:=xlUp Range("A200:M204").Borders.LineStyle = True Next End With Application.ScreenUpdating = True End Sub

  • エクセルのマクロ Range("A1").End(xlDown).rowで列を削除

    A列の一番下のデータの次の行から F列の一番下のデータの行まで削除したいのですが Rows(" & Range("A1").End(xlDown).row+1 & ":" & Range("F1").End(xlDown).Row & ").Delete Shift:=xlUp でうまくいきません どうすればいいのですか?

  • 重複行を完全削除するエクセルのマクロ

    Sub sakujyo() Dim i, ii As Long For i = 1 To Range("a65336").End(xlUp).Row For ii = Range("a65336").End(xlUp).Row To i + 1 Step -1 If Cells(i, 4).Value = Cells(ii, 4).Value _ And Cells(i, 13).Value = Cells(ii, 13).Value Then Delete Shift:=xlUp End If Next ii Next i End Sub マクロに関しては、素人でございます。 こちらのマクロを作ってみたのですがうまくいきません。 4列目と13列目の列が重複したときのみ重複した行をすべて削除させたいと思っております。どうぞお教えください。

  • 二つのマクロで一気に処理したい

    以下のようなことができるのかお伺い致します。よろしくお願い致します。  やりたいこと   ※ 前提として、sheet1にすでにA列に通し番号で奇数の数字が入っている。    1.sheet1からsheet2へコピペーストする。しかし、A列からO列のすべてにデータがあった場合のみコピー貼り付けさせたい。     (前提で示したように、A列に通し番号で奇数の数字が入っていて、A列のみ数字があり、以外が空欄の行があるため)    2.下記のコピー貼り付けのコードと重複削除のコードを合体させて、一つの処理で動かしたい。 Sub コピー貼り付けつけ()  'コピー貼り付けつけのコード Dim lastRow As Long 'Sheet1のA3から最終行までをコピー With Sheets("sheet1") .Range("A3:O" & .Cells(Rows.Count, "A").End(xlUp).Row).Copy End With 'Sheet2のA列の最終行の次の行に貼付け Sheets("sheet2").Cells(Rows.Count, "A").End(xlUp).Offset(1).PasteSpecial Application.CutCopyMode = False End Sub Sub 重複データを一括削除する() ' Macro1 Macro Dim i As Long, lastRow As Long, myRng As Range LastRow = Cells(Rows.Count, "A").End(xlUp).Row For i = 1 To lastRow - 1 If WorksheetFunction.CountIf(Range(Cells(i + 1, "O"), Cells(lastRow, "O")), Cells(i, "O")) > 0 Then If myRng Is Nothing Then Set myRng = Cells(i, "O") Else Set myRng = Union(myRng, Cells(i, "O")) End If End If Next i If Not myRng Is Nothing Then myRng.EntireRow.Delete End If End Sub

  • コピペマクロを高速化したい(Excel)

    見よう見まねで以下のようなコードを書いてみたのですが、 これだと表示にやや時間がかかるので改善したいです。 ------ Sub コピペ() Dim i As Long i = Range("A1") Range("C12").Value = Worksheets("sheet2").Cells(i, 2).Value Range("D12").Value = Worksheets("sheet2").Cells(i, 3).Value Range("E12").Value = Worksheets("sheet2").Cells(i, 4).Value Range("F12").Value = Worksheets("sheet2").Cells(i, 5).Value Range("G12").Value = Worksheets("sheet2").Cells(i, 7).Value ------ こんな感じでコピペしたい値があと15個くらいあります。 コピー元とコピー先のセル配置には法則性があまりありません。 よろしくお願いします。

このQ&Aのポイント
  • BASIO4用液晶カバーのPM-BAS4FLFを使用している際、フィルムがクシュクシュと剥がれてしまい、スマホに貼ることができませんでした。この現象について、どういう原因が考えられるのかを教えていただきたいです。
  • BASIO4用液晶カバーのPM-BAS4FLFを使用していると、フィルムが剥がれてしまい、スマホに貼ることができません。この問題の解決方法を教えてください。
  • BASIO4用液晶カバーのPM-BAS4FLFを使用している際、フィルムが剥がれてしまう現象が発生しました。この問題についての対処法を教えてください。
回答を見る

専門家に質問してみよう