Ayuda para ordenar filas

Buen dia, mi objetivo es ordenar una tabla, la primer columna es la columna de estado, puede ser pendiente, en proceso o terminado. Solo quiero ordenar las filas automáticamente cada ves que esa columna cambie. Mandando hacia arriba las pendientes, luego las en proceso bajo las pendientes y por eliminación quedaran las terminadas abajo. Me gustaría saber como funcionaria el método que se me ocurrió, que es buscar la palabra y si la encuentra mandar a insertar esa fila en la antes de la fila 2, luego iba a encontrar la ultima fila con la palabra pendiente y bajo esa iba a insertar todas las que dijeran procesando. También me gustaría saber como se hace (me imagino que en muchos menos pasos) utilizando un comando sort que he visto por ahi.
Lo que había pensado seria algo asi: pero da error
Private Sub Worksheet_Change(ByVal Target As Range)
Dim cnt As Integer cnt = 1
n = 1
While n = 1
cnt = cnt + 1
If Cells(cnt, 1) = "" Then
n = 0
End If
If Cells(cnt, 1) = "Procesando" Then
Rows("cnt:cnt").Select Selection.Cut ACA DA EL ERROR Rows("2:2").Select Selection.Insert Shift:=xlDown
cnt = cnt - 1
End If
Wend
End Sub

2 Respuestas

Respuesta
1

Me temo que tu código tiene varios errores sintácticos y alguno semántico que hacen imposible que funcione. Por ejemplo, no te debe funcionar

Rows("cnt:cnt").Select

porque "cnt:cnt" es un string. En su lugar es:

Rows(cnt & ":" & cnt).Select

Aun así tienes que tener en cuenta que al mover filas se producen eventos que modifican la hoja y por tanto la macro vuelve a ejecutarse desde el inicio y así infinitamente mientras haya cualquier cambio. Hay que desactivar los eventos una vez dentro y dejarlos activos antes de salir.

Si me permites un consejo es mejor dejar en el código de la hoja solo la llamada a la macro junto con la desactivación de eventos y en un módulo el cuerpo de la función. Esto da mas flexibilidad a la hora de hacer las cosas. Sería algo como:

Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Call Ordena
Application.EnableEvents = True
End Sub

Y para el módulo un código que funcione:

Sub Ordena()
Dim i As Integer
Dim maxi As Integer
Dim mini As Integer
maxi = Range("A6500").End(xlUp).Row
i = maxi
mini = 3
While i >= mini
 If Cells(i, 1) = "Procesando" Then
 Rows(i & ":" & i).Select
 Selection.Cut
 Rows("2:2").Select
 Selection.Insert Shift:=xlDown
 mini = mini + 1
 Else 'paso a la siguiente fila
 i = i - 1
 End If
Wend
i = 3
While i < maxi
 If Cells(i, 1) = "Terminado" Then
 Rows(i & ":" & i).Select
 Selection.Cut
 Rows(maxi + 1 & ":" & maxi + 1).Select
 Selection.Insert Shift:=xlUp
 maxi = maxi - 1
 Else 'paso a la anterior fila
 i = i + 1
 End If
Wend
End Sub

Aunque un código que hace lo mismo en un paso, basado en la order sort, como bien decías sería:

Sub OrdenaV2()
Columns("A:A").Select
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add Key:=Range("A1"), _
 SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Sheet1").Sort
 .SetRange Range("A2", Range("B2").End(xlDown))
 .Header = xlNo
 .MatchCase = False
 .Orientation = xlTopToBottom
 .SortMethod = xlPinYin
 .Apply
End With
End Sub

Este código asume que los campos para ordenar están en la columna A y el rango a ordenar son las filas rellenas de las columnas A y B. Seguramente tendrás que adaptarlo a tu modelo.

Por último, mira a ver si realmente necesitas que la macro funcione con cada cambio en la hoja por mínimo que sea. Tal vez es mejor asociar la macro a un botón o una combinación de teclas y ejecutarla cuando sea necesario solo. Una forma de no olvidarlo es cambiar los colores de los estados con el formato condicional. Asi rápidamente vas a notar una palabra de un color rodeada de palabras de diferente color y podrás ver que has de correr la macro que ordena.

De echo la columna A me da el estado, tiene un desplegable que solo deja 3 opciones. pendiente, en proceso y terminado. quiero que la macro se ejecute cuando el contenido de la celda cambie pero solo la de la columna A. Digamos que lleno los campos y al final le cambio de en proceso a "terminado" la macro debería idealmente solo pasar esta fila al final. si creo una nueva fila y le pongo que esta pendiente. debería automáticamente mandarla hacia arriba y si la cambio a en proceso dejarla justo debajo del ultimo "pendiente".

la macro mas eficiente quizá seria trabajar con la fila que cambia pero siento que seria mas larga, por eso he dejado que ordene todo cada vez que cambia, si me gustaría saber como restringir a que funcione cuando cambia la columna A. no se que pensás de hacerlo que unicamente trabaje con la fila que ha cambiado.

Se puede hacer de las dos maneras, bien con el sort como antes, bien fijádose en la fila que cambia. Como de algún modo siempre tiene que estar ordenado, no es problemático dejarlo con el sort.

Para que el evento salte solo cuando por ejemplo cambia la columna A, debe quedar así:

Private Sub worksheet_change(ByVal target As Range)
Dim r As Range
Application.EnableEvents = False
Set r = Range("A:A")
If Not Intersect(target, r) Is Nothing Then 'cambio en la celda que busco
Call Ordena
End If
Application.EnableEvents = True
End Sub

Muchas gracias, me ha sido muy útil ya llevaba ratos buscando una solución efectiva.

Saludos desde El Salvador, centroamérica.

Respuesta
1

Pero en tu código también lo tienes en la misma linea tres instrucciones distintas, ¿o ha sido al pegar?

Debería ser asi:

Private Sub Worksheet_Change(ByVal Target As Range)
Dim cnt As Integer cnt = 1
n = 1
While n = 1
cnt = cnt + 1
If Cells(cnt, 1) = "" Then
n = 0
End If
If Cells(cnt, 1) = "Procesando" Then
Rows("cnt:cnt").Select

Selection.Cut

Rows("2:2").Select

Selection.Insert Shift:=xlDown
cnt = cnt - 1
End If
Wend
End Sub

Ha sido el copiar pegar

Dado que el orden de pendiente, en proceso y terminado te coincide con un orden alfabético descendiente prueba haber si te vale con este breve código, también podría añadir otras keys de ordenación, como por ejemplo la fecha, aparte de la alfabética.

Excel esta lleno de instrucciones para ordenar los registros, sort, filter o autofilter... hacerlo "a mano" con el código que planteas no es muy lógico y sobretodo poco útil, pues podría funcionar bien para pocos registros, pero para listas muy largas retrasaría muchísimo la ejecución del código, hasta el punto de parecer que se ha bloqueado excel, es mejor investigar los filtros y las instrucciones de ordenación.

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 1 Then
Range( "A1" , "B" & Range("A1").End(xlDown).Row).Sort Key1:=Me.Range("A1"), Order1:=xlAscending
End If
End Sub

Yo he puesto la columna B, porque desconozco cuantas columnas tienes con datos, tu deberías cambiar la columna por la última que contuviera datos.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas