Cómo encontrar la última fecha/hora en la columna usando macro

Cómo encontrar la última fecha/hora en la columna usando macro

Tengo datos generados por el sistema que se parecen a la siguiente tabla. En la última columna necesito mostrar el usuario que fue el último en actualizar el sistema de cada departamento.

Update Time     User    Department  Last update  
-------------------------------------------------------
1/19/12 7:26    John    A
1/19/12 6:26    Yen     A
1/18/12 9:47    Jefta   B
1/18/12 9:47    Jefta   B
1/18/12 9:47    John    A

Respuesta1

SI entiendo lo que estás preguntando y esto está en Excel, podrías usar una "fórmula matricial".

Por ejemplo, si su conjunto de datos estaba en una hoja de trabajo en el rango A1:C5, podría usar esto en la columna "D":

{=INDIRECT("B" & MATCH(MAX(IF(C$1:C$5=C1,(A$1:A$5),)),A$1:A$5,0))}

Esta fórmula creará dinámicamente la referencia de celda que apuntará al nombre de usuario requerido al devolver el número de fila para la fila donde se encuentra la fecha máxima, pero solo para aquellas filas donde el valor del departamento coincide con el valor de esa fila en la columna "C". (la columna del departamento) y agregándolo al carácter de texto "B" (la columna que contiene los nombres de usuario), creando así la referencia completa de la celda "letra+número".

Tenga en cuenta que deberá ser una función de matriz, lo que significa que debe mantener presionado Ctrl+ Shift+ Enteral salir de la celda después de escribir la fórmula en lugar de simplemente ingresar como se haría normalmente. Cuando lo hagas bien, la fórmula quedará entre llaves como se muestra arriba. Si no hay llaves que envuelvan la fórmula, entonces no está configurada como una fórmula matricial y no funcionará correctamente.

Puede que haya una forma más sencilla o más elegante de hacer esto, pero si sólo necesitas una solución rápida y sucia, esta funcionará.

Si necesita más explicaciones, puedo proporcionarle más detalles.

Respuesta2

Volví y vi que nadie había publicado una solución VBA todavía. Pensé que pondría uno ahí.

'indexes of the values stored as an array in the collection object
  Private Const USERNAME As Integer = 0
  Private Const DATETIME As Integer = 1

'references to where the data is or should be in the workbook Public Enum DataColumns DateTimeStamp = 1 UName = 2 Department = 3 LastUpdater = 4 'The information we will be adding! End Enum

Sub Main() Dim lastUserByDept As Collection Set lastUserByDept = GetLastUpdater(2) AppendLastUserName 2, lastUserByDept End Sub

'//Builds a collection of department entries, and stores '//the last date along with the user tied to that date Private Function GetLastUpdater(dataStartRow As Long) As Collection Dim currRow As Integer: currRow = dataStartRow

Dim maxDatesByDept As Collection
Set maxDatesByDept = New Collection

Dim deptInfo As Variant
Do While Not IsEmpty(Cells(currRow, DataColumns.DateTimeStamp))
    Dim dept As String: dept = Cells(currRow, DataColumns.Department).Value
    If DeptExists(maxDatesByDept, dept) Then
        If Cells(currRow, DataColumns.DateTimeStamp).Value > maxDatesByDept.Item(dept)(DATETIME) Then
            deptInfo = Array(Cells(currRow, DataColumns.UName).Value, Cells(currRow, DataColumns.DateTimeStamp).Value)
            UpdateExistingEntry maxDatesByDept, deptInfo, Cells(currRow, DataColumns.Department)
        End If
    Else
        deptInfo = Array(Cells(currRow, DataColumns.UName).Value, Cells(currRow, DataColumns.DateTimeStamp).Value)
        maxDatesByDept.Add deptInfo, Cells(currRow, DataColumns.Department).Value
    End If

    currRow = currRow + 1
Loop

Set GetLastUpdater = maxDatesByDept
Set maxDatesByDept = Nothing

End Function

'//Since we are using the VBA collection object, there is no true '//test for if an element exists; the collection will just throw '//an error if you ask it for something it cannot find, so just '//trap the error and return false in that case, as it means no '//item was found in the list with that dept as it's key Private Function DeptExists(ByRef deptList As Collection, dept As String) As Boolean On Error GoTo handler deptList.Item dept DeptExists = True Exit Function handler: Err.Clear DeptExists = False End Function

'//Updates an existing entry in our collection of dept users. '//Note: this implementation allows for the trapping of failed attempts '//but is not used in this version to keep it as straight-forward as '//possible - If it was important to know when such attempts failed, you '//could trap on the return value of this method and take the appropriate '//action. Private Function UpdateExistingEntry(ByRef deptList As Collection, ByVal deptInfo As Variant, ByVal dept As String) As Boolean On Error GoTo handler

If DeptExists(deptList, dept) Then
    deptList.Remove dept
    deptList.Add deptInfo, dept
    UpdateExistingEntry = True
Else
    UpdateExistingEntry = False
End If
Exit Function

handler: Err.Clear UpdateExistingEntry = False End Function

'//Uses the created collection of dept, username to add the '//required username to the column Private Sub AppendLastUserName(dataStartRow As Long, deptListing As Collection) Dim currRow As Integer: currRow = dataStartRow Do While Not IsEmpty(Cells(currRow, DataColumns.DateTimeStamp)) Dim currDept As String: currDept = Cells(currRow, DataColumns.Department) Cells(currRow, DataColumns.LastUpdater).Value = deptListing(currDept)(USERNAME) currRow = currRow + 1 Loop End Sub

Este código colocará el nombre de usuario de la última persona que actualizó el sistema dentro del contexto del departamento.

Tenga en cuenta que se suponen algunas cosas, como las ubicaciones de las columnas; Se utiliza una enumeración para hacer referencia a las columnas relevantes, por lo que puede señalarles los índices de columna adecuados si difieren del ejemplo y todo debería funcionar como se esperaba. También se supone que la columna que contiene la marca de fecha no tiene espacios y siempre es una fecha.

Copie y pegue todo el conjunto de código en un solo módulo en Excel y funcionará bien.

información relacionada