• ベストアンサー

Excelのバージョンに依存しない最終セルの取得方法

VBAでたとえばA列の最後にデータが入っているセルを取得するのに、今まで Range("A65536").End(xlUp) という書き方をしてきました。 しかし、Office2007ではExcelの最大列数が従来の256列から16384列に,最大行数が従来の65536行から1048576行に増えました。 そうすると、Excelを2007にバージョンアップしたら、上記の書き方をした既存のマクロを使っているブックのデータが増えていって65536行を超えたとき、マクロが正常に稼動しなくなります。 Range("A1048576").End(xlUp) とすればExcel2007では動くのかもしれませんが、Excel2003以前のバージョンでは、A1048576などというセルはないのでエラーになります。 できるだけExcelのバージョンに依存しない書き方をしたいのですが、上記のようなA列の最後にデータが入っているセルを求めるには、どういう書き方をすればいいのでしょうか。 自分なりに考えたのは、行数だけ求めるなら、 Range("A1").CurrentRegion.SpecialCells(xlCellTypeLastCell).Row で、この値をInteger型の変数でFor~Nextでループさせる、という方法です。 しかし、ネットで検索していろいろ調べたところ、上記の書き方では不具合が生じることがわかりました。たとえばA1からA10まで値が入っていた場合、 Range("A1").CurrentRegion.SpecialCells(xlCellTypeLastCell).Row では10が求まりますが、A10のセルを選択してDelキー(またはBackSpace)で値を削除しても、上の式の結果は10のままなのです。(Selectすると、空白のセルが選択されます) Excelのバージョンに依存しない、データが入っている最終行の求め方でいい方法はないでしょうか?

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

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

こんにちは。 私自身は、あまり、Excel 2007 VBA自体に触ることもないような気がしているので、特に、あまり気にしていないのですが、こんな風にすればよいですね。 以前は、こう書きましたが、明示的ではないので、廃れたのだと思います。また、復活ですね。  Cells(Rows.Count, 1).End(xlUp).Select >Range("A1").CurrentRegion.SpecialCells(xlCellTypeLastCell).Row それ自体に、無理がありますね。CurrentRegion と、SpecialCells(xlCellTypeLastCell) との結びつきが薄いからです。親戚ではあっても、根っこの違うものを、繋げて使うのは良くありません。SpecialCells(xlCellTypeLastCell) これ自体が、勝手に範囲を取ろうとするからです。 SpecialCells は、ワークシート系(オブジェクト・ブラウザの[Excel]という項目に入ります)で、一般的にVBAでは用いられますが、SpecialCells メソッドは、UsedRangeでも、CurrentRegion でもない、独自の範囲の取り方をします。おそらく、ワークシートのショートカットなどとつながっているものだと思います。もちろん、ないはずのA10 の位置は、一旦保存すれば直りますが。 CurrentRegion で、取るというのでしたら、以下のようになりますね。良かったら試してみてください。 With ActiveSheet.Range("A1").CurrentRegion  i= .Cells(.Count).Row End With なお、Version で行数などを替える方法には、#if Directive 構文という方法がありますが、そこまでの致命的な問題はなさそうです。

ham_kamo
質問者

お礼

昔はRow.Countを使っていたのですね。SpecialCellsに関しても詳しい解説をありがとうございます。Wendy02さんのご回答はいつも勉強になります。どうもありがとうございました。

その他の回答 (7)

  • driverII
  • ベストアンサー率27% (248/913)
回答No.8

こんなのがありました。 ActiveSheet だとして、 Cells(ActiveSheet.UsedRange.SpecialCells(xlCellTypeLastCell).Row(), 1).Select

参考URL:
http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/feb06/hey0215.mspx
ham_kamo
質問者

お礼

Rows.Countを使うことで解決しました。 ご回答ありがとうございました。

  • gatt_mk
  • ベストアンサー率29% (356/1220)
回答No.6

Dim myLastCell As Range Dim r As Integer   Set myLastCell = Range("A1").SpecialCells(xlCellTypeLastCell)   If myLastCell.Value = "" Then     r = Cells.Find("*",myLastCell, , ,xlByRows,xlPrevious).Row   Else     r = myLastCell.Row   End If   Msgbox "最終行は" & r & "行です" 上記VBAスクリプトを実行したらどうなりますか? よくあるパターンです。ExcelVBAの参考書を1冊買われたらいかがですか?

ham_kamo
質問者

お礼

VBAの参考書は持っていて、それで勉強してはいるのですが、この回答のパターンは載っていませんでした。 (「最終行の求め方」で、質問文に書いたRange("A65536").End(xlUp)が載っていたのですが…) Rows.Countを使うことで解決しそうです。ご回答ありがとうございました。

  • driverII
  • ベストアンサー率27% (248/913)
回答No.5

1. Application.Versionでバージョンを調べ、グローバル変数に 対応した最終行を入れておく。 2. Range("A65536").End(xlUp)と同様にCells(最終行,1).End(xlUp) じゃ駄目ですか?

ham_kamo
質問者

お礼

Rows.Countを使うことで解決しました。 Application.Versionでわけるという方法も、他に異なる仕様が出てきた場合に使えそうですね。勉強になりました。 ご回答ありがとうございました。

noname#181803
noname#181803
回答No.4

ちょっと、回答とは違うんだけど・・・。 基本的に、ソフトウェア開発というものは下位バージョンとの互換性は考慮するけど、上位バージョンとの互換性は考慮できない。 そのため、どんなアプリでも対応OSを記載してる。 基本的な考え方としては、バージョンを取得して処理を分岐させるのがもっとも一般的なものだと思う。 今回の場合なんかは、Application.Version関数を利用してバージョンごとに異なる数値を割り当てるのがメンテナンスしやすいんじゃないかな~? Selectステートメントにしておけば、Caseを追加してくだけで今後行の最終値については取得できるようになると思うし。 あと、将来的に、対応できるようなプログラムというものは作ることができない。 それは、現在のプログラムというものはOSの上でのみ動くものだからね。 OSが進化している以上、プログラムの対応は必然的に発生するし・・・。 ・・・とこんなこといってもしょうがないので、ちょっと考えてみました。(相当強引) 1行目から+1行していく無限ループ作って、エラーをわざと発生させる。 Excel2007は1048577でエラーが発生するし、Excel2007以外では65537でエラーが発生する・・・はず。 そのエラーをOn Errorステートメントでキャッチして、その値から-1すれば求められるんじゃないかな? そのあと、Range(変数).End(xlUp)で求められると思うけど・・。 テストしたわけじゃなく、しかも、あくまで私の頭の中なんで参考程度にね・・・。 ただ、ロジック的に綺麗じゃないし、処理は遅くなるだろうし、相当邪道っぽいけどね。(^.^;;)

ham_kamo
質問者

お礼

私もソフトウェア開発に携わっていたので、仰ることはよくわかります。確かに上位バージョンとの互換性というのは、将来のバージョンで仕様がどう変わるかわからないので、考慮しようがないですね。 しかし今回の質問に関しては、Excel2007というのがまだ誰も仕様がわからない、という未知のものでなく既に発売されており仕様もわかっており、 「Excel2007で動作するが、まだ2003や2000を使っている人が多いことを考慮にいれて、それらでも支障なく動くようなVBAの書き方は?」 ということなので、どちらかと言うと下位互換性の話になるのかな~という感じです。 Application.Versionでわけるという方法は、他に今までのバージョンと違う仕様が出てきた場合(関数の仕様などが微妙に変わったりだとか。あるかな~、MSならこっそりやりそう…)に使えそうですね。参考になりました。 ご回答どうもありがとうございました。

  • hana-hana3
  • ベストアンサー率31% (4940/15541)
回答No.3

ベストな方法は解りませんが、単純な置き換えなら・・・ MsgBox Range("A" & Range("A:A").Count).End(xlUp).Row

ham_kamo
質問者

お礼

この方法でもできますね。いろいろ勉強になります。 ご回答ありがとうございました。

  • uro_tan
  • ベストアンサー率15% (6/40)
回答No.2

ActiveSheet.Rows.Count ではどうでしょうか。

ham_kamo
質問者

お礼

これが一番シンプルかつ確実そうですね。 もっとよく考えたら自分でも気づいたかもしれませんが、まだまだ勉強が足りないみたいです。ご回答ありがとうございました。

  • nobu555
  • ベストアンサー率45% (158/345)
回答No.1

入力済みセルと空白セルの合計で総数を求めては?

ham_kamo
質問者

お礼

Rows.Countを使うことで解決しました。 ご回答ありがとうございました。

関連するQ&A

  • エクセルで結合セルがあるため最終行が解りません。

    エクセルで結合セルがあるため最終行が解りません。 A列2行目と3行目が結合セル(見出し)のためA列の最終行(罫線を除きデータが入ってる行)を求めれなくて困ってます。データは4行目以降から入力していく予定ですが Range("A" & Rows.Count).End(xlUp).Row は2となるため+1で入力行を求めてると3となってしまいます。A4からAの最後の行の範囲で罫線を除く最終行を出せればよいのですが  最初は4 以下順次5 6 7 ‥ どなたかご教示頂けないでしょうか?

  • エクセルVBAでデータ最終行取得方法

    エクセルVBAでデータ最終行取得方法で良い方法を教えてください。 データの行数、列数は不定。 最多のデータ行の列も不定。 この条件で、データ最終行を取得するにはどうすればよいでしょうか? lastrow = ActiveSheet.Cells(ActiveSheet.Rows.Count, "A").End(xlUp).Row では、A列の最終行に限定されます。 lastrow = ActiveSheet.Cells(1, "A").SpecialCells(xlLastCell).Row では、列の限定はありませんが、一旦データ入力後、削除した部分まで入ってしまいます。 lastrow = ActiveSheet.UsedRange.Rows.Count では、データ入力後、削除した部分まで入ってしまい、かつ、1行目など上部が空白の場合、不正確になります。

  • エクセルのマクロ 最終行取得後の作業

    エクセルのマクロで(エクセル2010を使用) Range("A1:A900").Select Range("A" & Rows.Count).End(xlUp).Select i = Selection.Row 上記の900がセルの最終行で最終行数を取得し、iを利用して  Range("A1:A & i ").Select といった感じで使用したいのですが記述がわかりません。 申し訳ございませんが()内の書き方を教えてください。

  • Excelのセル選択範囲の指定について

    Excelのセル選択範囲の指定について d = Range("A65536").End(xlUp).Row Range("A1:K" & d).Select これでやると A1からk列のデータの最後の(データの入っている行)までを選択しますが このk列というところを n = ActiveSheet.Range("A1").End(xlToRight).Columnを使いKでなくデータのある列nを使った表現に変えたい。どうすればいいか。

  • EXCELマクロのデータの最終行の取得

    EXCELマクロでRange("A1").End(xldown).Rowで、正しい値が取得できません。 A1からA6697まで、連続して入力しているので、途中に空白セルはありません。 それよりうしろにも、データはありません。 しかし、帰ってくる値はなぜかそれより遥か下の空白セルの「78889」です。 下からxlUpで検索しても同じ値が返ってきます。 A78889には、何も入力してありません。 rangeで範囲指定ではなく、usedrangeやcolumnsでみると正しく認識します。 どなたか分かる方いらっしゃいましたら、よろしくお願いします。 ※A1からA6697まではマクロで自動作成して埋めているセルなので、問題のセルを含めそれ以外の場所はなにも触っていません。

  • Excel 任意の列の特定の行のみ値の取得

    書籍とサイトで教えていただいた説明などを見ながら、ExcelのVBAでセル内のデータの操作について勉強中ですが、タイトルのようなことをやる場合のオブジェクト式の選び方がわかりません。 よろしくお願いします。 例えば図のようなデータが入った"Sheet1"があり、行数、列数は様々なのですが、やりたいことは ・A列にエラーコード(ここでは"9999"または特定文字列)、空行、0が入っている行(ピンク色がついたセルのある行)は無視する。 ・任意の列がコピー元(ここでは「A列=コード」「B列=商品名」「E列=価格」で、上記に該当しないセルが対象 ・そのセルの値のみ取得し、"Sheet2"のA~C列に上から順に(上詰めで)「値」のみをはりつけたい Dim i As Long Worksheets("Sheet1").Select Rows(1).Copy Worksheets("Sheet2").Range("A1") For i = 2 To Range("A65536").End(xlUp).Row If Cells(i, "A") = 9999 And IsNumeric(Range("A" & i)) Then この記述ではこのデータ操作ではエラーを変えすのですが、 根本的な「任意の列の特定の行のみの値の取得(と他シートへの複写)」の概念がわかっていません。 正しく動作する記述において、なぜそのオブジェクト式を採用するのかも含めて教えていただければと思います。 よろしくお願いします。

  • VBScript エクセル 最終行と最終列取得

    今、たくさんのシートがある、エクセルのファイルがあり、「C6」以降が縦の項目行、「D5」以降が横の項目列です。 項目行と項目列には、間に空白のセルは存在しません。 この状態で、項目行、項目列の最終の場所を取得しなければなりません。 そこで、「r = Range("C6").End(-4121).Row」(「-4121」は「xlDown」)、「c = Range("D5").End(-4161).Column」(「-4161」は「xlToRight」)で次々に求めていったのですが、「C6」に縦の項目が1つだけ、「D5」に横の項目が1つだけ、というシートがありました。 すると、そのシートでは、「r」と「c」の値は、エクセルそのものの最大の行数と最大の列数が返ってきてしまいました。 そこで、「D6」にのみ、文字があるサンプルファイルを作り、そのサンプルファイルに対して、「r = Range("D5").End(-4121).Row」と「c = Range("C6").End(-4161).Column)」で求めると、ちゃんと、「r = 6」、「c = 4」という値が返ってきたので、「r」の場合は、1つ上から、「c」については、1つ左から「Range」を設定すればいい、と思って、実際のデータで試すと、他のシートでは、全然うまくゆきません。 結果的に、問題は、「If」文で、ムリヤリ解決させたのですが、「If」文の場合ですと、前もって全シートを確認して、調べておかなければなりません。 何とか、汎用的に項目が1つしかない場合も、その項目のある「行」と「列」が最終行、最終列として取得できる方法はないでしょうか? ただし、項目が「0個」ということはありませんので、そこまで考えて頂く必要はありません。 「VBA」でも結構ですので、よろしくお願いいたします。

  • エクセルで式のセルを値で貼り付ける際(マクロを組んで)

    毎回お世話になっております。 よろしくお願いします。 1行目にタイトルがありまして A2セルから下にデータが入っています (A2から隙間無く詰まっています  毎回変わりますが おおよそ数百くらい) そのA行のデータを参照している数式が M行 N行セルに 入っています。 たとえば M2=A2*3 N2=A2+9 というふうに M2 N2の式をA行のデータがある最終部分まで Cells(2, 13).Copy Range(Cells(3, 13), Cells(Cells(65536, 1).End(xlUp).Row, 13)) Cells(2, 14).Copy Range(Cells(3, 14), Cells(Cells(65536, 1).End(xlUp).Row, 14)) この式でコピーしています。 そしてMN行全体を選択して「値」で貼り付けているのですが 動作が重くなってきます。 そこでMN行のデータがある部分を選択できる マクロでの方法はありませんでしょうか? もしくは 「考える方向がおかしい」などの 御指摘ありましたら よろしくお願い致します。

  • エクセル オートフィルタ中の最終行移動マクロ

    表題について質問させていただきます。 行数の決まっていないA~E列までデータが入っている表があります。 仮に10行だったとして、マクロの操作でA11に移動させるには、以下で可能だったのですが、 ・Range("A65536").End(xlUp).Offset(1).Select ・Range("A1").End(xlDown).Offset(1,0).Select オートフィルタ実行中は不可視セルが選択されてしまい上記例のA11に移動できません。 オートフィルタ実行中にもA11へ移動する方法をご教授願います。 ※行数が15行のときはA16へ移動。  新規に入力する行へ移動することが望みです。 エクセル2003です よろしくお願いいたします。

  • 最終行/処理対象のデータまでを表すVBA

    こんばんは、データの最終行/処理する対象のセルまで処理する場合のVBAの記述について質問させてください!VBAの最終行/処理する対象のセルまで選択するために使用する記述方法が何種類かありますが、そのうち、書籍やネットで検索しても出てこない記述方法について今一つ理解ができていません(T_T) 本屋で売っている書籍やネットで検索すると出てくる記述方法 Range~.End(xlUp).Row Range~.CurrentRegion Range~.SpecialCells(xlLastCell) Range~.Cells(Rows.Count, 1).End(xlUp).Row 上記のようなVBAは書籍やネットで検索すると説明や違いについても出てくるので、説明を読めば理解ができるのですが、 Sheets("テスト").Range("A1:C" & Sheets("テスト").Cells _(1).CurrentRegion.Rows.Count) Range("A1").CurrentRegion.Cells(Range _("A1").CurrentRegion.Cells.Count).Row 上記のようなVBAについては検索しても説明など出てこないうえに、 なぜ上記のような記述になるのかあまり理解できていません(>_<) 書籍やネットで検索すると出てくる「Range~.CurrentRegion」などの記述方法から何となく、CurrentRegionやCells.Countを使わないといけないというのは理解できますが、なぜ「~CurrentRegion.Rows.Count)」はRowsがカッコの中に入っていて、「~CurrentRegion.Cells.Count).Row」はカッコの外に出ているのか??といった細かいことが分からずにいます。。。 半ば丸暗記のようにして使ってしまっているのですが、もし上記のようなVBAについてわかるかたがいらっしゃれば、ご教授いただけるととても嬉しいです! また、上記以外にもまだ検索しても出てこないようなVBAがあるのでしょうか?? 頭が混乱しそうです!(゜Д゜;)

専門家に質問してみよう