Kesalahan dalam menemukan sel yang terakhir digunakan di Excel dengan VBA

179

Ketika saya ingin menemukan nilai sel yang terakhir digunakan, saya menggunakan:

Dim LastRow As Long

LastRow = Range("E4:E48").End(xlDown).Row

Debug.Print LastRow

Saya mendapatkan output yang salah ketika saya memasukkan satu elemen ke dalam sel. Tetapi ketika saya memasukkan lebih dari satu nilai ke dalam sel, hasilnya benar. Apa alasan di balik ini?

james
sumber

Jawaban:

309

CATATAN : Saya bermaksud menjadikan ini "pos satu atap" tempat Anda dapat menggunakan Correctcara untuk menemukan baris terakhir. Ini juga akan mencakup praktik terbaik yang harus diikuti ketika menemukan baris terakhir. Dan karenanya saya akan terus memperbaruinya setiap kali saya menemukan skenario / informasi baru.


Cara yang tidak dapat diandalkan untuk menemukan baris terakhir

Beberapa cara paling umum untuk menemukan baris terakhir yang sangat tidak dapat diandalkan dan karenanya tidak boleh digunakan.

  1. DigunakanRange
  2. xlDown
  3. CountA

UsedRangeharus TIDAK PERNAH digunakan untuk menemukan sel terakhir yang memiliki data. Ini sangat tidak bisa diandalkan. Coba percobaan ini.

Ketikkan sesuatu di sel A5. Sekarang ketika Anda menghitung baris terakhir dengan salah satu metode yang diberikan di bawah ini, itu akan memberi Anda 5. Sekarang warna sel A10merah. Jika sekarang Anda menggunakan salah satu kode di bawah ini, Anda masih akan mendapatkan 5. Jika Anda menggunakan Usedrange.Rows.Countapa yang Anda dapatkan? Tidak akan 5.

Berikut ini adalah skenario untuk menunjukkan cara UsedRangekerjanya.

masukkan deskripsi gambar di sini

xlDown sama-sama tidak bisa diandalkan.

Pertimbangkan kode ini

lastrow = Range("A1").End(xlDown).Row

Apa yang akan terjadi jika hanya ada satu sel ( A1) yang memiliki data? Anda akan mencapai baris terakhir di lembar kerja! Ini seperti memilih sel A1dan kemudian menekan Endtombol dan kemudian menekan Down Arrowtombol. Ini juga akan memberi Anda hasil yang tidak dapat diandalkan jika ada sel kosong dalam rentang.

CountA juga tidak dapat diandalkan karena akan memberi Anda hasil yang salah jika ada sel kosong di antaranya.

Dan karenanya seseorang harus menghindari penggunaan UsedRange, xlDowndan CountAuntuk menemukan sel terakhir.


Temukan Baris Terakhir dalam Kolom

Untuk menemukan Baris terakhir di Kolom E gunakan ini

With Sheets("Sheet1")
    LastRow = .Range("E" & .Rows.Count).End(xlUp).Row
End With

Jika Anda perhatikan bahwa kami memiliki .sebelumnya Rows.Count. Kami sering memilih untuk mengabaikannya. Lihat pertanyaan INI tentang kemungkinan kesalahan yang mungkin Anda dapatkan. Saya selalu menyarankan menggunakan .sebelum Rows.Countdan Columns.Count. Pertanyaan itu adalah skenario klasik di mana kode akan gagal karena Rows.Countpengembalian 65536untuk Excel 2003 dan sebelumnya dan 1048576untuk Excel 2007 dan yang lebih baru. Demikian pula Columns.Countpengembalian 256dan 16384, masing-masing.

Fakta di atas bahwa Excel 2007+ memiliki 1048576baris juga menekankan pada fakta bahwa kita harus selalu mendeklarasikan variabel yang akan menyimpan nilai baris karena Longalih-alih IntegerAnda akan mendapatkan Overflowkesalahan.

Perhatikan bahwa pendekatan ini akan melewati setiap baris tersembunyi. Melihat kembali tangkapan layar saya di atas untuk kolom A , jika baris 8 disembunyikan, pendekatan ini akan kembali 5sebagai gantinya 8.


Temukan Baris Terakhir dalam Lembaran

Untuk menemukan Effectivebaris terakhir di lembar, gunakan ini. Perhatikan penggunaan Application.WorksheetFunction.CountA(.Cells). Ini diperlukan karena jika tidak ada sel dengan data di lembar kerja maka .Findakan memberi AndaRun Time Error 91: Object Variable or With block variable not set

With Sheets("Sheet1")
    If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
        lastrow = .Cells.Find(What:="*", _
                      After:=.Range("A1"), _
                      Lookat:=xlPart, _
                      LookIn:=xlFormulas, _
                      SearchOrder:=xlByRows, _
                      SearchDirection:=xlPrevious, _
                      MatchCase:=False).Row
    Else
        lastrow = 1
    End If
End With

Temukan Baris Terakhir dalam Tabel (ListObject)

Prinsip yang sama berlaku, misalnya untuk mendapatkan baris terakhir di kolom ketiga tabel:

Sub FindLastRowInExcelTableColAandB()
Dim lastRow As Long
Dim ws As Worksheet, tbl as ListObject
Set ws = Sheets("Sheet1")  'Modify as needed
'Assuming the name of the table is "Table1", modify as needed
Set tbl = ws.ListObjects("Table1")

With tbl.ListColumns(3).Range
    lastrow = .Find(What:="*", _
                After:=.Cells(1), _
                Lookat:=xlPart, _
                LookIn:=xlFormulas, _
                SearchOrder:=xlByRows, _
                SearchDirection:=xlPrevious, _
                MatchCase:=False).Row
End With

End Sub
Siddharth Rout
sumber
9
@ phan: Ketik sesuatu di sel A5. Sekarang ketika Anda menghitung baris terakhir dengan salah satu metode yang diberikan di atas, itu akan memberi Anda 5. Sekarang warna sel A10 merah. Jika sekarang Anda menggunakan salah satu kode di atas, Anda masih akan mendapatkan 5. Jika Anda menggunakan Usedrange.Rows.Countapa yang Anda dapatkan? Tidak akan menjadi 5. Usedrange sangat tidak dapat diandalkan untuk menemukan baris terakhir.
Siddharth Rout
6
Perhatikan bahwa .Find sayangnya mengacaukan pengaturan pengguna di dialog Temukan - yaitu Excel hanya memiliki 1 set pengaturan untuk dialog, dan Anda menggunakan .Find menggantinya. Trik lain adalah masih menggunakan UsedRange, tetapi gunakan sebagai maksimum (tapi tidak bisa diandalkan) maksimum dari mana Anda menentukan maksimum yang benar.
Carl Colijn
4
@CarlColijn: Saya tidak akan menyebutnya mengacaukan. :) Excel hanyalah rememberspengaturan terakhir. Bahkan ketika Anda secara manual melakukan Find, itu mengingat pengaturan terakhir yang sebenarnya adalah anugerah jika ada yang tahu "fakta" ini
Siddharth Rout
3
@KeithPark: Silakan :) :) Pengetahuan hanya memiliki arti jika menyebar :)
Siddharth Rout
9
Saya pikir deskripsi Anda tentang UsedRange( sangat tidak dapat diandalkan untuk menemukan sel terakhir yang memiliki data ) menyesatkan. UsedRangesama sekali tidak dimaksudkan untuk tujuan itu, meskipun dalam beberapa kasus mungkin memberikan hasil yang benar. Saya pikir eksperimen yang diajukan menambah kebingungan. Hasil yang diperoleh dengan UsedRange($ A $ 1: $ A $ 8) tidak bergantung pada memasukkan data terlebih dahulu dan menghapusnya. Angka di sebelah kanan akan tetap sama bahkan tanpa memasukkan data dan menghapusnya. Tolong lihat jawaban saya.
sancho.s ReinstateMonicaCellio
34

Catatan: jawaban ini dimotivasi oleh komentar ini . Tujuannya UsedRangeberbeda dari apa yang disebutkan dalam jawaban di atas.

Adapun cara yang benar untuk menemukan sel yang terakhir digunakan, pertama-tama kita harus memutuskan apa yang dianggap digunakan , dan kemudian memilih metode yang sesuai . Saya mengandung setidaknya tiga makna:

  1. Digunakan = tidak kosong, yaitu memiliki data .

  2. Used = "... in use, artinya bagian yang berisi data atau pemformatan ." Sesuai dokumentasi resmi , ini adalah kriteria yang digunakan oleh Excel pada saat menyimpan. Lihat juga dokumentasi resmi ini . Jika seseorang tidak mengetahui hal ini, kriteria dapat menghasilkan hasil yang tidak terduga, tetapi kriteria tersebut juga dapat secara sengaja dieksploitasi (lebih jarang, pasti), misalnya, untuk menyorot atau mencetak wilayah tertentu, yang pada akhirnya mungkin tidak memiliki data. Dan, tentu saja, diinginkan sebagai kriteria untuk rentang untuk digunakan saat menyimpan buku kerja, jangan sampai kehilangan bagian dari pekerjaan seseorang.

  3. Used = "... in use, artinya bagian yang berisi data atau pemformatan " atau pemformatan bersyarat. Sama seperti 2., tetapi juga termasuk sel yang menjadi target untuk aturan Pemformatan Bersyarat apa pun.

Cara menemukan sel yang terakhir digunakan tergantung pada apa yang Anda inginkan (kriteria Anda) .

Untuk kriteria 1, saya sarankan membaca jawaban ini . Catatan yang UsedRangedisebut tidak dapat diandalkan. Saya pikir itu menyesatkan (yaitu, "tidak adil" untuk UsedRange), karena UsedRangetidak dimaksudkan untuk melaporkan sel terakhir yang berisi data. Jadi itu tidak boleh digunakan dalam kasus ini, seperti yang ditunjukkan dalam jawaban itu. Lihat juga komentar ini .

Untuk kriteria 2, UsedRangeadalah opsi yang paling dapat diandalkan , dibandingkan dengan opsi lain yang juga dirancang untuk penggunaan ini. Bahkan membuatnya tidak perlu untuk menyimpan buku kerja untuk memastikan bahwa sel terakhir diperbarui. Ctrl+ Endakan menuju ke sel yang salah sebelum menyimpan (“Sel terakhir tidak diatur ulang hingga Anda menyimpan lembar kerja”, dari http://msdn.microsoft.com/en-us/library/aa139976%28v=office.10% 29.aspx . Ini adalah referensi lama, tetapi dalam hal ini valid).

Untuk kriteria 3, saya tidak tahu metode bawaan apa pun . Kriteria 2 tidak memperhitungkan Pemformatan Bersyarat. Seseorang mungkin memiliki sel yang diformat, berdasarkan pada rumus, yang tidak terdeteksi oleh UsedRangeatau Ctrl+ End. Dalam gambar, sel terakhir adalah B3, karena pemformatan diterapkan secara eksplisit padanya. Sel B6: D7 memiliki format yang berasal dari aturan Pemformatan Bersyarat, dan ini bahkan tidak terdeteksi oleh UsedRange. Akuntansi untuk ini akan memerlukan beberapa pemrograman VBA.

masukkan deskripsi gambar di sini


Mengenai pertanyaan spesifik Anda : Apa alasan di balik ini?

Kode Anda menggunakan sel pertama dalam rentang Anda E4: E48 sebagai trampolin, untuk melompat turun bersama End(xlDown).

Output "keliru" akan diperoleh jika tidak ada sel non-kosong dalam rentang Anda selain mungkin yang pertama. Kemudian, Anda melompat dalam gelap , yaitu, turun worksheet (Anda harus mencatat perbedaan antara kosong dan string kosong !).

Perhatikan bahwa:

  1. Jika rentang Anda berisi sel tidak kosong yang tidak bersebelahan, maka hasilnya juga akan salah.

  2. Jika hanya ada satu sel yang tidak kosong, tetapi itu bukan yang pertama, kode Anda akan tetap memberikan hasil yang benar.

sancho.s ReinstateMonicaCellio
sumber
3
Saya setuju bahwa orang pertama-tama harus memutuskan apa yang dianggap digunakan . Saya melihat setidaknya 6 makna. Sel memiliki: 1) data, yaitu formula, kemungkinan menghasilkan nilai kosong; 2) nilai, yaitu formula atau konstanta tidak kosong; 3) memformat; 4) pemformatan bersyarat; 5) bentuk (termasuk Komentar) yang tumpang tindih sel; 6) keterlibatan dalam Tabel (Daftar Objek). Kombinasi mana yang ingin Anda uji? Beberapa (seperti Tabel) mungkin lebih sulit untuk diuji, dan beberapa mungkin jarang (seperti bentuk di luar rentang data), tetapi yang lain mungkin bervariasi berdasarkan situasi (misalnya, rumus dengan nilai kosong).
GlennFromIowa
20

Saya membuat fungsi satu atap ini untuk menentukan baris, kolom, dan sel terakhir, baik itu untuk data, diformat (dikelompokkan / dikomentari / disembunyikan) sel atau pemformatan bersyarat .

Sub LastCellMsg()
    Dim strResult As String
    Dim lngDataRow As Long
    Dim lngDataCol As Long
    Dim strDataCell As String
    Dim strDataFormatRow As String
    Dim lngDataFormatCol As Long
    Dim strDataFormatCell As String
    Dim oFormatCond As FormatCondition
    Dim lngTempRow As Long
    Dim lngTempCol As Long
    Dim lngCFRow As Long
    Dim lngCFCol As Long
    Dim strCFCell As String
    Dim lngOverallRow As Long
    Dim lngOverallCol As Long
    Dim strOverallCell As String

    With ActiveSheet

        If .ListObjects.Count > 0 Then
            MsgBox "Cannot return reliable results, as there is at least one table in the worksheet."
            Exit Sub
        End If

        strResult = "Workbook name: " & .Parent.Name & vbCrLf
        strResult = strResult & "Sheet name: " & .Name & vbCrLf

        'DATA:
        'last data row
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            lngDataRow = .Cells.Find(What:="*", _
             After:=.Range("A1"), _
             Lookat:=xlPart, _
             LookIn:=xlFormulas, _
             SearchOrder:=xlByRows, _
             SearchDirection:=xlPrevious, _
             MatchCase:=False).Row
        Else
            lngDataRow = 1
        End If
        'strResult = strResult & "Last data row: " & lngDataRow & vbCrLf

        'last data column
        If Application.WorksheetFunction.CountA(.Cells) <> 0 Then
            lngDataCol = .Cells.Find(What:="*", _
             After:=.Range("A1"), _
             Lookat:=xlPart, _
             LookIn:=xlFormulas, _
             SearchOrder:=xlByColumns, _
             SearchDirection:=xlPrevious, _
             MatchCase:=False).Column
        Else
            lngDataCol = 1
        End If
        'strResult = strResult & "Last data column: " & lngDataCol & vbCrLf

        'last data cell
        strDataCell = Replace(Cells(lngDataRow, lngDataCol).Address, "$", vbNullString)
        strResult = strResult & "Last data cell: " & strDataCell & vbCrLf

        'FORMATS:
        'last data/formatted/grouped/commented/hidden row
        strDataFormatRow = StrReverse(Split(StrReverse(.UsedRange.Address), "$")(0))
        'strResult = strResult & "Last data/formatted row: " & strDataFormatRow & vbCrLf

        'last data/formatted/grouped/commented/hidden column
        lngDataFormatCol = Range(StrReverse(Split(StrReverse(.UsedRange.Address), "$")(1)) & "1").Column
        'strResult = strResult & "Last data/formatted column: " & lngDataFormatCol & vbCrLf

        'last data/formatted/grouped/commented/hidden cell
        strDataFormatCell = Replace(Cells(strDataFormatRow, lngDataFormatCol).Address, "$", vbNullString)
        strResult = strResult & "Last data/formatted cell: " & strDataFormatCell & vbCrLf

        'CONDITIONAL FORMATS:
        For Each oFormatCond In .Cells.FormatConditions

            'last conditionally-formatted row
            lngTempRow = CLng(StrReverse(Split(StrReverse(oFormatCond.AppliesTo.Address), "$")(0)))
            If lngTempRow > lngCFRow Then lngCFRow = lngTempRow

            'last conditionally-formatted column
            lngTempCol = Range(StrReverse(Split(StrReverse(oFormatCond.AppliesTo.Address), "$")(1)) & "1").Column
            If lngTempCol > lngCFCol Then lngCFCol = lngTempCol
        Next
        'no results are returned for Conditional Format if there is no such
        If lngCFRow <> 0 Then
            'strResult = strResult & "Last cond-formatted row: " & lngCFRow & vbCrLf
            'strResult = strResult & "Last cond-formatted column: " & lngCFCol & vbCrLf

            'last conditionally-formatted cell
            strCFCell = Replace(Cells(lngCFRow, lngCFCol).Address, "$", vbNullString)
            strResult = strResult & "Last cond-formatted cell: " & strCFCell & vbCrLf
        End If

        'OVERALL:
        lngOverallRow = Application.WorksheetFunction.Max(lngDataRow, strDataFormatRow, lngCFRow)
        'strResult = strResult & "Last overall row: " & lngOverallRow & vbCrLf
        lngOverallCol = Application.WorksheetFunction.Max(lngDataCol, lngDataFormatCol, lngCFCol)
        'strResult = strResult & "Last overall column: " & lngOverallCol & vbCrLf
        strOverallCell = Replace(.Cells(lngOverallRow, lngOverallCol).Address, "$", vbNullString)
        strResult = strResult & "Last overall cell: " & strOverallCell & vbCrLf

        MsgBox strResult
        Debug.Print strResult

    End With

End Sub

Hasilnya terlihat seperti ini:
tentukan sel terakhir

Untuk hasil yang lebih rinci, beberapa baris dalam kode dapat dibatalkan komentar:
kolom terakhir, baris

Ada satu batasan - jika ada tabel dalam lembar, hasilnya bisa menjadi tidak dapat diandalkan, jadi saya memutuskan untuk menghindari menjalankan kode dalam kasus ini:

If .ListObjects.Count > 0 Then
    MsgBox "Cannot return reliable results, as there is at least one table in the worksheet."
    Exit Sub
End If
ZygD
sumber
2
@ Franklin - Saya baru saja melihat pesan inbox dengan koreksi Anda yang ditolak oleh pengulas. Saya memperbaiki kesalahan itu. Saya sudah menggunakan fungsi ini sekali ketika saya membutuhkannya dan saya akan menggunakannya lagi, jadi terima kasih banyak, sobat!
ZygD
11

Satu catatan penting yang perlu diingat saat menggunakan solusi ...

LastRow = ws.Cells.Find(What:="*", After:=ws.range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row

... adalah untuk memastikan bahwa LastRowvariabel Anda Longbertipe:

Dim LastRow as Long

Kalau tidak, Anda akan mendapatkan kesalahan OVERFLOW dalam situasi tertentu di buku kerja .XLSX

Ini adalah fungsi enkapsulasi saya yang saya masukkan ke berbagai penggunaan kode.

Private Function FindLastRow(ws As Worksheet) As Long
    ' --------------------------------------------------------------------------------
    ' Find the last used Row on a Worksheet
    ' --------------------------------------------------------------------------------
    If WorksheetFunction.CountA(ws.Cells) > 0 Then
        ' Search for any entry, by searching backwards by Rows.
        FindLastRow = ws.Cells.Find(What:="*", After:=ws.range("a1"), SearchOrder:=xlByRows, SearchDirection:=xlPrevious).Row
    End If
End Function
Uskup
sumber
8

Saya akan menambahkan ke jawaban yang diberikan oleh Siddarth Rout untuk mengatakan bahwa panggilan CountA dapat dilewati dengan memiliki Temukan mengembalikan objek Range, bukan nomor baris, dan kemudian menguji objek Range yang dikembalikan untuk melihat apakah itu bukan apa-apa (lembar kerja kosong) .

Juga, saya akan meminta versi saya dari prosedur LastRow mengembalikan nol untuk lembar kerja kosong, maka saya bisa tahu itu kosong.

tidak ada comprende
sumber
8

Saya ingin tahu bahwa tidak ada yang menyebutkan ini, Tapi cara termudah untuk mendapatkan sel yang terakhir digunakan adalah:

Function GetLastCell(sh as Worksheet) As Range
    GetLastCell = sh.Cells(1,1).SpecialCells(xlLastCell)
End Function

Ini pada dasarnya mengembalikan sel yang sama dengan yang Anda dapatkan Ctrl+ Endsetelah memilih Cell A1.

Peringatan: Excel melacak sel paling kanan bawah yang pernah digunakan dalam lembar kerja. Jadi jika misalnya Anda memasukkan sesuatu di B3 dan sesuatu yang lain di H8 dan kemudian menghapus konten H8 , menekan Ctrl+ Endmasih akan membawa Anda ke sel H8 . Fungsi di atas akan memiliki perilaku yang sama.

dotNET
sumber
2
Last Celldi Excel terkadang merujuk ke sel kosong (dari Used Range) yang berbeda dari Last Used Cell;).
shA.t
1
OP hanya membutuhkan baris terakhir tetapi Anda benar, sel terakhir harus H5 ; Tetapi Anda dapat menguji fungsi Anda setelah menghapus nilai di A5 Anda akan melihat bahwa sel terakhir adalah sel kosong itu, dan saya pikir kode Anda memerlukan beberapa pengeditan seperti Cells(1,1).Select()itu mungkin tidak valid ActiveSheet.Cells(1,1).Select; Juga di VBA tidak disarankan untuk digunakan Select;).
shA.t
5
Ini melanggar dua aturan utama untuk Excel VBA: Jangan gunakan Pilih! Dan jangan menganggap lembar yang Anda inginkan adalah yang aktif.
Rachel Hettinger
1
Ini adalah jawaban lama, tetapi tidak ada a Set.
BigBen
8

Karena pertanyaan awal adalah tentang masalah dengan menemukan sel terakhir, dalam jawaban ini saya akan mencantumkan berbagai cara Anda bisa mendapatkan hasil yang tidak terduga ; lihat jawaban saya untuk "Bagaimana saya bisa menemukan baris terakhir yang berisi data dalam lembar Excel dengan makro?" untuk saya ambil pada pemecahan ini.

Saya akan mulai dengan memperluas jawaban oleh sancho.s dan komentar oleh GlennFromIowa , menambahkan lebih detail:

[...] yang pertama harus memutuskan apa yang dianggap digunakan. Saya melihat setidaknya 6 makna. Sel memiliki:

  • 1) data, yaitu formula, kemungkinan menghasilkan nilai kosong;
  • 2) nilai, yaitu formula atau konstanta tidak kosong;
  • 3) memformat;
  • 4) pemformatan bersyarat;
  • 5) bentuk (termasuk Komentar) yang tumpang tindih sel;
  • 6) keterlibatan dalam Tabel (Daftar Objek).

Kombinasi mana yang ingin Anda uji? Beberapa (seperti Tabel) mungkin lebih sulit untuk diuji, dan beberapa mungkin jarang (seperti bentuk di luar rentang data), tetapi yang lain mungkin bervariasi berdasarkan situasi (misalnya, rumus dengan nilai kosong).

Hal-hal lain yang mungkin ingin Anda pertimbangkan:

  • A) Bisakah ada baris tersembunyi (mis. Autofilter), sel kosong atau baris kosong?
  • B) Kinerja seperti apa yang dapat diterima?
  • C) Bisakah makro VBA memengaruhi buku kerja atau pengaturan aplikasi dengan cara apa pun?

Dengan mengingat hal itu, mari kita lihat bagaimana cara umum mendapatkan "sel terakhir" dapat menghasilkan hasil yang tidak terduga:

  • The .End(xlDown)kode dari pertanyaan akan mematahkan paling mudah (misalnya dengan sel non-kosong tunggal atau ketika ada sel kosong di antara ) untuk alasan yang dijelaskan dalam jawaban oleh Siddharth Rout sini (mencari "xlDown sama tidak bisa diandalkan." ) 👎
  • Solusi apa pun yang didasarkan pada Count( CountAatau Cells*.Count) atau .CurrentRegionjuga akan pecah di hadapan sel atau baris kosong 👎
  • Sebuah solusi yang melibatkan .End(xlUp)pencarian mundur dari akhir kolom akan, sama seperti CTRL + UP, mencari data (rumus yang menghasilkan nilai kosong dianggap "data") dalam baris yang terlihat (jadi menggunakannya dengan autofilter yang diaktifkan mungkin menghasilkan hasil yang salah ⚠️ ).

    Anda harus berhati-hati untuk menghindari jebakan standar (untuk detail saya akan lagi merujuk pada jawaban oleh Siddharth Rout di sini, lihat bagian "Temukan Baris Terakhir dalam Kolom" ), seperti mengkodekan baris terakhir ( Range("A65536").End(xlUp)) bukannya mengandalkan sht.Rows.Count.

  • .SpecialCells(xlLastCell)setara dengan CTRL + END, mengembalikan sel paling bawah dan paling kanan dari "rentang yang digunakan", jadi semua peringatan yang berlaku untuk mengandalkan "rentang yang digunakan", berlaku untuk metode ini juga. Selain itu, "rentang yang digunakan" hanya direset saat menyimpan buku kerja dan saat mengakses worksheet.UsedRange, sehingga xlLastCelldapat menghasilkan hasil yang basi⚠️ dengan modifikasi yang belum disimpan (misalnya setelah beberapa baris dihapus). Lihat jawaban terdekat dengan dotNET .
  • sht.UsedRange(dijelaskan secara terperinci dalam jawaban oleh sancho.s di sini) mempertimbangkan data dan pemformatan (meskipun bukan pemformatan bersyarat) dan mengatur ulang "rentang yang digunakan" dari lembar kerja , yang mungkin atau mungkin tidak seperti yang Anda inginkan.

    Perhatikan bahwa kesalahan umum adalah ️ untuk digunakan .UsedRange.Rows.Count⚠️, yang mengembalikan jumlah baris dalam rentang yang digunakan, bukan nomor baris terakhir (mereka akan berbeda jika beberapa baris pertama kosong), untuk detail lihat jawaban newguy untuk Bagaimana saya dapat menemukan baris terakhir yang berisi data dalam lembar Excel dengan makro?

  • .Findmemungkinkan Anda menemukan baris terakhir dengan data apa pun (termasuk rumus) atau nilai yang tidak kosong di kolom mana pun . Anda dapat memilih apakah Anda tertarik pada rumus atau nilai, tetapi yang menariknya adalah ia menyetel ulang default di dialog Temukan Excel ️️⚠️, yang dapat sangat membingungkan pengguna Anda. Ini juga perlu digunakan dengan hati-hati, lihat jawaban oleh Siddharth Rout di sini (bagian "Temukan Baris Terakhir dalam Lembaran" )
  • Solusi yang lebih eksplisit yang memeriksa masing Cells- masing individu dalam satu lingkaran pada umumnya lebih lambat daripada menggunakan kembali fungsi Excel (meskipun masih bisa menjadi performan), tetapi membiarkan Anda menentukan dengan tepat apa yang ingin Anda temukan. Lihat solusi saya berdasarkan pada UsedRangedan array VBA untuk menemukan sel terakhir dengan data di kolom yang diberikan - ini menangani baris tersembunyi, filter, kosong, tidak mengubah standar Cari dan cukup performan.

Solusi apa pun yang Anda pilih, berhati-hatilah

  • untuk digunakan Longalih-alih Integermenyimpan nomor baris (untuk menghindari mendapatkan Overflowlebih dari 65 ribu baris) dan
  • untuk selalu menentukan lembar kerja yang sedang Anda kerjakan (yaitu Dim ws As Worksheet ... ws.Range(...)alih-alih Range(...))
  • saat menggunakan .Value(yang merupakan Variant) hindari gips implisit seperti .Value <> ""karena mereka akan gagal jika sel berisi nilai kesalahan.
Nickolay
sumber
4

Namun pertanyaan ini mencari untuk menemukan baris terakhir menggunakan VBA, saya pikir akan lebih baik untuk memasukkan formula array untuk fungsi lembar kerja karena ini sering dikunjungi:

{=ADDRESS(MATCH(INDEX(D:D,MAX(IF(D:D<>"",ROW(D:D)-ROW(D1)+1)),1),D:D,0),COLUMN(D:D))}

Anda harus memasukkan rumus tanpa tanda kurung dan kemudian tekan Shift+ Ctrl+ Enteruntuk menjadikannya rumus array.

Ini akan memberi Anda alamat sel yang terakhir digunakan di kolom D.

M--
sumber
1
Saya suka ini. Saya mungkin mengubah sedikit untuk hanya mendapatkan nomor baris ... '{= MATCH (INDEX (D: D, MAX (JIKA: D <> "), ROW (D: D) -ROW (D1) +1)) , 1), D: D, 0)} '
PGSystemTester
3
sub last_filled_cell()
msgbox range("A65536").end(xlup).row
end sub

Di sini, A65536adalah sel terakhir di Kolom A kode ini diuji pada excel 2003.

Ashwith Ullal
sumber
Bisakah Anda menjelaskan bagaimana kode Anda menjawab pertanyaan lama ini?
shoover
1
Meskipun jawaban ini mungkin benar dan bermanfaat, lebih disukai jika Anda menyertakan beberapa penjelasan bersama dengan itu untuk menjelaskan bagaimana itu membantu menyelesaikan masalah. Ini menjadi sangat berguna di masa depan, jika ada perubahan (mungkin tidak terkait) yang menyebabkannya berhenti bekerja dan pengguna perlu memahami bagaimana cara kerjanya.
Kevin Brown
2

Saya sedang mencari cara untuk meniru CTRL+ Shift+ End, jadi solusi dotNET sangat bagus, kecuali dengan Excel 2010 saya perlu menambahkan setjika saya ingin menghindari kesalahan:

Function GetLastCell(sh As Worksheet) As Range
  Set GetLastCell = sh.Cells(1, 1).SpecialCells(xlLastCell)
End Function

dan cara memeriksa ini sendiri:

Sub test()
  Dim ws As Worksheet, r As Range
  Set ws = ActiveWorkbook.Sheets("Sheet1")
  Set r = GetLastCell(ws)
  MsgBox r.Column & "-" & r.Row
End Sub
J. Chomel
sumber
1

Ini dua sen saya.

IMHO, risiko baris tersembunyi dengan data yang dikecualikan terlalu signifikan untuk xlUpdianggap sebagai jawaban One stop . Saya setuju itu sederhana dan akan bekerja PALING saat itu, tetapi itu menyajikan risiko mengecilkan baris terakhir, tanpa peringatan. Ini bisa menghasilkan hasil CATASTROPHIC di beberapa poinit untuk seseorang yang melompat di Stack Overlow dan mencari "cara pasti" untuk menangkap nilai ini.

The FindMetode sempurna dan saya akan menyetujui itu sebagai Jawaban One Stop . Namun kelemahan dari mengubah Findpengaturan dapat mengganggu, terutama jika ini adalah bagian dari UDF.

Jawaban lain yang diposting tidak masalah, namun kerumitannya sedikit berlebihan. Jadi, inilah upaya saya untuk menemukan keseimbangan keandalan, kompleksitas minimal, dan tidak menggunakan Find.

Function LastRowNumber(Optional rng As Range) As Long

If rng Is Nothing Then
    Set rng = ActiveSheet.UsedRange
Else
    Set rng = Intersect(rng.Parent.UsedRange, rng.EntireColumn)
    If rng Is Nothing Then
        LastRowNumber = 1
        Exit Function
    ElseIf isE = 0 Then
        LastRowNumber = 1
        Exit Function

    End If

End If

LastRowNumber = rng.Cells(rng.Rows.Count, 1).Row

Do While IsEmpty(Intersect(rng, _
    rng.Parent.Rows(LastRowNumber)))

    LastRowNumber = LastRowNumber - 1
Loop

End Function

Kenapa ini bagus:

  • Cukup sederhana, tidak banyak variabel.
  • Mengizinkan beberapa kolom.
  • Tidak mengubah Findpengaturan
  • Dinamis jika digunakan sebagai UDF dengan seluruh kolom dipilih.

Mengapa ini buruk:

  • Dengan kumpulan data yang sangat besar dan kesenjangan besar antara rentang yang digunakan dan baris terakhir dalam kolom yang ditentukan, ini akan melakukan lebih lambat, dalam kasus yang jarang lebih lambat.

Namun, saya pikir One-Stop-Solution yang memiliki kelemahan findpengaturan kacau atau melakukan lebih lambat adalah solusi keseluruhan yang lebih baik. Seorang pengguna kemudian dapat mengotak-atik pengaturan mereka untuk mencoba meningkatkan, mengetahui apa yang terjadi dengan kode mereka. Menggunakan xLUptidak akan memperingatkan potensi risiko dan mereka dapat melanjutkan untuk yang tahu berapa lama tidak mengetahui kode mereka tidak berfungsi dengan benar.

PGSystemTester
sumber
1

Selama 3+ tahun terakhir ini adalah fungsi yang saya gunakan untuk menemukan baris terakhir dan kolom terakhir per kolom yang ditentukan (untuk baris) dan baris (untuk kolom):

Kolom Terakhir:

Function lastCol(Optional wsName As String, Optional rowToCheck As Long = 1) As Long

    Dim ws  As Worksheet

    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If

    lastCol = ws.Cells(rowToCheck, ws.Columns.Count).End(xlToLeft).Column

End Function

Baris terakhir:

Function lastRow(Optional wsName As String, Optional columnToCheck As Long = 1) As Long

    Dim ws As Worksheet

    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If

    lastRow = ws.Cells(ws.Rows.Count, columnToCheck).End(xlUp).Row

End Function

Untuk kasus OP, ini adalah cara untuk mendapatkan baris terakhir di kolom E:

Debug.Print lastRow(columnToCheck:=Range("E4:E48").Column)

Baris Terakhir, menghitung baris kosong dengan data:

Di sini kita dapat menggunakan rumus Excel yang terkenal , yang memberi kita baris terakhir lembar kerja di Excel, tanpa melibatkan VBA -=IFERROR(LOOKUP(2,1/(NOT(ISBLANK(A:A))),ROW(A:A)),0)

Untuk menempatkan ini dalam VBA dan tidak menulis apa pun di Excel, menggunakan parameter untuk fungsi yang terakhir, sesuatu seperti ini dapat diingat:

Public Function LastRowWithHidden(Optional wsName As String, Optional columnToCheck As Long = 1) As Long

    Dim ws As Worksheet

    If wsName = vbNullString Then
        Set ws = ActiveSheet
    Else
        Set ws = Worksheets(wsName)
    End If

    Dim letters As String
    letters = ColLettersGenerator(columnToCheck)
    LastRowWithHidden = ws.Evaluate("=IFERROR(LOOKUP(2,1/(NOT(ISBLANK(" & letters & "))),ROW(" & letters & " )),0)")

End Function

Function ColLettersGenerator(col As Long) As String

    Dim result As Variant
    result = Split(Cells(1, col).Address(True, False), "$")
    ColLettersGenerator = result(0) & ":" & result(0)

End Function
Vityata
sumber
Ini akan mengembalikan hasil yang salah jika baris / kolom terakhir disembunyikan.
PGSystemTester
@PGSystemTester - ya, tetapi dalam pemahaman saya, ketika saya memprogramnya, jika disembunyikan itu bukan kolom / baris terakhir yang diperlukan.
Vityata
Senang itu bekerja untukmu. Saya menduga situasi Anda bukan kasus penggunaan biasa. Lebih sering ketika saya bekerja dengan klien yang membutuhkan baris terakhir, mereka mencari sel terendah dengan data, bukan sel terlihat terendah dengan data. Pokoknya ... senang itu berhasil. 👍
PGSystemTester
@PGSystemTester - Saya mengerti maksud Anda, tetapi merawat struktur dan tidak membiarkan sel-sel yang tak terlihat bekerja seperti pesona.
Vityata
@PGSystemTester - ya, jika tugas memungkinkan baris kosong, saya mungkin akan menggunakan EVAL()dan rumus Excel yang terkenal. Meskipun orang mungkin berpikir itu Eval()adalah kejahatan dan ini adalah kisah menarik lainnya untuk ditulis ...
Vityata
0
Sub lastRow()

    Dim i As Long
        i = Cells(Rows.Count, 1).End(xlUp).Row
            MsgBox i

End Sub

sub LastRow()

'Paste & for better understanding of the working use F8 Key to run the code .

dim WS as worksheet
dim i as long

set ws = thisworkbook("SheetName")

ws.activate

ws.range("a1").select

ws.range("a1048576").select

activecell.end(xlup).select

i= activecell.row

msgbox "My Last Row Is " & i

End sub
pengguna85489
sumber