miércoles, 3 de septiembre de 2025

Modularización de consultas por medio de procedimientos almacenados en SQL Server

En SQL Server un procedimiento almacenado es un grupo de una o más instrucciones de Transact-SQL (Lenguaje de programación). Estos procedimientos aceptan parámetros de entrada y devuelven múltiples valores en forma de parámetros de salida al programa que llama al procedimiento, además contienen instrucciones de programación que realizan operaciones en la base de datos. También, estos procedimientos devuelven un valor de estado al programa que llamo al procedimiento para indicar éxito o fracaso (y el motivo del fracaso).

Gracias al control de flujo que ofrece SQL Server es que podemos usar los procedimientos almacenados. Como se describió, Transact-SQL tiene diversas instrucciones que nos permiten emplear estructuras de control tal como en los lenguajes de programación, es decir, podemos usar construcciones del lenguaje para modificar el flujo de ejecución de las instrucciones de un programa.

Los procedimientos almacenados tienen la ventaja de que permiten modularizar soluciones de software al encapsular el código en unidades manejables y con ello facilitar su reutilización. Además, con el uso de procedimientos almacenados los comandos de estos se ejecutan como un único lote de código, esto puede reducir significativamente el tráfico de red entre el servidor y el cliente, ya que solo se envía la llamada a través de la red para ejecutar un procedimiento determinado. Sin la encapsulación de código que proporciona un procedimiento, cada línea de código tendría que atravesar la red.

Creación de procedimientos almacenados
La sentencia CREATE PROCEDURE es la que nos permite la creación y persistencia de bloques de código, además, cuando se usa esta sentencia, el procedimiento se guarda en la carpeta Databases > NombreBaseDeDatos > Programmability > Stored procedures, aquí es donde podemos encontrar todos los bloques de código que se han guardado en la propia base de datos. La carpeta de procedimientos almacenados se muestra en la siguiente imagen.


Como ejemplo de código, vamos a suponer que tenemos una tabla de productos que tiene un campo cantidad y que deseamos actualizar los valores de este campo, para esto, podemos crear un procedimiento almacenado que nos va permitir llamarlo cada vez que lo necesitemos sin tener que volver a escribir el código en su interior. El código es el que se muestra en seguida.

CREATE PROCEDURE p_actualiza_stock
AS
BEGIN
    IF EXISTS(SELECT * FROM productos
            WHERE cantidad = 0)
        UPDATE 
            productos SET cantidad = 20
        WHERE 
            cantidad <= 5;
END

Con el código anterior se guarda el procedimiento y ahora solo falta ejecutarlo por medio de la sentencia EXEC, esto se muestra a continuación.

EXECUTE p_actualiza_stock;

Es importante mencionar que cada vez que un procedimiento se guarda y modifica en la base de datos, será necesario ejecutarlo o mandarlo a llamar por medio de la sentencia EXEC.

Actualización de procedimientos almacenados
Para actualizar o modificar un procedimiento que ya guardamos previamente, tenemos que usar la sentencia ALTER PROCEDURE. Como ejemplo, podemos modificar el procedimiento que describimos previamente, en este caso podemos agregar 10 unidades más a cada artículo que tenga 20 elementos, entonces el código es el siguiente.

ALTER PROCEDURE p_actualiza_stock
AS
BEGIN
    IF EXISTS(SELECT * FROM productos
            WHERE cantidad = 10)
        UPDATE 
            productos SET cantidad = 30
        WHERE 
            cantidad = 20;
END

De igual manera, la instrucción ALTER modifica y guarda el procedimiento en la base de datos en cuestión.

Borrar procedimientos almacenados
Para borrar procedimientos almacenados tenemos que usar la instrucción DROP PROCEDURE, entonces para borrar el procedimiento con el que hemos estado trabajando tenemos que usar el código que muestra a continuación.

DROP PROCEDURE p_actualiza_stock;

Con esto, el módulo de actualización de stock ya no estará disponible en la carpeta Stored Procedures de la base de datos.

Parámetros de entrada en procedimientos almacenados
Para usar parámetros o variables al interior de una procedimiento almacenado tenemos que declarar las variables antes del propio código de ejecución, es decir, antes de la clausula AS, recordemos que la declaración de variables tiene la sintaxis @nombreVar TipoDeDato = valor, además, si se usan varias variables tenemos que separarlas por comas. En el siguiente ejemplo se muestra un procedimiento almacenado que nos permite buscar un producto con determinados valores en cada campo. En este caso la tabla de productos tiene los campos nombre, precio y cantidad (existencia) en su estructura.

CREATE OR ALTER PROCEDURE p_buscar_producto
@producto VARCHAR(40) = 'Microcontrolador',
@precioProducto SMALLMONEY = 29.99,
@existencia INT = 35
AS
SELECT * FROM productos
WHERE
    nombre = @producto AND
    precio = @precioProducto AND
    cantidad = @existencia;

En esta ocasión se uso la palabra reservada ALTER en el encabezado del procedimiento almacenado, con esto podemos crear y/o modificar un procedimiento en el mismo lugar sin la necesidad de realizar estas operaciones por separado.

Referencias
En los siguientes enlaces se puede obtener más detalles técnicos sobre las sentencias de código usadas en este artículo.

viernes, 29 de agosto de 2025

Proyecto de clínica de especialidades usando Microsoft Access

Este proyecto tiene como objetivo implementar una base de datos en Microsoft Access que será para una clínica de especialidades y tiene como finalidad llevar el control de citas de los diferentes médicos. La base de datos tiene tres tablas, Citas, Médicos y Pacientes, a continuación se describen los campos que contendrá cada tabla.
  • Médicos: idMedico, nombre, apellidoPaterno, especialidad
  • Pacientes: idPaciente, nombre, apellidoPaterno, apellidoMaterno, género, numeroDeExpediente, calleYNumero, colonia, codigoPostal, entidadFederativa, telefono, correoElectronico
  • Citas: idCita, idMedico, idPaciente, fechaCita, horaCita, costoCita, observaciones
El desarrollo de esta base de datos se describe a continuación.

Creación de tablas
La creación de las tablas se realizó por medio de lenguaje SQL. Es importante recordar que la ejecución de sentencias SQL se realiza por medio de la pestaña Crear, grupo Consultas, opción Diseño de consulta y después en la ventana de consulta tenemos que elegir Vista SQL por medio del uso de clic derecho. A continuación se muestran los códigos utilizados para crear cada una de estas tablas.

CREATE TABLE Medicos(
idMedico INTEGER,
nombre CHAR(40) NOT NULL,
apellidoPaterno CHAR(40) NOT NULL,
especialidad CHAR(40) NOT NULL,
CONSTRAINT PK_enlace_medico PRIMARY KEY (idMedico)
);

CREATE TABLE Pacientes(
idPaciente INTEGER,
nombre CHAR(40) NOT NULL,
apellidoPaterno CHAR(40) NOT NULL,
apellidoMaterno CHAR(40) NOT NULL,
sexo CHAR(20) NOT NULL,
numeroDeExpediente NOT NULL,
calleYNumero CHAR(40) NOT NULL,
colonia CHAR(40) NOT NULL,
codigoPostal CHAR(5) NOT NULL,
entidadFederativa CHAR(40) NOT NULL,
telefono CHAR(20),
correoElectronico CHAR(40),
CONSTRAINT PK_enlace_pacientes PRIMARY KEY (idPaciente)
);

CREATE TABLE Citas(
idCita INTEGER NOT NULL,
idMedico INTEGER NOT NULL,
idPaciente INTEGER NOT NULL,
fechaCita DATETIME NOT NULL,
horaCita CHAR(10) NOT NULL,
costoCita MONEY NOT NULL,
observaciones CHAR(80),
CONSTRAINT PK_enlace_citas PRIMARY KEY (idCita)
);

Configuración de relaciones entre tablas
El siguiente paso es establecer la relación entre estas tablas, para esto tenemos que hacer uso de las restricciones, esto se puede lograr por medio de las sentencia ALTER TABLE y CONSTRAINT. Las instrucciones usadas para lograr esto se muestran en seguida.

ALTER TABLE Citas ADD CONSTRAINT FK_citas_pacientes FOREIGN KEY (idPaciente) 
REFERENCES Pacientes(idPaciente);

ALTER TABLE Citas ADD CONSTRAINT FK_citas_medicos FOREIGN KEY (idMedico)
REFERENCES Medicos(idMedico);

Access genera un diagrama entidad-relación que resulta de la ejecución de las instrucciones anteriores, este se muestra en la siguiente imagen.


Desde luego, la creación de tablas, relaciones y el diagrama entidad-relación también se puede generar por medio del uso de la interfaz gráfica de usuario de Access.

Inserción de registros
Ya que se tiene la estructura de la base de datos entonces podemos proceder a realizar la inserción de registros en las tablas correspondientes, para ellos tenemos que hacer uso de la instrucción INSERT INTO pero se hará una excepción, es decir, se usarán las macros de VBA en Access para realizar la inserción de varios registros debido a que la ventana de consultas de este software solo permite insertar un registro a la vez pero por medio de las macros podemos introducir gran cantidad de registros usando una sola subrutina. Esta subrutina se muestra a continuación.

Sub conectarConDbActual()
    Dim conexionDB As New ADODB.Connection
    Set conexionDB = CurrentProject.Connection
    
    'Inserción de registros en tabla Medicos
    conexionDB.Execute ("INSERT INTO Medicos VALUES(1, 'Julio',         'Rodriguez', 'Cardiología')")
    conexionDB.Execute ("INSERT INTO Medicos VALUES(2, 'Pedro',         'Estrada', 'Neurología')")
    conexionDB.Execute ("INSERT INTO Medicos VALUES(3, 'Mariana',         'Hurtado', 'Dermatología')")
    conexionDB.Execute ("INSERT INTO Medicos VALUES(4, 'Luis',             'Fernández', 'Oncología')")
    conexionDB.Execute ("INSERT INTO Medicos VALUES(5, 'Sonia',         'Martínez', 'Radiología')")

    'Inserción de registros en tabla Pacientes
    conexionDB.Execute ("INSERT INTO Pacientes VALUES(1, 'Alberto',     'Ramírez', 'Camarena', 'Masculino', 10, 'Calle 3, No 9', 'Valle     de Bravo', '99502', 'CDMX', '0987640123',                            'alberto@micorreo.com')")
    conexionDB.Execute ("INSERT INTO Pacientes VALUES(2, 'Maria',         'Juarez', 'López', 'Femenino', 30, 'Calle 9, No 8', 'Valle de         Anáhuac', '88412', 'Estado de México', '8904321456',                 'maria@micorreo.com')")
    conexionDB.Execute ("INSERT INTO Pacientes VALUES(3, 'Adriana',     'Domínguez', 'Antulio', 'Femenino', 36, 'Calle 13, No 90',             'Héreoes', '89022', 'CDMX', '5589098901',                             'adriana@micorreo.com')")
    conexionDB.Execute ("INSERT INTO Pacientes VALUES(4, 'Fernando',     'Jiménez', 'Fernández', 'Masculino', 45, 'Calle 23, No 4',             'Laureles', '09789', 'CDMX', '550000000021',                         'fernando@micorreo.com')")
    conexionDB.Execute ("INSERT INTO Pacientes VALUES(5, 'Antonio',     'Perales', 'Ochoa', 'Masculino', 48, 'Calle 33, No 2', 'Cedros',     '09034', 'Estado de México', '0923567891',                             'kevin@micorreo.com')")
    
    'Inserción de registros en tabla Citas
    conexionDB.Execute ("INSERT INTO Citas VALUES(1, 1, 1, '2025-05-    25', '10:00', 70, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(2, 2, 1, '2025-06-    25', '13:00', 70, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(3, 1, 2, '2025-01-    25', '16:00', 80, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(4, 2, 2, '2025-02-    25', '09:00', 80, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(5, 1, 3, '2025-03-    25', '14:00', 90, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(6, 2, 3, '2025-04-    25', '15:00', 90, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(7, 1, 4, '2025-11-    25', '16:00', 100, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(8, 2, 4, '2025-12-    25', '15:00', 100, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(9, 1, 5, '2025-10-    25', '15:00', 50, 'Ninguna')")
    conexionDB.Execute ("INSERT INTO Citas VALUES(10, 2, 5, '2025-11-    25', '17:00', 50, 'Ninguna')")
End Sub

La siguiente imagen muestra los registros colocados en las tablas de este proyecto de Access (Clic en cada imagen para ampliarla).




Pruebas y resultados
Para probar la correcta estructuración de la base de datos podemos ejecutar algunas consultas multitabla que nos permitan observar las relaciones que fueron creadas, para esto se tiene la opción de usar uniones, específicamente se va usar INNER JOIN para obtener los datos comunes a dos o más tablas. Por ejemplo, vamos a realizar una consulta para obtener la fecha de la cita, la hora y el costa de la misma, también vamos a extraer el nombre del paciente de esa cita, su entidad federativa y el nombre del médico que va atender a ese paciente. El código para llevar a cabo esto es el siguiente.

SELECT 
    Citas.fechaCita, Citas.horaCita, Citas.costoCita, Pacientes.nombre, Pacientes.entidadFederativa, Medicos.nombre
FROM 
    (Citas
INNER JOIN 
    Pacientes ON Citas.idPaciente = Pacientes.idPaciente) 
INNER JOIN 
    Medicos ON Citas.idMedico = Medicos.idMedico;

El resultado (Vista de hoja de datos) que devuelve esta consulta se muestra en la siguiente imagen.


Otra consulta que puede ser muy útil es extraer todas las citas que tiene un médico junto con datos del paciente asociado, para esto podemos usar la clausula INNER JOIN y la clausula WHERE para definir la condición de extraer solo los datos de columnas de un id de médico específico. El código de esta consulta se muestra en seguida.

SELECT 
    Citas.fechaCita, Citas.horaCita, Medicos.nombre, Medicos.idMedico
FROM 
    Citas 
INNER JOIN 
    Medicos ON Citas.idMedico =  Medicos.idMedico
WHERE 
    Medicos.idMedico = 1;

Esta consulta devuelve la tabla de datos que se muestra en la siguiente imagen.


También podemos hacer uso de uniones de tipo LEFT JOIN para extraer todos los médicos o pacientes que no tienen ninguna cita pero que están presentes en la base de datos, esto puede ser útil para casos como contactar a clientes con los que no se ha tenido comunicación o que no han tenido la oportunidad de asistir a la clínica  y por tanto no tienen citas recientes en el sistema, o bien, puede se útil para asignar citas y pacientes a médicos que por el momento están más libres de tiempo. En seguida se proporcionan dos consultas del tipo descrito.

SELECT Pacientes.nombre, Pacientes.apellidoPaterno, Pacientes.telefono, Citas.idCita
FROM
    Pacientes
LEFT JOIN
    Citas ON Pacientes.idPaciente = Citas.idPaciente;

SELECT Medicos.nombre, Medicos.apellidoPaterno, Citas.idCita
FROM
    Medicos
LEFT JOIN
    Citas ON Medicos.idMedico = Citas.idMedico;

Los resultados de estas consultas se muestran en las siguientes imágenes.




En estas imágenes se puede ver que aquellos pacientes sin citas y médicos sin citas muestran una casilla vacía de id de citas, esto se debe a que LEFT JOIN devuelve los resultados propios de cada tabla (registros sin cita) y los comunes a ambas tablas (registros con cita).

Además, de las consultas multitabla que se usaron previamente, podemos usar RIGHT JOIN para traer todos los registros de la tabla de citas (definida como tabla derecha) junto con los registros coincidentes de la tabla de médicos o pacientes, en este caso, en el sistema todas las citas están asignadas, por tanto no se van a devolver resultados vacíos de parte de la tabla de citas. La consulta RIGHT JOIN se describe a continuación y contiene los id de cada cita pero también el nombre y apellido de cada paciente relacionado con esa cita.

SELECT citas.idCita, Pacientes.nombre, Pacientes.apellidoPaterno
FROM 
    Pacientes
RIGHT JOIN 
    Citas ON Pacientes.idPaciente = Citas.idPaciente;

El resultado devuelto por esta consulta se muestra a continuación.


Finalmente, la estructura del proyecto creada con los procesos anteriores se puede observar en la siguiente imagen, los objetos que están presentes son las tablas,  consultas y los módulos que contienen los códigos de VBA.

lunes, 25 de agosto de 2025

El modelo de objetos de Excel y su importancia para las macros

Microsoft Excel proporciona un modelo de objetos que es útil para obtener acceso a hojas de cálculo, rangos, tablas, gráficos, etc., esto es de relevancia porque podemos manipular tales objetos por medio de código de programación, en específico por medio del lenguaje VBA (Visual Basic for Applications), esto tiene el beneficio de poder personalizar la funcionalidad de las aplicaciones y proyectos creados con esta hoja de cálculo. Este modelo de objetos se describe a continuación.

  • Un Libro contiene una o varias Hojas de cálculo.
  • Una Hoja de cálculo contiene colecciones de aquellos objetos de datos presentes en la hoja individual y da acceso a las celdas en los objetos de Rango.
  • Un Rango representa un grupo de celdas adyacentes.
  • Los Rangos se usan para crear y colocar Tablas, Gráficos, Formas y otros objetos de visualización u organización de datos.
Objetos y colección de VBA
Un objeto representa un elemento de una aplicación, como una hoja de cálculo, una celda, un gráfico, un formulario o un informe, además, en Visual Basic, es necesario identificar un objeto para poder llamar a uno de sus métodos o cambiar el valor de sus propiedades .

Una colección es un objeto que contiene varios objetos y generalmente son objetos del mismo tipo. En Microsoft Excel, el objeto Workbooks contiene todos los objetos Workbook abiertos. En Visual Basic, la colección Forms contiene todos los objetos Form de una aplicación

Ahora, para poder acceder a estos objetos por medio de código VBA se van a mostrar diversos ejemplos.

Libros
El objeto Workbook representa un libro de Microsoft Excel, sin embargo puede ser de utilidad usar el objeto ActiveWorkbok que representa un objeto Workbook presente en la ventana activa o en uso. 

Los libros tienen varios métodos para operar con ellos, por ejemplo, podemos usar la propiedad Author para establecer un nombre de propiedad para un archivo, o bien, usamos el método Save para guardar los cambios, esto se muestra en los siguientes segmentos de código,

ActiveWorkbook.Author = "Samuel Ramirez"
ActiveWorkbook.Save

Hojas
En las macros de Excel podemos acceder a todas las hojas de un libro por medio del objeto Worksheets, como ejemplo, podemos asignar la primera hoja del libro a una variable Worksheet, cambiarle el nombre a la misma y también definir su orientación en vertical, esto se puede realizar con el siguiente código.

Dim hoja As Worksheet
Set hoja = Worksheets(1)
hoja.Name = "HojaProductos"
hoja.PageSetup.Orientation = xlPortrait

Rangos
Un rango es un grupo de celdas adyacentes en el libro. Los rangos tienen tres propiedades básicas: values, formulas y format. Estas propiedades obtienen o establecen los valores de celda, las fórmulas que se deben evaluar y el formato visual de las celdas. 

El objeto Range es el que representa una celda, una fila, una columna o un grupo de celdas adyacente en un libro.

Para ejemplificar lo descrito anteriormente podemos hacer uso de la siguiente tabla de Excel.


Para acceder a los valores contenidos en una celda o rango tenemos que usar la propiedad Value. En el siguiente código se accede al valor del rango A1, que en este caso también es una celda. Este ejemplo tiene una serie de nombres en la columna A, es por eso que se declara una variable de tipo String para almacenar el resultado obtenido de la llamada a la propiedad Value.

Dim valorCadena As String
valorCadena = Worksheets("HojaProductos").Range("A1").Value
MsgBox valorCadena

Para establecer una fórmula en, por ejemplo, la celda C1, podemos usar el siguiente código. Usamos la propiedad Formula para definir el método CONCATENAR en esa celda, en esta caso se unirá un nombre y un apellido.

Worksheets("HojaProductos").Range("C1").Formula = "=CONCATENAR(A1, "" "", B2)"

Además, para establecer el formato de un rango, podemos cambiar el tipo de letra, a saber, podemos establecer letra negritas en el rango de columnas de apellidos por medio de la propiedad Font.

Worksheets("HojaProductos").Range("B1:B7").Font.Bold = True

Celdas
En Visual Basic la propiedad Cells representa un objeto Range que contiene todas las celdas de la hoja de cálculo (no solo las celdas que están actualmente en uso). Las celdas usan la sintáxis Cells(Fila, columna) para acceder a elementos específicos. Como ejemplo, se puede acceder a la celda E2 y F2 para asignarles una valor por medio de la propiedad Value, además, podemos cambiar el color de cada una de estas celdas con la propiedad Interior.Color.

Worksheets("HojaProductos").Cells(2, 5).Value = 260
Worksheets("HojaProductos").Cells(2, 6).Value = "Camisas"
    
Worksheets("HojaProductos").Cells(2, 5).Interior.Color = _
        RGB(16, 40, 87)
Worksheets("HojaProductos").Cells(2, 6).Interior.Color = _
        RGB(56, 99, 33)

Tablas
En VBA se usa el objeto ListObject para representar una tabla en la hoja de cálculo. Además, tenemos disponible el objeto ListObjects que representa una colección de las tablas pertenecientes a una hoja. 

Como ejemplo, podemos acceder a todas las filas de la segunda tabla de la hoja de productos y luego podemos agregar una fila a esa tabla, para esto podemos usar el siguiente código.

Dim listaFilas As ListRows 
Set listaFilas = Worksheets("HojaProductos").ListObjects(2).ListRows
listaFilas.Add

En este caso ListObjects(2) representa la segunda tabla de la hoja, ListObjects(1) la primer tabla y así sucesivamente, además, ListRows es una entidad u objeto que representa todas las filas de la tabla y el método Add es el que nos permite agregar una nueva fila.

Gráficas
En Visual Basic el objeto ChartObject representa un gráfico incrustado en una hoja de cálculo, las propiedades y métodos de ChartObject controlan la apariencia y el tamaño del gráfico incrustado. El siguiente código muestra un ejemplo de configuración de una gráfica en una hoja de cálculo.

Dim grafica As ChartObject
Set grafica = _            Worksheets("HojaProductos").ChartObjects.Add(Left:=350, _
 Top:=100, Width:=280, Height:=200)
grafica.Chart.SetSourceData _                       Source:=Sheets("HojaProductos").Range("A10:C13"), _
 PlotBy:=xlColumns
grafica.Chart.SetElement (msoElementChartTitleAboveChart)
grafica.Chart.ChartTitle.Text = "Existencias"
grafica.Chart.HasLegend = False

En este código se declara una variable de tipo ChartObject para almacenar la gráfica que se desea incrustar en la hoja de cálculo, después se llama al método Add para establecer la esquina superior izquierda de la gráfica así como el ancho y alto de la misma, esta llamada al método devuelve un objeto que se guarda en la variable gráfica. También se llama al método SetSourceData que recibe los argumentos Source y PlotBy que definen la fuente de datos para dibujar la gráfica y el modo de representación de los datos, adicionalmente se ejecuta el método SetElement y se le provee el argumento msoElementChartTitleAboveChart para definir que se va mostrar el título que se encuentra en la parte superior del gráfico. Finalmente se usan las propiedades ChartTitle.Text para establecer el texto que se va colocar en el título previamente descrito y HasLegend con un valor de False para desactivar las etiquetas (estas etiquetas pueden ser las propiedades o características de los datos) que pueda tener el gráfico. La gráfica resultante se muestra en la siguiente imagen.


Instrucción Set
La instrucción Set que se uso previamente nos sirve para asignar un objeto (devuelto por una llamada a un método) a una variable de objeto (Declarada previamente por medio de la instrucción Dim). Es posible asignar una expresión de objeto o Nothing por medio de Set. En el siguiente código se realizan algunas asignaciones de objetos a variables de objetos.

Dim hoja As Worksheet
Set hoja = Worksheets(1)
Set objetoTest = Nothing

En este caso la variable de objeto llamada hoja es asignada con la primer hoja de calculo del libro y la variable objeto llamada objetoTest se asigna con Nothing. La palabra clave Nothing nos sirve para desasociar una variable de objeto de un objeto real y de esta manera usar esa variable de objeto para asignarle otro diferente.

Referencias
Para obtener más detalles técnicos sobre las propiedades y métodos del modelo de objetos de Excel se recomienda visitar los siguiente enlaces oficiales de Microsoft.

viernes, 18 de julio de 2025

Estructuras de repetición en macros de Excel

Las macros de Excel tienen a disposición del usuario un conjunto de estructuras de control de código que permiten ejecutar acciones repetitivas y con ello automatizar tareas y flujos de trabajo que así lo requieren, estas estructuras son las siguientes:

  • Do While... Loop
  • For... Next
  • For Each... Next
El ciclo Do While... Loop se usa para ejecutar un bloque de sentencias un número indefinido de veces. Las sentencias se repiten mientras una condición sea verdadera o hasta que se convierta en verdadera.

La estructura For...Next se utiliza para repetir un bloque de sentencias un número específico de veces. Este bucle utilizan una variable de contador cuyo valor aumenta o disminuye con cada repetición.

El ciclo For Each... Next repite un bloque de instrucciones para cada objeto de una colección o cada elemento de una matriz. Visual Basic hace uso de una variable cada vez que se ejecuta el bucle.

Ejemplos de aplicación
A continuación se describen una serie de ejemplos en los que estos bucles pueden ser de utilidad en flujos de trabajo de Excel.

Suponiendo un caso en el que se desea realizar la limpieza de un conjunto de datos, podemos usar el ciclo For Each... Next para establecer un color de celda en aquellas que se encuentren vacías, de acuerdo a esto vamos a poder identificarlas de manera más sencilla y en consecuencia tomar una serie acciones como borrarlas o tenerlas pendientes para un posterior procesamiento de acuerdo a las necesidades del análisis. El código que describe lo descrito previamente de muestra a continuación.

Public Sub establecerColorCeldasVacias()
    Sheets("Hoja1").Select
    Dim celda As Range
    
    For Each celda In Range("A1:A38")
        If IsEmpty(celda) Then
            celda.Interior.Color = RGB(255, 164, 32) 'Se coloca un color anaranjado
        End If
    Next
End Sub

En este código definimos una variable rango para que el ciclo lo recorra y establecemos una variable llamada celda que va representar cada elemento sobre el que vamos iterando, además, usamos la propiedad Interior.Color para establecer el color de las celdas que cumplan la condición de estar vacías.

Otro caso en que los ciclos pueden ser de mucha utilidad es cuando queremos enviar datos desde una columna hacia otra, ya sea en la misma hoja o en una diferente, en este caso podemos usar el ciclo For... Next porque ya sabemos el número específico de datos que queremos enviar, en el siguiente ejemplo se copian datos en la misma hoja y desde una columna hacia otra.

Public Sub copiarDatosEntreColumnas()
    Dim i As Integer
    
    For i = 1 To 38
        Sheets("Hoja1").Cells(i, 2).Value =                        Sheets("Hoja1").Cells(i, 1).Value
    Next i
End Sub

En esta subrutina se copian los valores de celda desde la columna 1 (A) hacia la columna 2 (B), este código puede ser muy útil para conjuntos de datos cuya cantidad de registros sea muy grande. En este caso el ciclo recorre desde la primera fila hasta las número 38.

Por último, podemos hacer uso del ciclo Do While... Loop para generar un listado de fechas en un rango de celdas, esto puede se de utilidad para aplicaciones que necesiten llevar un control del día en que ocurrió un evento determinado, el ejemplo se muestra a continuación.

Public Sub generarFechas()
    Sheets("Hoja1").Select
    Dim i As Integer
    
    i = 1    
    Do While i <= 60
        Cells(i, 1).Value = Date + i - 1
        i = i + 1
    Loop
End Sub

En este caso se va iterar sobre la celda A, es por eso que se utiliza el 1 en el segundo argumento de la propiedad Cells, además, en la asignación de la fecha se va aumentar el valor del índice i al objeto Date y se le va restar un valor de uno para que la lista de fechas comience en el día actual.

Referencias
Los siguientes enlaces describen los detalles técnicos de las estructuras de Visual Basic utilizadas en este artículo.