Hojas de cálculo en Excel - página principal

Determinar las cabeceras de una tabla donde tenemos los valores buscados

En el artículo anterior, vimos un ejemplo un poco rebuscado, para determinar en qué columnas (A, B, C…) se encontraban una serie de valores que teníamos en una tabla. La utilidad de ese ejercicio era poca, para qué negarlo :-( pero fue un reto interesante, para saber hasta qué punto Excel puede convertirse en una herramienta a medida, en la que podemos implementar funciones que no vienen de forma nativa dentro de la aplicación.

Ahora veremos algo más interesante, y que probablemente alguna vez hayáis necesitado, y si no ha sido así, seguramente en alguna ocasión necesitaréis. Se trata de obtener los rótulos o cabeceras de una tabla, donde tenemos los valores que estamos buscando. Como siempre, lo veremos con un sencillo ejemplo. Imaginemos que tenemos tres zonas donde nuestra empresa vende: la zona A, la zona B, y la zona C. Las ventas las tenemos divididas en meses, de enero a diciembre, y pretendemos determinar qué mes es aquel que tiene las ventas máximas en cada zona. La tabla sería la siguiente:


Si nos fijamos bien, las ventas máximas de la zona A, son 78, y se producen en el mes de octubre. Pues precisamente eso, obtener el mes de octubre, es lo que pretendemos conseguir que nos determine Excel.

Como bien sabéis, obtener la cifra máxima de ventas para la zona A, sería tan sencillo, como poner esta fórmula:

=MAX(C5:N5)

Pero la pregunta es: ¿cómo hacemos para que Excel nos diga que ese valor máximo que obtenemos en la zona A, y que corresponde a unas ventas de 78, se producen en el mes de octubre (OCT)?. Pues de una forma bastante sencilla. Solo tendremos que utilizar la función MAX, para determinar el valor máximo de ventas.

También utilizaremos la función COINCIDIR que nos determinará el número de columna en la que tenemos el valor máximo, teniendo en cuenta que el número de la columna se determina en función del rango que escojamos, y tomando como columna inicial, aquella que corresponda a la primera celda del rango. ¿Esto último parece complicado?. No, no lo es. Si te digo que escogemos como rango de la zona A, el que va desde C5 hasta N5, la columna C sería la primera, y la columna N sería la duodécima. Con esta función, obtendremos que la columna cuyas ventas son máximas en la zona A, se corresponde con la número diez.

Y por último, necesitaremos convertir esa columna número diez, en la cabecera o rótulo correspondiente de la tabla, es decir, en OCT (mes de octubre). Para ello, nos bastará con utilizar la función INDICE.

Sería algo tan sencillo, como aplicar esta fórmula, para determinar el mes en el que se producen las ventas máximas de la zona A:

=INDICE(C4:N4;COINCIDIR(MAX(C5:N5);C5:N5;0))

Para obtener lo mismo de la zona B, sería esto:

=INDICE(C4:N4;COINCIDIR(MAX(C6:N6);C6:N6;0))

Y en la zona C, las ventas máximas se producen en el mes que nos devuelve como resultado esta fórmula:

=INDICE(C4:N4;COINCIDIR(MAX(C7:N7);C7:N7;0))

Y en esta imagen, podéis ver los resultados:


Desde aquí, podéis descargar el libro de Excel, con el ejemplo que hemos visto en este artículo.



¿En qué columnas tenemos los datos que buscamos?

En esta ocasión vamos a explicar, a través de una función personalizada, es decir, a través de una función no implementada en el propio Excel, sino que nosotros mismos vamos a programar, cómo conseguir descubrir en qué columnas se encuentra un valor que buscamos dentro de un rango de celdas.

Quizás leyendo el párrafo anterior, no os quede muy claro que es lo que queremos obtener, pero como siempre, vamos a hacerlo lo más ameno posible, explicándolo de una forma sencilla, para que sea más inteligible.

Concretamente, vamos a hacer algo como esto: Imaginemos que tenemos una tabla de Excel, donde hay diferentes valores, ya sean numéricos, alfanuméricos, o simplemente caracteres de texto. Lo que pretendemos, es buscar un valor determinado en esa tabla, para saber en qué columnas se encuentra. Veámoslo con una imagen:


Como veis en esa imagen, hay una serie de vendedores, con sus ventas mensuales, un total anual, y una desviación con respecto a las ventas medias por vendedor. Vamos a complicarnos la vida, y lo que vamos a buscar no son los meses en los que encontremos determinado valor, sino la columna de Excel donde estos se encuentran.

Veámoslo con un ejemplo: Supongamos que queremos buscar en qué columnas tenemos el valor 6.000,00, para el vendedor llamado Pedro. Si os fijáis en la tabla anterior, podemos localizar ese valor en el mes de septiembre, que corresponde a la columna K. Esto último es lo que pretendemos localizar.


Para hacerlo más complicado, y como es probable que el valor buscado no coincida con ninguno de la tabla (por ejemplo, el vendedor Rafael no tiene ventas por importe de 6.000,00), vamos a buscar también aquellas columnas que tengan el valor buscado o uno superior (que se cumpla cualquiera de esas dos condiciones), y también aquellas columnas que tengan un valor inferior. Si queréis, podéis adaptar vosotros este ejercicio, para buscar las columnas cuyos valores que sean iguales o inferiores (que se cumpla cualquiera de esas dos condiciones), o bien, buscar las columnas cuyos valores sean superiores al valor buscado, pues es muy sencillo hacerlo, con los pasos que os indico a lo largo de este artículo.

Vamos al lío… Vamos a construir nuestra función personalizada, para lo cual, en un módulo VBA, copiaremos esto, que nos servirá para localizar las columnas que contengan el valor exacto al valor que busquemos:

Function Localizar(rango As Range, valor As Variant)
'fichamos la celda donde están los datos
'inicial y final (el rango)

mi_rango = rango.Address
'separamos los datos inicial y final
coordenadas = Split(mi_rango, ":")

inicio = coordenadas(0)
fin = coordenadas(1)
'pasamos a una variable la dirección de la celda inicial
celda = Range(inicio).Address
'para todo el rango de datos...
For i = 0 To Range(fin).Column - Range(inicio).Column
     'Comprobamos el valor introducido
     If Range(celda) = valor Then
         columna = columna & " " & Range(celda).Address
         'eliminamos el signo de $ de referencia absoluta
         columna = Replace(columna, "$", "")
     End If
     'pasamos a la siguiente columna
     celda = Range(celda).Offset(0, 1).Address
'seguimos con el bucle
Next
'Si no existe el dato en ninguna columna
If columna = 0 Then columna = " No existe"
'eliminamos los números de la fila
numeros = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
For j = 0 To UBound(numeros)
     columna = Replace(columna, numeros(j), "")
Next
'asignamos a la función, el dato del contador
'eliminando previamente el primer espacio vacío
Localizar = Mid(columna, 2)
End Function

Vale, esto está muy bien, pero ¿cómo se utiliza esta función?. Pues así:

=localizar(rango_de_celdas_donde_buscaremos;valor_a_buscar)

Veámoslo con otro ejemplo:


En la tabla anterior, podemos ver que estamos buscando el valor 6.000,00 en toda la tabla que va, del rango de celdas C7, hasta la celda N12, pero lo hemos separado por vendedores, por lo que en el caso por ejemplo del vendedor Rafael, lo que haremos será buscar el valor 6.000,00 en el rango que va de C7 a N7. Para ello, la fórmula que hemos puesto en la celda C17 es esta:

=localizar(C7:N7;$D$3)

En este caso, como vemos, no hay ventas por valor de 6.000,00, aunque sí las hay por valores superiores e inferiores. Si lo que queremos es obtener las columnas donde haya valores superiores o iguales a 6.000,00, entonces crearemos otra función personalizada a la que llamaremos "localizarMasOIgual", donde copiaremos el código que os puse anteriormente, cambiando estas líneas que os añado a continuación.

Cambiaremos esta línea del código (ojo, que tenemos que llamar a esta nueva función con otro nombre, y yo he elegido el de "localizarMasOIgual"):

If Range(celda) = valor Then

Por esta otra:

If Range(celda) >= valor Then

Y también cambiaremos esta línea:

localizar = Mid(columna, 2)

Por esta otra:

localizarMasOIgual = Mid(columna, 2)

De esta forma, ya tendremos nuestra nueva función creada, donde buscaremos las columnas donde tengamos un valor igual o superior al buscado. Este será el resultado, después de aplicar la nueva fórmula, al rango de datos donde buscaremos las ventas superiores o iguales a 6.000,00:


En el caso de buscar las columnas con valores inferiores al valor buscado (en nuestro ejemplo, ventas inferiores a 6.000,00), crearemos una nueva función a la que llamaremos "localizarMenos". En esta nueva función, cambiaremos el código inicial que os puse de dos líneas, concretamente cambiaremos esta línea:

If Range(celda) = valor Then

Por esta otra:

If Range(celda) <= valor Then

Y también cambiaremos esta línea:

localizar = Mid(columna, 2)

Por esta otra:

localizarMenos = Mid(columna, 2)

Y el resultado después de aplicar la nueva función, será este, si buscamos las columnas donde tenemos ventas de cada vendedor, inferiores a 6.000,00:


Como veis, es muy sencillo adaptar la función inicial, a vuestras necesidades. Si queréis, podéis probar a obtener las columnas donde se encuentran valores superiores al valor buscado. En nuestro ejemplo hemos aplicado la función "localizarMasOIgual", pero nos busca los valores superiores o iguales al valor buscado, y no solo los valores superiores, como os sugiero que hagáis. También podéis crear una función más, para localizar las columnas donde hay valores menores o iguales al valor buscado. En nuestro ejemplo hemos aplicado la función "localizarMenos", pero nos busca solo los valores inferiores al valor buscado.

Desde aquí, podéis descargar el libro de Excel, con el ejemplo que hemos visto en este artículo, para que lo analicéis, lo probéis, y veáis si esta utilidad tiene alguna funcionalidad en vuestra vida diaria, o simplemente os parece otro interesante ejemplo más de cómo crear funciones personalizadas en Excel.



Obtener un consolidado, extrayendo los datos de diferentes ficheros

Hace poco me preguntaba una amiga, si era posible obtener en un fichero único de Excel, una serie de registros procedentes de otros ficheros, de los cuales desconocemos, un montón de cosas, incluido el propio nombre de estos ficheros. Es decir, se trataba de obtener en ese fichero único de Excel, los registros de forma concatenada (o agregada, unos detrás de los otros), de una serie de archivos, de los que desconocemos tanto su número, como su nombre, e incluso, la subcarpeta en la que están estos propios ficheros que serán la fuente desde la que vamos a obtener la información.

Mi respuesta fue: “Ufffffff, no entiendo nada de lo que me planteas. Hazme un ejemplo de lo que necesitas, que soy muy torpe.”

Su explicación fue más o menos así: Imagina que tengo una carpeta donde tengo alojadas una serie de subcarpetas (desconozco su número), y dentro de estas subcarpetas hay una serie de ficheros (desconozco tanto el número de ficheros como el nombre que tienen los mismos), …pues bien, lo que quiero, es que mire en todas esas subcarpetas, y en todos los ficheros que haya dentro, y como todos tienen un esquema similar, que coja esos datos, y me los ponga en un único fichero de Excel, colocando cada bloque de registros de cada fichero, uno detrás de otro, dentro de este único fichero que recoge la información.

Y ante esa respuesta, yo pensé: “¿tú lo que quieres es trabajar poco, y que Excel lo haga todo, einghhhh?”. Pues sí, no estaba equivocado, quería que Excel le hiciese el trabajo tedioso, recopilar los datos, sin tener que abrir cada fichero de Excel, y hacer un “copypaste” en el fichero de destino, que ella ya se encargaría de analizar toda esa información.
Vamos, que la idea era pasar de esto:

A esto otro:

Pues nada, me puse manos a la obra, y tras un buen rato de de análisis, trabajo y depuración de código, conseguimos un macro que haría todo eso en un abrir y cerrar de ojos.
La idea parte de esto que podéis ver en esta imagen, que contiene una serie de carpetas, que a su vez están alojadas en una carpeta que será la que dediquemos a albergar los ficheros desde los que obtendremos la información:

Y dentro de cada carpeta, tenemos diferentes ficheros (en cada carpeta podemos tener un número diferente de ficheros), y con diferentes nombres (aunque puede que haya varios ficheros con el mismo nombre, pero en carpetas diferentes, claro). Este sería un ejemplo de lo que tenemos en la carpeta llamada "Carpeta 4":

Como podéis ver se trata de ficheros de Excel, que en mi caso he hecho con la versión 2003, para que los usuarios con una versión antigua de esta popular hoja de cálculo, vean que no van a tener ningún problema a la hora de utilizar el macro que recopilará la información de los diferentes ficheros. Evidentemente aquellos usuarios que utilicen versiones posteriores de Excel (2007, 2010, 2013, o las que estén por llegar), no van a tener el más mínimo problema, pues nos da igual el nombre que tenga el fichero, o incluso su extensión, pues solo necesitamos quesean ficheros de Excel.
Si abrimos por ejemplo el fichero llamado “Usuarios zona A.xls”, nos encontramos con esto (la estructura o registros de todos los ficheros es similar, aunque los datos contenidos evidentemente no, pues cada fichero tiene datos diferentes, los cuales queremos extraer, para pegarlos de forma concatenada, en un único fichero que nos servirá de agregado para poder analizar los datos, a partir de él):

Algo muy importante, a lo que tengo que hacer mención es que:

  • Da igual el nombre que tengan nuestras carpetas, y el nombre que tengan los ficheros que cuelguen de cada carpeta, y no tienen por qué tener un nombre correlativo. Incluso pueden tener nombre absurdos :-)
  • Da igual tanto el número de carpetas, y de ficheros que cuelguen de cada carpeta, aunque si tenemos más de la cuenta, puede que Excel no pueda procesar tanta información y se nos cuelgue la aplicación (no he probado el límite en el cual se cuelga, porque no soy masoquista).
  • Los datos los obtendremos de la primera hoja de cada uno de los libros.
  • Los datos de los libros deben tener todos la misma estructura (mismo número de campos), pues consolidaremos peras con peras, y no peras con manzanas. No obstante, el número de registros de cada fichero puede ser distinto (en el ejemplo de este artículo trabajamos con registros diferentes en cada fichero, para que veáis como funciona).
Vamos allá. Para hacer todo esto, lo primero que haremos, será crear un fichero que llamaremos “Consolidado.xls”, que contendrá dos hojas. La primera será donde consolidaremos los datos (hemos puesto los encabezados de fila, para ahorrarnos el trabajo en el macro). A esta primera hoja la hemos llamado “Consolidado”. La segunda hoja llamada “Ficheros”, contendrá nos nombres de las carpetas en una columna, y en la adyacente tendremos los archivos que contiene cada carpeta, pero claro, esto no lo haremos manualmente, porque sino no tendría sentido crear un macro. Esta segunda hoja también nos la “rellenará” nuestro macro, pues él solito obtendrá los nombres de las carpetas, y los ficheros que contiene cada una de ellas.

Es decir, en la hoja “Consolidado” de nuestro libro tendremos esta plantilla:

Y en la “Ficheros” tendremos esto (ojo, que esto que veis, es tras la ejecución del macro, pues ha recorrido cada carpeta y cada fichero “fichando” el nombre de todo lo que encuentra dentro, así que para evitar problemas, trabajad solo con ficheros Excel, y no los mezcléis con ficheros Word, o con imágenes, por ejemplo):

Bueno, pues para hacer todo esto, tan solo deberemos copiar y pegar este macro, en un módulo:

Sub Consolidado()
'--------------------------------------------------------
'Lo primero que haremos, será recorrer los directorios
'seleccionando los ficheros que haya en cada uno de ellos
'--------------------------------------------------------
'Si hay errores, que continúe

On Error Resume Next
'seleccionamos la hoja1
Hoja1.Select
'Seleccionamos el botón cuyo nombre queramos cambiar
ActiveSheet.Shapes("Botón 1").Select
'le cambiamos el nombre, y lo ponemos en rojo
Selection.Characters.Text = "Espera unos segundos..."
With Selection.Font
.ColorIndex = 3
End With
'Ocultamos el procedimiento
Application.ScreenUpdating = False
'borramos todo lo que haya de datos anteriores en la Hoja1
Range("A6").Select
If ActiveCell <> "" Then
    Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select
    Selection.EntireRow.Delete
    Selection.ClearContents
    Selection.ClearFormats
End If
'Nos situamos en la hoja 2
Windows(ThisWorkbook.Name).Activate
Hoja2.Select
'borramos lo que haya de otras veces
Range("A2").Select
If ActiveCell <> "" Then
    Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select
    Selection.EntireRow.Delete
End If
'Creamos el objeto FileSystemObject
Set Fso = CreateObject("Scripting.FileSystemObject")
'Informamos de la ruta de donde vamos a obtener
'los ficheros, en este caso, el mismo directorio
'donde tengamos grabado este fichero con el macro
ruta = ActiveWorkbook.Path
'definimos dos variables que necesitaremos,
'para recuperar el nombre de la carpeta, y
'los subdirectorios y ficheros que haya dentro
Set directorio = Fso.GetFolder(ruta)
Set Subdirectorios = directorio.SubFolders
Set ficheros = directorio.Files
'escribimos un encabezado en la celda A2
Range("A2").Select
'escribimos los subdirectorios
For Each Subdirectorio In Subdirectorios
Hoja2.Select
'escribimos el nombre del subdirectorio
ActiveCell = Subdirectorio.Name
    'entramos en el subdirectorio
    Set directorio = Fso.GetFolder(Subdirectorio)
    Set Subdirectorios = directorio.SubFolders
    Set ficheros = directorio.Files
    ActiveCell.Offset(0, 1).Select
    For Each Archivo In ficheros
    'escribimos el nombre del fichero
    ActiveCell = Archivo.Name
    'bajamos una fila
    ActiveCell.Offset(1, 0).Select
    Next
'bajamos una fila y volvemos una columna atrás
ActiveCell.Offset(1, -1).Select
Next
'Limpiamos los objetos
Set Fso = Nothing
Set directorio = Nothing
Set Subdirectorios = Nothing
Set ficheros = Nothing
'---------------------------------------------------------------
'Abrimos los ficheros uno a uno, y vamos copiando y escribiendo
'los datos en el fichero del consolidado en la hoja1 (no importa
'el nombre que tenga esta hoja)
'---------------------------------------------------------------
'abrimos las carpetas desde la 1 a la 50, para no hacer esto interminable
carpeta = Range("A2").Address
For i = 1 To 50
'nos situamos en la celda A2, de la hoja 2, que era donde estábamos,
'creando unas variables que nos serán de ayuda
fichero = Range(carpeta).Offset(0, 1)
j = 1
    Do While Not IsEmpty(fichero)
        Workbooks.Open Filename:=ruta & "\" & Range(carpeta) & "\" & fichero
        'copiamos los datos que tenga desde A2 hasta el final
        Range("A2").Select
        Range(Selection, ActiveCell.SpecialCells(xlLastCell)).Select
        Selection.Copy
        'los pegamos en nuestro libro
        Windows(ThisWorkbook.Name).Activate
        Hoja1.Select
        If Range("A6") = "" Then
            Range("A6").Select
        Else
            Range("A6").Select
            Selection.End(xlDown).Select
            ActiveCell.Offset(1, 0).Select
        End If
        ActiveSheet.Paste
        Application.CutCopyMode = False
        'nos situamos al final de la lista consolidada
        Selection.End(xlDown).Select
        'bajamos una celda
        ActiveCell.Offset(1, 0).Select
        'cerramos el libro
        Workbooks("" & fichero & "").Close savechanges:=False
        'volvemos a la hoja2
        Hoja2.Select
        'creamos una variable para ir bajando a los ficheros
        fichero = Range(carpeta).Offset(j, 1)
        j = j + 1
        Loop
Range(carpeta).Select
Selection.End(xlDown).Select
carpeta = ActiveCell.Address
Next
'volvemos a la Hoja2
Hoja2.Select
Range("A2").Select
'volvemos a la Hoja1
Hoja1.Select
'Seleccionamos el botón
ActiveSheet.Shapes("Botón 1").Select
'le cambiamos el nombre al botón, poniéndole el que tenía
'inicialmente y lo ponemos en negro
Selection.Characters.Text = "Consolidar"
With Selection.Font
.ColorIndex = xlAutomatic
End With
Range("A6").Select
'Mostramos el procedimiento
Application.ScreenUpdating = True
'mostramos un mensaje al finalizar
CreateObject("wscript.shell").Popup _
" Ya hemos finalizado. ¿Ves como tardaría poco?. " + _
Chr(13) + " Los datos han sido consolidados, y demasiado sin esfuerzo ;-) ", _
4, " Consolidación completada"
End Sub

Cuando ejecutéis el macro, lo primero que hace, es eliminar los datos que haya previamente (si es que los hay). Luego, simplemente consolida los datos de los diferentes ficheros. Os dejo que lo probéis, y veáis que he puesto cada bloque de datos de diferentes colores en los ficheros de origen, para que se vea claramente que en el consolidado se “pegan” de la misma forma, es decir, manteniendo su formato (en este caso el color de origen, para que se vean bien los datos “copypasetados”).

Descomprimid el fichero comprimido de este enlace, en una carpeta, y probadlo. Veréis como el contenido de cada uno de los ficheros, de todas y cada una de las carpetas, pasa a formar parte de un único fichero, que es este desde el que ejecutamos el macro (Consolidado.xls).