ExcelVBAで広範囲セルの空白チェックをする方法

このQ&Aのポイント
  • ExcelVBAを使用して、広範囲のセルに空白が存在するかどうかをチェックするための方法を探しています。現在のコードでは、データが存在しない場合に処理時間が長くなってしまいます。
  • データ範囲が65536行になるため、処理時間がかかります。データが存在しない場合の処理を改善する方法を教えてください。
  • ExcelVBAを使用して、広範囲のセルにデータが存在するかどうかをチェックし、存在しない場合には処理を早く終了する方法を知りたいです。
回答を見る
  • ベストアンサー

ExcelVBAで、広範囲セルの空白チェックをしたいと思います。

ExcelVBAで、広範囲セルの空白チェックをしたいと思います。 以下のようなExcelシートがあります。 ・10行目まではタイトル行 ・データ入力可能セル範囲はA11~AF65536 全てのデータ範囲を削除するために、以下のコードを作成しました。 動きとしては問題ないのですが、データが存在しない場合の 処理時間が長くなってしまいます。 Sub 全データ削除() Dim endrow As Long Dim mydelete As Integer Dim myrange As Range endrow = Range("A11").End(xlDown).Row For Each myrange In Range("A11:AF" & endrow) If myrange.Value <> "" Then GoTo 削除処理 End If Next myrange MsgBox "データがありません。" Exit Sub 削除処理: mydelete = MsgBox("全てのデータを削除しますか?", vbOKCancel) Select Case mydelete Case vbOK Rows("11:65536").Delete Range("D4").Formula = "=COUNTA(A11:A65536)" MsgBox "データを削除しました。" Exit Sub Case vbCancel MsgBox "キャンセルされました。" Exit Sub End Select End Sub データ範囲が65536行までになってしまうため時間がかかっているのだと思いますが、 回避方法がわかりません。 ご教授お願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.4

>二度目以降は、myRangeの行選択が前回までの最大行数を >引き継いでいるようです。 何か、情報が不足しているようです。 少し説明しながら書きます。考えてみてください。 修正:  Set myRange = Intersect(ActiveSheet.UsedRange, Range("A11:A" & EndRow).EntireRow)           ↓  Set myRange = Range("A11:A" & EndRow).EntireRow '当面はこれでやってみてください。 「UsedRange と Range("A11:A" & EndRow)の行全体までで重なる部分を削除しろ。」という命令ですが、実際、こちら側では、UsedRangeの範囲がはっきりみえていません。たぶん、その通常書き込むデータ範囲以外のところに文字や数字などのデータがあると思います。 一度、Ctrl + Shift + End(データが存在したという痕跡も含む) または、ActiveSheet.UsedRange.Selectで、最終データ位置を確認したほうがよいです。もし、不要なら、それらの文字や情報などは削除したほうがよいと思います。ファイルの肥大化の原因になります。そうでなければ、修正したほうをお使いください。 もう少し専門的な説明をさせていただきますが、   Rows("11:65536").Delete このコマンドを使わないのは、Excelというのは、最大行が、65536行(Excel2003まで)あるとすると、データのある範囲までは、ファイルが存在するということです。それ以降は理論行・理論列で実際には存在しません。実際は、最終行・最終列の四角の範囲がファイルのサイズになります。マクロの時は、必ず、最終行・最終列まで行きますが、存在していない所でも、論理的な処理をしてしまいます。 なお、この数式ですが、 > Range("D4").Formula = "=COUNTA(A11:A65536)" =COUNTA(INDIRECT("A11:A65536")) 'ただし、再計算関数になってしまいます。 [Range("D4").Formula = "=COUNTA(INDIRECT(""A11:A65536""))"]   または、 =COUNTA(A10:A65536)-1 これはたぶん、削除した時に、エラーになってしまうからですね。 本当は、INDIRECT 関数を用いるか、先頭行を一つ手前にして、-1 にすれば、書き加えずに済みます。

rose1224
質問者

お礼

ご親切にありがとうございます。 大変丁寧に解説いただいたので、理解できました。 Ctrl + Shift + Endで調べたら、データの痕跡があったようです。 > Range("D4").Formula = "=COUNTA(A11:A65536)" この数式についても、苦肉の策でしたが、 ちゃんと回避方法があったんですね。 =COUNTA(A10:A65536)-1 を利用させていただきます。 どうもありがとうございました。

その他の回答 (3)

  • Wendy02
  • ベストアンサー率57% (3570/6232)
回答No.3

だいぶ、VBAのコーディングは書きなれているようにお見受けしています。しかし、ご質問のコードは、独特の癖があるようです。たぶん、製作の手順に問題があるようです。メインにするのは、Delete の部分ですから、そこを中心にして必要な部分を付け足すようにしたほうがよいですね。 Goto の良し悪しについては、金科玉条で文句をつける人がいますが、それについては指摘しません。ただ、もし使うなら、なるべくサブルーチンにしたほうがよいかもしれません。Goto は、エラーが発生した時にしたほうがきれいです。 以下の私のコードは、決してほめられたコードとは言えません。詰め込みすぎて、息苦しい気もします。必ずしも、そうするべきものではもありません。 32 + vbOKCancel の32は、実際は組み込み定数でよいです。長くなるので省いただけです。 EndRow = Cells(Rows.Count, 1).End(xlUp).Row EndRow2 = Cells(11, 1).End(xlDown).Row 下側に向かって探す方法ですと、65536まで探します。 最後から上側に向かって探す方法だと、データの最後尾を探します。 どちらにも欠点があります。それを補うために、  If EndRow2 > EndRow Then EndRow = EndRow2 で、補完させました。フルにいれなければ、こんな問題は発生しませんが、  Rows("11:65536").Delete こういうコードから根拠にました。  Intersect(ActiveSheet.UsedRange, Range("A11:A" & EndRow).EntireRow) UsedRange と、重なる部分のみを削除するということにしました。 Range("A11:A" & EndRow).EntireRow.Delete だけでもよいはずですが、削除に必要な最小限の範囲にするためにIntersect を使いました。 変数は、キャメル(らくだ)型にすると、小文字で入力すると、変化しますから、入力ミスが分かります。 '// Sub 全データ削除r1()  Dim EndRow As Long '変数はキャメル型が良いです。  Dim EndRow2 As Long  Dim myDelete As Integer  Dim myRange As Range    EndRow = Cells(Rows.Count, 1).End(xlUp).Row  EndRow2 = Cells(11, 1).End(xlDown).Row  If EndRow2 > EndRow Then EndRow = EndRow2  Set myRange = Intersect(ActiveSheet.UsedRange, Range("A11:A" & EndRow).EntireRow)  If Not myRange Is Nothing Then   myRange.Select   If MsgBox("全てのデータを削除しますか?", 32 + vbOKCancel) = vbCancel Then    MsgBox "キャンセルされました", vbInformation    Exit Sub   Else    Application.ScreenUpdating = False    myRange.Delete    Application.ScreenUpdating = True    Range("D4").Formula = "=COUNTA(A11:A65536)"    MsgBox "データを削除しました。", 64   End If  Else   MsgBox "データがありません。"  End If End Sub

rose1224
質問者

補足

回答ありがとうございます。 すばらしいですね。 EndRowとEndRow2の2つを使う方法は、目からウロコでした! 瞬時に処理ができましたし、理想の動きでした。 かなり勉強になりました。 ただ、成功したのは一番最初だけでした。 二度目以降は、myRangeの行選択が前回までの最大行数を 引き継いでいるようです。 Excelを一度保存し、再起動しても、この部分は引き継いでいました。 コードの最後に、Set myRange = Nothing を付け加えてみましたが、 結果は同じでした。 あれこれ試行錯誤してみましたが、解決しません。。。 度々申し訳ありません。

  • o_chi_chi
  • ベストアンサー率45% (131/287)
回答No.2

検索を使えばよいのでは? ループで回せば1件づつの削除も可能です。 --- With Worksheets(1).Range("a11:AF65536") Set c = .Find("*", LookIn:=xlValues) If Not c Is Nothing Then call 削除処理 End If End With

rose1224
質問者

お礼

回答ありがとうございます。 ご教授いただいた方法でも、結果は同じでした。

  • mu2011
  • ベストアンサー率38% (1910/4994)
回答No.1

データ入力がない場合、空白チェックをA11:AF65536まで繰り返すからです。 何故、空白チェックが必要なのか不明、単純に削除処理だけのコードでよいと思いますが駄目なのでしょうか。

rose1224
質問者

お礼

回答ありがとうございます。 ユーザーにとっての使いやすさを考慮すると、 データの存在チェックは必要不可欠だと考えています。

関連するQ&A

  • エクセル マクロ:チェックボックス コピー

    教えてください。 sheet1にデータがあり sheet2にチェックボックスとコマンドボタンがあります。 チェックボックスにレ点を入れ、コマンドボタンを押すと sheet1の該当する列をコピーして、sheet3に貼り付ける マクロを作ろうと思ってますがうまくいきません。 下記のマクロを使えるように手直ししていただけないでしょうか。 よろしくお願い致します。 Private Sub CommandButton1_Click() Dim myrange As String Dim rmax As Long rmax = Sheets("sheet1").Range("A2").End(xlDown).Row With Sheets("sheet2") If .CheckBox1 Then myrange = myrange & ",$B$1:$B$" & rmax If .CheckBox2 Then myrange = myrange & ",$C$1:$C$" & rmax If .CheckBox3 Then myrange = myrange & ",$D$1:$D$" & rmax End With If myrange = "" Then MsgBox "チェックしてください" Exit Sub End If myrange = "$A$2:$A$" & rmax & myrange Sheets("sheet1").Range(myrange).Copy Sheets("sheet3").Range("A1").PasteSpecial xlPasteValues Application.CutCopyMode = False Sheets("sheet3").Select End Sub

  • エクセルVBAでセル範囲のデータをクリップボードに

    セル範囲のデータをテキストとしてクリップボードに取り込みたいのです。 http://okwave.jp/qa/q5650002.html#16327676 の回答ANo2を見て Sub test01() Dim myData As DataObject Dim myCb As Variant Dim x x = "TESTデータです。" Set myData = New DataObject myData.SetText x myCb = myData.GetText myData.PutInClipboard End Sub は出来ました。 そこで、セル範囲A1:B3をクリップボードに貼ろうといろいろやってみました。 一応、下記でできましたが、実際にはもっと広い範囲を取り込みたいので、もっと簡単な方法はないでしょうか? Sub Clip() Dim myStr As String Dim myData As DataObject Dim myCb As Variant Set myData = New DataObject With Sheets(1) myStr = .Range("A1").Value & ":" & .Range("B1").Value & _ vbNewLine & .Range("A2").Value & ":" & .Range("B2").Value & _ vbNewLine & .Range("A3").Value & ":" & .Range("B3").Value End With myData.SetText myStr ', 1 myCb = myData.GetText If MsgBox("データ" & vbNewLine & myCb & " をクリップボードに送りますか? ", vbYesNo + vbQuestion, "確認") = vbNo Then Exit Sub End If myData.PutInClipboard End Sub

  • ExcelVBAで行と列の検索

       A  B  C  D  E 1  コード あ  い  う  え 2  10  ○    ○ 3  20     ○  ○ 4  30          ○ 上記の表が5000件あります。Textbox1に入力し検索ボタンを押すと A列のコードを検索して一致する列の○のあるところの1行目の項目 をtextbox2に表示したいのですがうまく行きません。 よろしくお願い致します。 Private Sub CommandButton1_Click() '検索フォームボタン Dim i As Long Dim 最終行 As String Dim サーチ行 As Long Sheets(1).Activate 最終行 = Range("A1").End(xlDown).Row サーチ行 = 0 For i = 2 To 最終行 If TextBox1.Value = Range("A" & i) Then If Range("B" & i, "N" & i) = "" Then TextBox2.Text = Range("B1", "N1") サーチ行 = i Exit For End If End If Next If サーチ行 = 0 Then MsgBox TextBox1.Value & "データはありません。", vbInformation, "無し" End If TextBox1.SetFocus End Sub エラーはでません。データはありませんとなります。  

  • VBA:セルの空白を検索

    A列を上から検索して(とりあえず100行まで)最初の空白セルのアドレスを取得したいです。 Dim CellAd As Range Set CellAd = Range("A1:A100").CurrentRegion.Find(What:="ABC") If CellAd Is Nothing Then Exit Sub Else MsgBox CellAd.Address End If 以上のコードで、A列にABCがあればそのアドレスを$A$15のような形で表示できました。 検索したいのは空白なのですが、どのように指定すればよいでしょうか。 What:=""やNullではダメだったので(自分、「Null」を勘違いしてるかもしれません)。 また、ここでは取得したアドレスをmsgboxで表示させているだけですが、 実際は取得したアドレスの行番号のみを取得して変数Add1に入れ、 以降のコードのセル範囲指定として使いたいです。 「1行目からAdd1行目までをコピーする」のように。 私のレベルでは、 ・範囲指定はRange("A1:A100")のように、「""」でくくらなければ使えない ・変数は""の中に入れたら文字列として扱われる との認識があるのですが、 このようなコードは可能でしょうか。

  • Excel VBA データの入っているセルの取り出し

    Excel VBA データの入っているセルの取り出し Excel2007使用です。 大きなセル範囲の中にデータが点在している場合に、そのデータを一か所にまとめるマクロを作りたいです。セル範囲は決まっています(A1:Q100)。最終的には隣のセルの1列にまとめたいです。 以下のようなマクロを作ってみましたが、いずれも作動しませんでした(エラーメッセージも出ず) NullをEmptyに変えてみても同じでした。 (ややこしいですが、アクティブセルはSheet2、Sheet1へ貼り付けたい) (とりあえずシート内で列上部にまとめようとした) Dim myRange As Range For Each myRange In Range("A1:Q100") If myRange.Value = Null Then myRange.Delete xlShiftUp End If Next myRange End Sub (1行1列ずつの参照をループさせて「空白でない」セルを切り取り-貼り付けさせようとした) Worksheets("sheet2").Activate Dim Gyou As Integer Dim Retsu As Integer For Gyou = 1 To 100 For Retsu = 1 To 17 If Cells(Gyou, Retsu).Value = Not Null Then Cells(Gyou, Retsu).Cut Destination:=Worksheets("sheet1").Cells(5, 2) End If Next Retsu Next Gyou End Sub また、以下のマクロは、実行すると現状のままSheet1のE列以降に移るだけで、データのあるセルだけがまとまるという状態にはなりません。 Range("A1:Q100").SpecialCells(xlCellTypeVisible).Cut Destination:=Worksheets("Sheet3").Range("E1") End Sub 以下は某サイトで、まさに「空白セルを削除しデータの入ってるセルを上詰めにする」というマクロが紹介されていたので、加工してやってみましたが、「RangeクラスのDeleteメソッドが失敗しました」という実行時エラーが出てできませんでした。 Dim WS As Worksheet Dim myRng As Range Dim Lrow As Long Set WS = Worksheets("Sheet1") Lrow = WS.Range("A" & CStr(Rows.Count)).End(xlUp).Row Set myRng = WS.Range("A1:A" & CStr(Lrow)) myRng.SpecialCells(xlCellTypeBlanks).Delete xlShiftUp End Sub データの入っているセルだけを取り出して一つの列にまとめたいのですが、どうしたらいいのでしょうか。

  • ExcelVBAの知恵をお貸しください。

    一つのシートで、複数のセル範囲を選択している場合に、セル範囲を選択しているのか?列、行を選択しているのかを判別する方法として次のようなのを考えました。 それとなく動いているのですが、なんとなくスマートでなく、場当たり的な感じがしますが、どのようにすればいいのか判りません!! どなたか、アドバイス頂けないでしょうか?宜しくお願いいたします。 Sub test()  Dim myRang As Range  Dim myArry As Variant  For Each myRang In Selection.Areas myArry = Split(Replace(myRang.Address, ":", ""), "$") If UBound(myArry) <> 2 Then   MsgBox "セル範囲を選択しています。" & myRang.Address Else If IsNumeric(myArry(1)) Then MsgBox "行を選択しています。" & myRang.Address Else MsgBox "列を選択しています。" & myRang.Address End If End If  Next End Sub

  • :【Excel VBA】 Do Until ~ Loop 構文で途中の空白セルを飛ばしてデータのチェックをしたい

    こんにちは。 Do Until ~ Loop 構文で 空白セルまでループして重複する値をチェックしたいと考えています。 --------------------------------------------- Sub 重複チェック() Dim 検索語 As String Dim 該当数 As Long Dim 確認 As Integer Range("A4").Activate Do Until ActiveCell.Value = "" 検索語 = ActiveCell.Value 該当数 = WorksheetFunction.CountIf(Range("A:A"), 検索語) If 該当数 >= 2 Then ActiveCell.AutoFilter Field:=1, Criteria1:=検索語 確認 = MsgBox("次を検索しますか?", vbYesNo) If 確認 = vbNo Then Exit Sub End If ActiveCell.Offset(1, 0).Activate Loop Range("A4").AutoFilter MsgBox "名前の重複チェックが終了しました。" End Sub --------------------------------------------- ただセルA列には行の途中、空白も含まれているため、 途中で止まってしまいます。 今後A列にはデータが追加されていきます。 途中の空白セルを飛ばして、 データーの最後までチェックするにはどのようにすればよいでしょうか?

  • ExcelVBAで範囲指定

    セル範囲、D3:E15とG3:G15とI3:I15をクリアする場合 Sub Macro2() Range("D3:E15,G3:G15,I3:I15").ClearContents End Sub と書くと思います。 この15行目を変数にする場合 Sub Macro3() Dim x As Long x = 15 Range("D3:E" & x & ",G3:G" & x & ",I3:I" & x).ClearContents End Sub と書く以外にもっと簡単な範囲指定の方法はないでしょうか?

  • 空白行の削除マクロについてご教示ください

    空白行の削除に、下記マクロを活用させていただいていますが、 見た目空白なのに削除されない行が時々残ってしまいます。 削除されなかったセルを「Deleteキー」で空白にするとマクロが 実行され、きちんと削除されます。 こういった、スペースか何かが入っていても、見た目空白なら 削除するようにはできないでしょうか。 どなたかよろしくお願いいたします。 Sub 削除() Dim c As Range Dim 開始行 As Long Dim 最終行 As Long 開始行 = 5 最終行 = Range("a5000").End(xlUp).Row For Each c In Range("a" & 開始行 & ":a" & 最終行) If c.Value = "" Then Rows(c.Row).Delete End If Next End Sub

  • 【Excel VBA】チェックボックスの挿入位置

    Excel2003を使用しています。 Sheet2のN1セルに入力されている番号と同じ番号が入力されているセルをSheet1のA列(A11:A200)から探して、その行のB列にチェックボックスを挿入したく、下記のようにコードを書いてみましたが、チェックボックスの挿入と挿入位置等(?部分)をどのように書いたらいいのかわかりません。 ---------------------------------------- Sub test1() Dim myStr As String Dim myRange As Range myStr = Sheets("Sheet2").Range("N1").Value Set myRange = Sheets("Sheet1").Range("A11:A200").Find(myStr) If myRange Is Nothing Then Exit Sub Else  '?←この部分がわかりません…。 End If End Sub ---------------------------------------- 実際にチェックボックスを挿入してマクロの記録もとってみたのですが、あまり参考にすることができず、質問させていただいた次第です。 チェックボックスは、コントロールツールボックスのチェックボックスを使用したいのですが…。 よろしくお願いします。

専門家に質問してみよう