Comment puis-je trouver la dernière ligne qui contient des données dans la feuille Excel avec une macro?

Comment puis-je trouver la dernière ligne qui contient des données dans une colonne spécifique et sur une feuille spécifique?

53
demandé sur ashleedawg 2008-09-16 14:54:53

12 réponses

Que Diriez-vous de:

 Sub GetLastRow(strSheet, strColumn)
 Dim MyRange As Range
 Dim lngLastRow As Long

    Set MyRange = Worksheets(strSheet).Range(strColum & "1")

    lngLastRow = Cells(Rows.Count, MyRange.Column).End(xlUp).Row
 End Sub

Nouveau Commentaire

Ce

  Cells.Find("*",SearchOrder:=xlByRows,SearchDirection:=xlPrevious).Row

renverra le numéro de ligne de la dernière cellule même si une seule cellule dans la dernière rangée a des données.

41
répondu Fionnuala 2017-01-27 22:00:08

Vous devez utiliser le .End(xlup) mais au lieu d'utiliser 65536 vous pouvez utiliser:

sheetvar.Rows.Count

de cette façon, il fonctionne pour Excel 2007 qui je crois a plus de 65536 lignes

21
répondu Jon Fournier 2012-06-02 16:17:31
function LastRowIndex(byval w as worksheet, byval col as variant) as long
  dim r as range

  set r = application.intersect(w.usedrange, w.columns(col))
  if not r is nothing then
    set r = r.cells(r.cells.count)

    if isempty(r.value) then
      LastRowIndex = r.end(xlup).row
    else
      LastRowIndex = r.row
    end if
  end if
end function

Utilisation:

? LastRowIndex(ActiveSheet, 5)
? LastRowIndex(ActiveSheet, "AI")
7
répondu GSerg 2008-09-16 11:14:22

Simple et rapide:

Dim lastRow as long
Range("A1").select
lastRow = Cells.Find("*",SearchOrder:=xlByRows,SearchDirection:=xlPrevious).Row

exemple d'utilisation:

cells(lastRow,1)="Ultima Linha, Last Row. Youpi!!!!"

'or 

Range("A" & lastRow).Value = "FIM, THE END"
7
répondu user2988717 2014-08-26 15:32:42

Voici une solution pour trouver la dernière ligne de la dernière colonne, ou la dernière cellule. Il aborde le dilemme du Style de référence A1 R1C1 pour la colonne qu'il trouve. J'aimerais pouvoir donner crédit, mais je ne peux pas trouver/se rappeler d'où je l'ai obtenu, alors " merci!"à qui que ce soit qui a posté le code original quelque part.

Sub Macro1
    Sheets("Sheet1").Select
    MsgBox "The last row found is: " & Last(1, ActiveSheet.Cells)
    MsgBox "The last column (R1C1) found is: " & Last(2, ActiveSheet.Cells)
    MsgBox "The last cell found is: " & Last(3, ActiveSheet.Cells)
    MsgBox "The last column (A1) found is: " & Last(4, ActiveSheet.Cells)
End Sub

Function Last(choice As Integer, rng As Range)
' 1 = last row
' 2 = last column (R1C1)
' 3 = last cell
' 4 = last column (A1)
    Dim lrw As Long
    Dim lcol As Integer

    Select Case choice
    Case 1:
        On Error Resume Next
        Last = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        LookAt:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByRows, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Row
        On Error GoTo 0

    Case 2:
        On Error Resume Next
        Last = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        LookAt:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByColumns, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Column
        On Error GoTo 0

    Case 3:
        On Error Resume Next
        lrw = rng.Find(What:="*", _
                       After:=rng.Cells(1), _
                       LookAt:=xlPart, _
                       LookIn:=xlFormulas, _
                       SearchOrder:=xlByRows, _
                       SearchDirection:=xlPrevious, _
                       MatchCase:=False).Row
        lcol = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        LookAt:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByColumns, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Column
        Last = Cells(lrw, lcol).Address(False, False)
        If Err.Number > 0 Then
            Last = rng.Cells(1).Address(False, False)
            Err.Clear
        End If
        On Error GoTo 0
    Case 4:
        On Error Resume Next
        Last = rng.Find(What:="*", _
                        After:=rng.Cells(1), _
                        LookAt:=xlPart, _
                        LookIn:=xlFormulas, _
                        SearchOrder:=xlByColumns, _
                        SearchDirection:=xlPrevious, _
                        MatchCase:=False).Column
        On Error GoTo 0
        Last = R1C1converter("R1C" & Last, 1)
        For i = 1 To Len(Last)
            s = Mid(Last, i, 1)
            If Not s Like "#" Then s1 = s1 & s
        Next i
        Last = s1

    End Select

End Function

Function R1C1converter(Address As String, Optional R1C1_output As Integer, Optional RefCell As Range) As String
    'Converts input address to either A1 or R1C1 style reference relative to RefCell
    'If R1C1_output is xlR1C1, then result is R1C1 style reference.
    'If R1C1_output is xlA1 (or missing), then return A1 style reference.
    'If RefCell is missing, then the address is relative to the active cell
    'If there is an error in conversion, the function returns the input Address string
    Dim x As Variant
    If RefCell Is Nothing Then Set RefCell = ActiveCell
    If R1C1_output = xlR1C1 Then
        x = Application.ConvertFormula(Address, xlA1, xlR1C1, , RefCell) 'Convert A1 to R1C1
    Else
        x = Application.ConvertFormula(Address, xlR1C1, xlA1, , RefCell) 'Convert R1C1 to A1
    End If
    If IsError(x) Then
        R1C1converter = Address
    Else
        'If input address is A1 reference and A1 is requested output, then Application.ConvertFormula
        'surrounds the address in single quotes.
        If Right(x, 1) = "'" Then
            R1C1converter = Mid(x, 2, Len(x) - 2)
        Else
            x = Application.Substitute(x, "$", "")
            R1C1converter = x
        End If
    End If
End Function
3
répondu 2 revs, 2 users 67%Greg Podesta 2011-11-18 20:57:40
Public Function LastData(rCol As Range) As Range    
    Set LastData = rCol.Find("*", rCol.Cells(1), , , , xlPrevious)    
End Function

Utilisation: ?lastdata(activecell.EntireColumn).Address

3
répondu Dick Kusleika 2013-12-19 09:40:56

je voudrais ajouter une façon plus fiable en utilisant UsedRange pour trouver la dernière ligne utilisée:

lastRow = Sheet1.UsedRange.Row + Sheet1.UsedRange.Rows.Count - 1

de même pour trouver la dernière colonne utilisée Vous pouvez voir ce

enter image description here

résultat dans la fenêtre immédiate:

?Sheet1.UsedRange.Row+Sheet1.UsedRange.Rows.Count-1
 21 
1
répondu newguy 2017-05-23 12:10:44

toutes les solutions qui reposent sur des comportements intégrés (comme .Find et .End ) ont des limites qui ne sont pas bien documentées (voir mon autre réponse pour plus de détails).

j'avais besoin de quelque chose qui:

  • trouve la dernière case non vide (i.e. qui a n'importe quelle formule ou valeur , même si c'est une chaîne vide) dans une colonne spécifique
  • S'appuie sur des primitives avec un comportement bien défini
  • fonctionne de manière fiable avec les filtres automatiques et les modifications de l'utilisateur
  • fonctionne aussi vite que possible sur 10 000 lignes (à exécuter dans un Worksheet_Change handler sans se sentir léthargique)
  • ...avec des performances qui ne tombent pas d'une falaise avec des données accidentelles ou formatage mis à la toute fin de la feuille (à ~1M rangées)

la solution ci-dessous:

  • utilise UsedRange pour trouver la limite supérieure du nombre de lignes (pour faire la recherche de la vraie "dernière ligne" rapide dans le cas commun où il est proche de la fin de la gamme utilisée);
  • va en arrière pour trouver la ligne avec des données dans la colonne donnée;
  • ...utilisation de tableaux VBA pour éviter d'accéder à chaque ligne individuellement (dans le cas où il ya beaucoup de lignes dans le UsedRange , nous devons sauter)

(pas de tests, désolé)

' Returns the 1-based row number of the last row having a non-empty value in the given column (0 if the whole column is empty)
Private Function getLastNonblankRowInColumn(ws As Worksheet, colNo As Integer) As Long
    ' Force Excel to recalculate the "last cell" (the one you land on after CTRL+END) / "used range"
    ' and get the index of the row containing the "last cell". This is reasonably fast (~1 ms/10000 rows of a used range)
    Dim lastRow As Long: lastRow = ws.UsedRange.Rows(ws.UsedRange.Rows.Count).Row - 1 ' 0-based

    ' Since the "last cell" is not necessarily the one we're looking for (it may be in a different column, have some
    ' formatting applied but no value, etc), we loop backward from the last row towards the top of the sheet).
    Dim wholeRng As Range: Set wholeRng = ws.Columns(colNo)

    ' Since accessing cells one by one is slower than reading a block of cells into a VBA array and looping through the array,
    ' we process in chunks of increasing size, starting with 1 cell and doubling the size on each iteration, until MAX_CHUNK_SIZE is reached.
    ' In pathological cases where Excel thinks all the ~1M rows are in the used range, this will take around 100ms.
    ' Yet in a normal case where one of the few last rows contains the cell we're looking for, we don't read too many cells.
    Const MAX_CHUNK_SIZE = 2 ^ 10 ' (using large chunks gives no performance advantage, but uses more memory)
    Dim chunkSize As Long: chunkSize = 1
    Dim startOffset As Long: startOffset = lastRow + 1 ' 0-based
    Do ' Loop invariant: startOffset>=0 and all rows after startOffset are blank (i.e. wholeRng.Rows(i+1) for i>=startOffset)
        startOffset = IIf(startOffset - chunkSize >= 0, startOffset - chunkSize, 0)
        ' Fill `vals(1 To chunkSize, 1 To 1)` with column's rows indexed `[startOffset+1 .. startOffset+chunkSize]` (1-based, inclusive)
        Dim chunkRng As Range: Set chunkRng = wholeRng.Resize(chunkSize).Offset(startOffset)
        Dim vals() As Variant
        If chunkSize > 1 Then
            vals = chunkRng.Value2
        Else ' reading a 1-cell range requires special handling <http://www.cpearson.com/excel/ArraysAndRanges.aspx>
            ReDim vals(1 To 1, 1 To 1)
            vals(1, 1) = chunkRng.Value2
        End If

        Dim i As Long
        For i = UBound(vals, 1) To LBound(vals, 1) Step -1
            If Not IsEmpty(vals(i, 1)) Then
                getLastNonblankRowInColumn = startOffset + i
                Exit Function
            End If
        Next i

        If chunkSize < MAX_CHUNK_SIZE Then chunkSize = chunkSize * 2
    Loop While startOffset > 0

    getLastNonblankRowInColumn = 0
End Function
1
répondu Nickolay 2018-04-22 23:02:25
Public Function GetLastRow(ByVal SheetName As String) As Integer
    Dim sht As Worksheet
    Dim FirstUsedRow As Integer     'the first row of UsedRange
    Dim UsedRows As Integer         ' number of rows used

    Set sht = Sheets(SheetName)
    ''UsedRange.Rows.Count for the empty sheet is 1
    UsedRows = sht.UsedRange.Rows.Count
    FirstUsedRow = sht.UsedRange.Row
    GetLastRow = FirstUsedRow + UsedRows - 1

    Set sht = Nothing
End Function

de la feuille.UsedRange.Rangée.Nombre de lignes utilisées, ne pas inclure la ligne vide au-dessus de la première ligne utilisée

si la ligne 1 est vide, et que la dernière ligne utilisée est 10, Utilisez la barre.Rangée.Le compte retournera 9, pas 10.

cette fonction calcule le nombre de la première ligne UsedRange plus le nombre de lignes UsedRange.

0
répondu Phaithoon Jariyanantakul 2017-09-26 06:21:50

la première fonction déplace le curseur vers la dernière ligne non vide de la colonne. La deuxième fonction imprime cette rangée de colonnes.

Selection.End(xlDown).Select
MsgBox (ActiveCell.Row)
-1
répondu databyss 2008-09-16 11:23:04
sub test()
msgbox Worksheets("sheet_name").Range("A65536").End(xlUp).Row
end sub

c'est la valeur de recherche dans la colonne A à cause de" a65536 "

-1
répondu Ashwith Ullal 2015-10-30 11:08:29
Function LastRow(rng As Range) As Long
    Dim iRowN As Long
    Dim iRowI As Long
    Dim iColN As Integer
    Dim iColI As Integer
    iRowN = 0
    iColN = rng.Columns.count
    For iColI = 1 To iColN
        iRowI = rng.Columns(iColI).Offset(65536 - rng.Row, 0).End(xlUp).Row
        If iRowI > iRowN Then iRowN = iRowI
    Next
    LastRow = iRowN
End Function 
-2
répondu Galwegian 2008-09-16 10:56:52