library(DBI)
library(odbc)
library(dplyr)
library(dbplyr)Migración de RODBC a dplyr/dbplyr para bases de datos Access
Guía práctica para trabajar con bases de datos Access en R
Introducción
Esta guía facilita la transición desde RODBC hacia dplyr/dbplyr para trabajar con bases de datos Microsoft Access. La principal ventaja de este cambio es la integración con el ecosistema tidyverse, permitiendo usar la sintaxis familiar de dplyr para trabajar con bases de datos.
Ventajas de dbplyr frente a RODBC
- Sintaxis tidyverse: Usa los verbos habituales de dplyr (
filter(),select(),mutate(), etc.) - Evaluación diferida (lazy evaluation): Las consultas no se ejecutan hasta que sea necesario
- Optimización automática: dbplyr traduce el código R a SQL optimizado
- Visualización de consultas: Puedes ver el SQL generado con
show_query() - Menor uso de memoria: Solo traes los datos cuando los necesitas con
collect()
Paquetes necesarios
Función de conexión
Ya tienes preparada una función sencilla para conectar a bases de datos Access:
fConAccess <- function(ruta) {
DBI::dbConnect(odbc::odbc(),
.connection_string = paste0("Driver={Microsoft Access Driver ",
"(*.mdb, *.accdb)};",
"DBQ=", ruta, ";"))
}Uso de la función
# Conectar a la base de datos
con <- fConAccess("C:/ruta/a/tu/base_datos.accdb")Guarda la ruta de tu base de datos en una variable al inicio del script para facilitar cambios futuros:
ruta_bd <- "C:/datos/hidraulica.accdb"
con <- fConAccess(ruta_bd)Exploración de la base de datos
Listar tablas disponibles
# Ver todas las tablas en la base de datos
DBI::dbListTables(con)Crear referencia a una tabla
Con dbplyr, no traes los datos inmediatamente. Primero creas una referencia a la tabla:
# Crear referencia a la tabla (NO descarga datos todavía)
estaciones <- tbl(con, "Estaciones")Ver estructura de la tabla
# Ver primeras filas
estaciones
# Ver columnas y tipos
glimpse(estaciones)Trabajar con datos: evaluación diferida
La clave de dbplyr es la evaluación diferida (lazy evaluation): puedes encadenar operaciones sin que se ejecuten consultas hasta que sea estrictamente necesario.
Filtrado y selección
# Filtrar y seleccionar columnas (aún no se ejecuta)
estaciones_filtradas <- estaciones |>
filter(Cuenca == "Ebro",
Año >= 2010) |>
select(Codigo, Nombre, Municipio, Latitud, Longitud, Año)
# Ver la consulta SQL que se generará
show_query(estaciones_filtradas)Agregaciones y resúmenes
# Calcular estadísticos por cuenca
resumen_cuencas <- estaciones |>
group_by(Cuenca) |>
summarise(
n_estaciones = n(),
cota_media = mean(Cota, na.rm = TRUE),
cota_max = max(Cota, na.rm = TRUE)
) |>
arrange(desc(n_estaciones))
# Todavía no se han traído los datos
show_query(resumen_cuencas)Joins entre tablas
# Referencias a dos tablas
estaciones <- tbl(con, "Estaciones")
datos_aforo <- tbl(con, "DatosAforo")
# Join entre tablas
datos_completos <- datos_aforo |>
inner_join(estaciones, by = c("CodigoEstacion" = "Codigo")) |>
filter(Fecha >= "2020-01-01") |>
select(Fecha, CodigoEstacion, Nombre, Caudal, Cuenca)
show_query(datos_completos)Traer datos a R: collect()
Cuando necesites los datos en memoria, usa collect():
# AHORA sí se ejecuta la consulta y se traen los datos
datos_en_r <- estaciones_filtradas |>
collect()
# Ya es un tibble normal de R
class(datos_en_r)
dim(datos_en_r)Usa collect() solo cuando necesites los datos en R. Si puedes hacer el filtrado y agregación en la base de datos, será mucho más eficiente, especialmente con tablas grandes.
Comparativa: RODBC vs dbplyr
Estilo RODBC (anterior)
# Forma antigua con RODBC
library(RODBC)
canal <- odbcConnectAccess2007("C:/datos/hidraulica.accdb")
# SQL explícito
consulta <- "SELECT Codigo, Nombre, Municipio
FROM Estaciones
WHERE Cuenca = 'Ebro' AND Año >= 2010"
datos <- sqlQuery(canal, consulta)
odbcClose(canal)Estilo dbplyr (nuevo)
# Forma nueva con dbplyr
con <- fConAccess("C:/datos/hidraulica.accdb")
datos <- tbl(con, "Estaciones") |>
filter(Cuenca == "Ebro", Año >= 2010) |>
select(Codigo, Nombre, Municipio) |>
collect()
DBI::dbDisconnect(con)Ventajas del nuevo enfoque:
- Sintaxis R nativa (no SQL)
- Más legible y mantenible
- Fácil de combinar con otros procesos tidyverse
- Mejor manejo de tipos de datos
- Evaluación diferida para optimización
Operaciones comunes
Filtrado avanzado
# Múltiples condiciones
datos <- tbl(con, "DatosAforo") |>
filter(
Fecha >= "2020-01-01",
Fecha <= "2023-12-31",
!is.na(Caudal),
Caudal > 0
) |>
collect()Crear nuevas columnas
# Transformaciones sobre los datos
datos_transformados <- tbl(con, "DatosAforo") |>
mutate(
Año = year(Fecha),
Mes = month(Fecha),
Caudal_m3s = Caudal / 1000,
Categoria = case_when(
Caudal < 10 ~ "Bajo",
Caudal < 100 ~ "Medio",
TRUE ~ "Alto"
)
) |>
collect()Exportar a distintos formatos
Una vez tengas los datos en R con collect(), puedes guardarlos:
# A CSV
write.csv(datos, "resultados.csv", row.names = FALSE)
# Con readr (mejor para grandes archivos)
readr::write_csv(datos, "resultados.csv")
# A Excel
library(writexl)
write_xlsx(datos, "resultados.xlsx")
# A formato RDS (nativo de R, mantiene tipos)
saveRDS(datos, "resultados.rds")Flujo de trabajo recomendado
# 1. Conectar
con <- fConAccess("C:/datos/mi_base.accdb")
# 2. Explorar
DBI::dbListTables(con)
# 3. Crear referencias y filtrar (lazy)
datos_filtrados <- tbl(con, "MiTabla") |>
filter(Condicion == "Valor") |>
select(Columna1, Columna2, Columna3)
# 4. Verificar la consulta (opcional)
show_query(datos_filtrados)
# 5. Traer datos solo cuando sea necesario
datos_finales <- datos_filtrados |>
collect()
# 6. Procesamiento adicional en R si es necesario
datos_procesados <- datos_finales |>
mutate(nueva_columna = Columna1 * 2)
# 7. Guardar resultados
write_csv(datos_procesados, "resultados.csv")
# 8. Cerrar conexión
DBI::dbDisconnect(con)Buenas prácticas
Filtra en la base de datos: Usa
filter(),select()antes decollect()para reducir la cantidad de datos transferidosVerifica consultas complejas: Usa
show_query()para ver el SQL generado, especialmente en joins complejosCierra conexiones: Siempre usa
DBI::dbDisconnect(con)al terminarUsa collect() conscientemente: Solo trae datos cuando realmente los necesites en memoria
Gestión de fechas: Las fechas pueden ser problemáticas. Verifica el formato con
glimpse()tras elcollect()NAs en agregaciones: Recuerda usar
na.rm = TRUEen funciones comomean(),sum(), etc.
Solución de problemas comunes
Error de codificación de caracteres
# Si tienes problemas con acentos o eñes
datos <- tbl(con, "Tabla") |>
collect() |>
mutate(across(where(is.character), ~ iconv(., from = "latin1", to = "UTF-8")))Fechas no reconocidas
# Convertir explícitamente después de collect()
datos <- tbl(con, "Tabla") |>
collect() |>
mutate(Fecha = as.Date(Fecha, format = "%d/%m/%Y"))Nombres de columnas con espacios
# Usar backticks para nombres con espacios
datos <- tbl(con, "Tabla") |>
select(`Nombre Estación`, `Caudal Medio`) |>
collect()
# O renombrar al traer los datos
datos <- tbl(con, "Tabla") |>
select(nombre = `Nombre Estación`, caudal = `Caudal Medio`) |>
collect()Recursos adicionales
Ejemplo práctico completo
# Análisis completo de datos de aforo
library(DBI)
library(odbc)
library(dplyr)
library(lubridate)
# Conectar
con <- fConAccess("C:/datos/aforos.accdb")
# Análisis: caudales medios mensuales por estación en 2023
analisis_caudales <- tbl(con, "DatosAforo") |>
filter(year(Fecha) == 2023) |>
mutate(Mes = month(Fecha)) |>
group_by(CodigoEstacion, Mes) |>
summarise(
Caudal_Medio = mean(Caudal, na.rm = TRUE),
Caudal_Max = max(Caudal, na.rm = TRUE),
Dias_Datos = n(),
.groups = "drop"
) |>
collect()
# Unir con información de estaciones
estaciones_info <- tbl(con, "Estaciones") |>
select(Codigo, Nombre, Cuenca, Rio) |>
collect()
resultado_final <- analisis_caudales |>
left_join(estaciones_info, by = c("CodigoEstacion" = "Codigo"))
# Guardar
write_csv(resultado_final, "caudales_mensuales_2023.csv")
# Cerrar
DBI::dbDisconnect(con)Fecha de creación: 2025-11-04