Error con permisos de access?

Juan Antonio Figueroa 20 Puntos de reputación
2025-09-12T12:57:44.7733333+00:00

Tengo inconvenientes con los permisos, me indica que vba no acepta este tipo de automatización ¿Alguna idea?

CREATE TABLE tblNormalizacionDef (

TablaOrigen TEXT(128) NOT NULL,

TablaDestino TEXT(128) NOT NULL,

Delimitador TEXT(5) NULL,

CopiarSiSinExpansion YESNO NOT NULL

);

CREATE TABLE tblMapeoCampos (

TablaOrigen TEXT(128) NOT NULL,

CampoLista TEXT(64) NOT NULL,

CampoComentario TEXT(64) NULL,

Orden LONG NOT NULL

);

CREATE TABLE tblTokensIgnorados (

TablaOrigen TEXT(128) NOT NULL,

Token TEXT(64) NOT NULL

);

INSERT INTO tblNormalizacionDef (TablaOrigen, TablaDestino, Delimitador, CopiarSiSinExpansion) VALUES ("TuTablaOrigen", "NORM_TuTablaOrigen", ",", False);

INSERT INTO tblMapeoCampos (TablaOrigen, CampoLista, CampoComentario, Orden) VALUES ("TuTablaOrigen", "documento1", "comentario1", 1);

INSERT INTO tblMapeoCampos (TablaOrigen, CampoLista, CampoComentario, Orden) VALUES ("TuTablaOrigen", "documento2", "comentario2", 2);

INSERT INTO tblTokensIgnorados (TablaOrigen, Token) VALUES ("TuTablaOrigen", "/n");

INSERT INTO tblTokensIgnorados (TablaOrigen, Token) VALUES ("TuTablaOrigen", "n/a");

INSERT INTO tblTokensIgnorados (TablaOrigen, Token) VALUES ("TuTablaOrigen", "-");

Option Compare Database

Option Explicit

' ====== VALORES POR DEFECTO ======

' Si se llama al procedimiento sin parámetros,

' se usarán estos valores.

Public Const DEF_TABLA_ORIGEN As String = "TuTablaOrigen"

Public Const DEF_TABLA_DESTINO As String = "NORM_TuTablaOrigen"

Public Const DEF_TABLA_CONFIG_DEF As String = "tblNormalizacionDef"

Public Const DEF_TABLA_CONFIG_MAPEO As String = "tblMapeoCampos"

Public Const DEF_TABLA_CONFIG_TOKENS As String = "tblTokensIgnorados"

' ===============================================================

' FUNCIONES DE UTILIDAD

' ===============================================================

' Verifica si existe una tabla en la base de datos actual

Private Function ExisteTabla(ByVal nombreTabla As String) As Boolean

Dim t As DAO.TableDef

ExisteTabla = False

For Each t In CurrentDb.TableDefs

' Ignorar tablas del sistema

If t.Attributes = 0 Or (t.Attributes And dbSystemObject) = 0 Then

If t.Name = nombreTabla Then ExisteTabla = True: Exit Function

End If

Next t

End Function

' Verifica si un campo existe dentro de una tabla

Private Function ExisteCampo(ByVal nombreTabla As String, ByVal nombreCampo As String) As Boolean

Dim t As DAO.TableDef

Dim f As DAO.Field

ExisteCampo = False

For Each t In CurrentDb.TableDefs

If t.Name = nombreTabla Then

For Each f In t.Fields

If f.Name = nombreCampo Then ExisteCampo = True: Exit Function

Next f

Exit For

End If

Next t

End Function

' Crea la tabla destino copiando todos los campos de la tabla origen

' y agregando tres campos adicionales:

' - CampoDocumentoOrigen

' - ValorDocumento

' - ComentarioAsociado

Private Sub CrearTablaDestinoComoOrigenMasExtras(ByVal tablaOrigen As String, ByVal tablaDestino As String)

Dim db As DAO.Database

Dim tSrc As DAO.TableDef

Dim tNew As DAO.TableDef

Dim f As DAO.Field

Dim fNew As DAO.Field

Set db = CurrentDb

' Si ya existe la tabla destino, no la volvemos a crear

If ExisteTabla(tablaDestino) Then Exit Sub

Set tNew = db.CreateTableDef(tablaDestino)

' Copiar campos de la tabla origen

For Each tSrc In db.TableDefs

If tSrc.Name = tablaOrigen Then

For Each f In tSrc.Fields

' Si es texto o binario, se conserva el tamaño

If f.Type = dbText Or f.Type = dbBinary Then

Set fNew = tNew.CreateField(f.Name, f.Type, f.Size)

Else

Set fNew = tNew.CreateField(f.Name, f.Type)

End If

tNew.Fields.Append fNew

Next f

Exit For

End If

Next tSrc

' Agregar campos adicionales para normalización

tNew.Fields.Append tNew.CreateField("CampoDocumentoOrigen", dbText, 128)

tNew.Fields.Append tNew.CreateField("ValorDocumento", dbText, 255)

tNew.Fields.Append tNew.CreateField("ComentarioAsociado", dbMemo)

db.TableDefs.Append tNew

End Sub

' Devuelve "" si el valor es NULL

Private Function LimpiarNull(ByVal v As Variant) As String

If IsNull(v) Then LimpiarNull = "" Else LimpiarNull = CStr(v)

End Function

' Limpia espacios y comas extra en los tokens

Private Function TrimToken(ByVal s As String) As String

Dim r As String

r = Trim$(s)

If Left$(r, 1) = "," Then r = Mid$(r, 2)

If Right$(r, 1) = "," Then r = Left$(r, Len(r) - 1)

TrimToken = Trim$(r)

End Function

' Lee configuración en tblNormalizacionDef para una tabla origen

Private Function LeerDef(ByVal tablaOrigen As String, ByVal tablaConfigDef As String, ByRef tablaDestino As String, ByRef delim As String, ByRef copiarSiSin As Boolean) As Boolean

Dim rs As DAO.Recordset

Dim sql As String

LeerDef = False

' Valores predeterminados

tablaDestino = "NORM_" & tablaOrigen

delim = ","

copiarSiSin = False

' Si no existe la tabla de configuración, salimos

If Not ExisteTabla(tablaConfigDef) Then Exit Function

sql = "SELECT TOP 1 TablaDestino, Nz(Delimitador, ',') AS Delim, CopiarSiSinExpansion FROM [" & tablaConfigDef & "] WHERE TablaOrigen = '" & Replace(tablaOrigen, "'", "''") & "'"

Set rs = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)

If Not rs.EOF Then

tablaDestino = rs!TablaDestino

delim = rs!Delim

copiarSiSin = rs!CopiarSiSinExpansion

LeerDef = True

End If

rs.Close

End Function

' Lee pares de campos (documento - comentario) de tblMapeoCampos

Private Function LeerMapeos(ByVal tablaOrigen As String, ByVal tablaConfigMapeo As String) As Collection

Dim col As New Collection

Dim rs As DAO.Recordset

Dim sql As String

Dim item As String

If Not ExisteTabla(tablaConfigMapeo) Then Set LeerMapeos = col: Exit Function

sql = "SELECT CampoLista, CampoComentario FROM [" & tablaConfigMapeo & "] WHERE TablaOrigen = '" & Replace(tablaOrigen, "'", "''") & "' ORDER BY Orden"

Set rs = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)

Do While Not rs.EOF

item = LimpiarNull(rs!CampoLista) & "|" & LimpiarNull(rs!CampoComentario)

col.Add item

rs.MoveNext

Loop

rs.Close

Set LeerMapeos = col

End Function

' Carga la lista de tokens ignorados de tblTokensIgnorados

Private Function CargarTokensIgnorados(ByVal tablaOrigen As String, ByVal tablaConfigTokens As String) As Collection

Dim col As New Collection

Dim rs As DAO.Recordset

Dim sql As String

If Not ExisteTabla(tablaConfigTokens) Then Set CargarTokensIgnorados = col: Exit Function

sql = "SELECT Token FROM [" & tablaConfigTokens & "] WHERE TablaOrigen = '" & Replace(tablaOrigen, "'", "''") & "'"

Set rs = CurrentDb.OpenRecordset(sql, dbOpenSnapshot)

Do While Not rs.EOF

col.Add LCase$(Trim$(LimpiarNull(rs!Token)))

rs.MoveNext

Loop

rs.Close

Set CargarTokensIgnorados = col

End Function

' Verifica si un token está en la lista de ignorados

Private Function TokenIgnorado(ByVal token As String, ByVal tokens As Collection) As Boolean

Dim t As Variant

Dim k As String

k = LCase$(Trim$(token))

If k = "" Then TokenIgnorado = True: Exit Function

On Error Resume Next

For Each t In tokens

If k = t Then TokenIgnorado = True: Exit Function

Next t

End Function

' ===============================================================

' PROCEDIMIENTO PRINCIPAL

' ===============================================================

Public Sub Normalizar_Expandir(Optional ByVal tablaOrigen As String = DEF_TABLA_ORIGEN, Optional ByVal tablaDestino As String = DEF_TABLA_DESTINO, Optional ByVal tablaConfigDef As String = DEF_TABLA_CONFIG_DEF, Optional ByVal tablaConfigMapeo As String = DEF_TABLA_CONFIG_MAPEO, Optional ByVal tablaConfigTokens As String = DEF_TABLA_CONFIG_TOKENS)

Dim db As DAO.Database

Dim rsSrc As DAO.Recordset

Dim rsDst As DAO.Recordset

Dim delim As String

Dim copiarSiSin As Boolean

Dim tieneDef As Boolean

Dim mapeos As Collection

Dim tokensIgn As Collection

Dim par As String

Dim nombreLista As String

Dim nombreComentario As String

Dim valorLista As String

Dim comentarioVal As String

Dim tokens() As String

Dim tok As Variant

Dim huboExp As Boolean

Dim f As DAO.Field

Dim i As Long

Set db = CurrentDb

' 1. Leer configuración general (si existe)

tieneDef = LeerDef(tablaOrigen, tablaConfigDef, tablaDestino, delim, copiarSiSin)

If Not tieneDef Then

' Si no hay config, usar valores por defecto

tablaDestino = IIf(Len(Trim$(tablaDestino)) = 0, "NORM_" & tablaOrigen, tablaDestino)

delim = ","

copiarSiSin = False

End If

' 2. Leer pares documento-comentario

Set mapeos = LeerMapeos(tablaOrigen, tablaConfigMapeo)

' 3. Cargar tokens a ignorar

Set tokensIgn = CargarTokensIgnorados(tablaOrigen, tablaConfigTokens)

' 4. Crear tabla destino si no existe

Call CrearTablaDestinoComoOrigenMasExtras(tablaOrigen, tablaDestino)

' 5. Vaciar la tabla destino antes de insertar nuevos datos

db.Execute "DELETE FROM [" & tablaDestino & "]", dbFailOnError

' 6. Abrir recordsets

Set rsSrc = db.OpenRecordset("SELECT * FROM [" & tablaOrigen & "]", dbOpenSnapshot)

Set rsDst = db.OpenRecordset("SELECT * FROM [" & tablaDestino & "]", dbOpenDynaset)

' 7. Procesar cada registro de la tabla origen

Do While Not rsSrc.EOF

huboExp = False

' Recorrer los pares configurados

For i = 1 To mapeos.Count

par = mapeos(i)

nombreLista = Split(par, "|")(0)

nombreComentario = ""

If UBound(Split(par, "|")) >= 1 Then nombreComentario = Split(par, "|")(1)

' Verificar que el campo de documentos exista en la tabla

If ExisteCampo(tablaOrigen, nombreLista) Then

valorLista = LimpiarNull(rsSrc.Fields(nombreLista).Value)

' Si hay datos en el campo documento

If valorLista <> "" Then

tokens = Split(valorLista, delim)

comentarioVal = ""

' Traer comentario si existe

If nombreComentario <> "" And ExisteCampo(tablaOrigen, nombreComentario) Then comentarioVal = LimpiarNull(rsSrc.Fields(nombreComentario).Value)

' Recorrer cada token

For Each tok In tokens

tok = TrimToken(CStr(tok))

' Insertar solo si no está en la lista de ignorados

If Not TokenIgnorado(CStr(tok), tokensIgn) Then

rsDst.AddNew

' Copiar todos los campos originales

For Each f In rsSrc.Fields

rsDst.Fields(f.Name).Value = rsSrc.Fields(f.Name).Value

Next f

' Agregar campos extra

rsDst.Fields("CampoDocumentoOrigen").Value = nombreLista

rsDst.Fields("ValorDocumento").Value = tok

rsDst.Fields("ComentarioAsociado").Value = comentarioVal

rsDst.Update

huboExp = True

End If

Next tok

End If

End If

Next i

' Si no hubo expansiones y la config lo permite, copiar el registro tal cual

If Not huboExp And copiarSiSin Then

rsDst.AddNew

For Each f In rsSrc.Fields

rsDst.Fields(f.Name).Value = rsSrc.Fields(f.Name).Value

Next f

rsDst.Fields("CampoDocumentoOrigen").Value = ""

rsDst.Fields("ValorDocumento").Value = ""

rsDst.Fields("ComentarioAsociado").Value = ""

rsDst.Update

End If

rsSrc.MoveNext

Loop

' 8. Cerrar recordsets

rsSrc.Close

rsDst.Close

MsgBox "Normalización completada. Tabla destino: " & tablaDestino, vbInformation

End Sub

Microsoft 365 y Office | Access | Otros | Otros

2 respuestas

Ordenar por: Lo más útil
  1. Juan Antonio Figueroa 20 Puntos de reputación
    2025-10-02T12:21:26.4666667+00:00

    EL problema tanbién se da con este código

    Option Compare Database

    Option Explicit

    '========================

    ' Utilidades

    '========================

    Private Function TblExiste(ByVal nombre As String) As Boolean

    On Error Resume Next

    Dim t As DAO.TableDef

    For Each t In CurrentDb.TableDefs

    If StrComp(t.Name, nombre, vbTextCompare) = 0 Then TblExiste = True: Exit Function

    Next t

    TblExiste = False

    End Function

    Private Sub DropSiExiste(ByVal nombre As String)

    On Error Resume Next

    CurrentDb.Execute "DROP TABLE [" & nombre & "]"

    On Error GoTo 0

    End Sub

    Private Function FmtISO(ByVal d As Date) As String

    FmtISO = Format(d, "yyyy-mm-dd")

    End Function

    '========================

    ' Lectura de configuración

    '========================

    Private Sub LeerConfig( _

    ByRef tablaLlamadas As String, ByRef campoIdUsu1 As String, ByRef campoInicio As String, ByRef campoFin As String, _

    ByRef tablaClasif As String, ByRef campoIdUsu2 As String, ByRef campoFechaReg As String)

    Dim rs As DAO.Recordset

    Set rs = CurrentDb.OpenRecordset("SELECT * FROM tblConfig")

    If rs.EOF Then Err.Raise vbObjectError + 7001, "LeerConfig", "tblConfig no tiene registros."

    tablaLlamadas = Nz(rs!TablaLlamadas, "")

    campoIdUsu1 = Nz(rs!CampoIdUsuario1, "")

    campoInicio = Nz(rs!CampoInicio, "")

    campoFin = Nz(rs!CampoFin, "")

    tablaClasif = Nz(rs!TablaClasificador, "")

    campoIdUsu2 = Nz(rs!CampoIdUsuario2, "")

    campoFechaReg = Nz(rs!CampoFechaRegistro, "")

    rs.Close

    If Len(tablaLlamadas) = 0 Or Len(campoIdUsu1) = 0 Or Len(campoInicio) = 0 Or Len(campoFin) = 0 _

    Or Len(tablaClasif) = 0 Or Len(campoIdUsu2) = 0 Or Len(campoFechaReg) = 0 Then

    Err.Raise vbObjectError + 7002, "LeerConfig", "Faltan campos en tblConfig."

    End If

    End Sub

    '========================

    ' Crear tablas finales (desde cero) clonando tipos

    '========================

    Private Sub RecrearTablasFinales(ByVal tablaLlamadas As String, ByVal tablaClasif As String)

    ' tblCruce_Final = L.* + C.* (sin filas), luego agrega FechaProceso

    DropSiExiste "tblCruce_Final"

    CurrentDb.Execute "SELECT TOP 0 L.*, C.* INTO tblCruce_Final FROM [" & tablaLlamadas & "] AS L, [" & tablaClasif & "] AS C"

    CurrentDb.Execute "ALTER TABLE tblCruce_Final ADD COLUMN FechaProceso DATETIME"

    ' tblSinLlamada_Final = C.* (sin filas), luego FechaProceso

    DropSiExiste "tblSinLlamada_Final"

    CurrentDb.Execute "SELECT TOP 0 C.* INTO tblSinLlamada_Final FROM [" & tablaClasif & "] AS C"

    CurrentDb.Execute "ALTER TABLE tblSinLlamada_Final ADD COLUMN FechaProceso DATETIME"

    ' tblSinClasif_Final = L.* (sin filas), luego FechaProceso

    DropSiExiste "tblSinClasif_Final"

    CurrentDb.Execute "SELECT TOP 0 L.* INTO tblSinClasif_Final FROM [" & tablaLlamadas & "] AS L"

    CurrentDb.Execute "ALTER TABLE tblSinClasif_Final ADD COLUMN FechaProceso DATETIME"

    End Sub

    '========================

    ' Procesar un día (sin mensajes, acumula totales)

    '========================

    Private Sub ProcesarDiaInterno( _

    ByVal tablaLlamadas As String, ByVal campoIdUsu1 As String, ByVal campoInicio As String, ByVal campoFin As String, _

    ByVal tablaClasif As String, ByVal campoIdUsu2 As String, ByVal campoFechaReg As String, _

    ByVal fechaProc As Date, _

    ByRef totalCruce As Long, ByRef totalSinLlamada As Long, ByRef totalSinClasif As Long)

    Dim db As DAO.Database: Set db = CurrentDb

    Dim sqlText As String

    Dim f As String: f = FmtISO(fechaProc)

    ' 1) Cruce en rango

    sqlText = "INSERT INTO tblCruce_Final SELECT L.*, C.*, #" & f & "# AS FechaProceso " & _

    "FROM [" & tablaLlamadas & "] AS L INNER JOIN [" & tablaClasif & "] AS C " & _

    "ON L.[" & campoIdUsu1 & "] = C.[" & campoIdUsu2 & "] " & _

    "AND C.[" & campoFechaReg & "] BETWEEN L.[" & campoInicio & "] AND L.[" & campoFin & "] " & _

    "WHERE DateValue(C.[" & campoFechaReg & "]) = #" & f & "#"

    db.Execute sqlText

    totalCruce = totalCruce + db.RecordsAffected

    ' 2) Cruce por última llamada previa

    sqlText = "INSERT INTO tblCruce_Final SELECT L.*, C.*, #" & f & "# AS FechaProceso " & _

    "FROM [" & tablaLlamadas & "] AS L INNER JOIN [" & tablaClasif & "] AS C " & _

    "ON L.[" & campoIdUsu1 & "] = C.[" & campoIdUsu2 & "] " & _

    "WHERE L.[" & campoFin & "] = (" & _

    " SELECT MAX(L2.[" & campoFin & "]) FROM [" & tablaLlamadas & "] AS L2 " & _

    " WHERE L2.[" & campoIdUsu1 & "] = C.[" & campoIdUsu2 & "] " & _

    " AND L2.[" & campoFin & "] < C.[" & campoFechaReg & "]" & _

    ") AND DateValue(C.[" & campoFechaReg & "]) = #" & f & "#"

    db.Execute sqlText

    totalCruce = totalCruce + db.RecordsAffected

    ' 3) Clasificaciones sin llamada

    sqlText = "INSERT INTO tblSinLlamada_Final SELECT C.*, #" & f & "# AS FechaProceso " & _

    "FROM [" & tablaClasif & "] AS C " & _

    "WHERE DateValue(C.[" & campoFechaReg & "]) = #" & f & "# " & _

    "AND NOT EXISTS (" & _

    " SELECT 1 FROM tblCruce_Final AS X " & _

    " WHERE X.[" & campoFechaReg & "] = C.[" & campoFechaReg & "] " & _

    " AND X.FechaProceso = #" & f & "# " & _

    ")"

    db.Execute sqlText

    totalSinLlamada = totalSinLlamada + db.RecordsAffected

    ' 4) Llamadas sin clasificaciones

    sqlText = "INSERT INTO tblSinClasif_Final SELECT L.*, #" & f & "# AS FechaProceso " & _

    "FROM [" & tablaLlamadas & "] AS L " & _

    "WHERE DateValue(L.[" & campoInicio & "]) = #" & f & "# " & _

    "AND NOT EXISTS (" & _

    " SELECT 1 FROM tblCruce_Final AS X " & _

    " WHERE X.[" & campoInicio & "] = L.[" & campoInicio & "] " & _

    " AND X.[" & campoFin & "] = L.[" & campoFin & "] " & _

    " AND X.[" & campoIdUsu1 & "] = L.[" & campoIdUsu1 & "] " & _

    " AND X.FechaProceso = #" & f & "# " & _

    ")"

    db.Execute sqlText

    totalSinClasif = totalSinClasif + db.RecordsAffected

    End Sub

    '========================

    ' Principal (híbrido): procesa todo o un rango

    '========================

    Public Sub ProcesarRango(Optional ByVal fIni As Variant, Optional ByVal fFin As Variant)

    On Error GoTo EH

    Dim tablaLlamadas As String, tablaClasif As String

    Dim campoIdUsu1 As String, campoInicio As String, campoFin As String

    Dim campoIdUsu2 As String, campoFechaReg As String

    Dim rsDias As DAO.Recordset

    Dim sqlDias As String

    Dim minDia As Date, maxDia As Date

    Dim fechaDia As Date

    Dim totalCruce As Long, totalSinLlamada As Long, totalSinClasif As Long

    Dim rangoIniTxt As String, rangoFinTxt As String

    ' 1) Config

    Call LeerConfig(tablaLlamadas, campoIdUsu1, campoInicio, campoFin, tablaClasif, campoIdUsu2, campoFechaReg)

    ' 2) Recrear tablas finales

    Call RecrearTablasFinales(tablaLlamadas, tablaClasif)

    ' 3) Días disponibles

    sqlDias = "SELECT DISTINCT DateValue([" & campoFechaReg & "]) AS Dia FROM [" & tablaClasif & "] ORDER BY Dia"

    Set rsDias = CurrentDb.OpenRecordset(sqlDias)

    If rsDias.EOF Then

    MsgBox "No hay registros en el insumo para procesar.", vbInformation

    Exit Sub

    End If

    minDia = rsDias!Dia

    rsDias.MoveLast: maxDia = rsDias!Dia

    rsDias.MoveFirst

    ' 4) Definir rango efectivo

    If IsMissing(fIni) Or IsNull(fIni) Then fIni = minDia

    If IsMissing(fFin) Or IsNull(fFin) Then fFin = maxDia

    rangoIniTxt = Format(CDate(fIni), "dd/mm/yyyy")

    rangoFinTxt = Format(CDate(fFin), "dd/mm/yyyy")

    ' 5) Recorrer días y procesar

    Do Until rsDias.EOF

    fechaDia = rsDias!Dia

    If fechaDia >= CDate(fIni) And fechaDia <= CDate(fFin) Then

    Call ProcesarDiaInterno(tablaLlamadas, campoIdUsu1, campoInicio, campoFin, _

    tablaClasif, campoIdUsu2, campoFechaReg, fechaDia, _

    totalCruce, totalSinLlamada, totalSinClasif)

    End If

    rsDias.MoveNext

    Loop

    rsDias.Close

    ' 6) Resumen final

    MsgBox "Procesamiento completado del " & rangoIniTxt & " al " & rangoFinTxt & vbCrLf & vbCrLf & _

    "Totales insertados:" & vbCrLf & _

    " tblCruce_Final: " & totalCruce & vbCrLf & _

    " tblSinLlamada_Final: " & totalSinLlamada & vbCrLf & _

    " tblSinClasif_Final: " & totalSinClasif, vbInformation

    Exit Sub

    EH:

    MsgBox "Error: " & Err.Number & " - " & Err.Description, vbCritical, "ProcesarRango"

    End Sub

    ¿Le resultó útil esta respuesta?


  2. Anónimo
    2025-09-12T14:02:56.13+00:00

    Hola @Juan Antonio Figueroa

    Esta respuesta ha sido traducida automáticamente. Como resultado, puede contener errores gramaticales o expresiones extrañas. 

    Gracias por ponerte en contacto con el Foro de Microsoft Q&A. 

    Según tu descripción, parece que Access podría estar bloqueando la automatización de VBA debido a restricciones de seguridad o permisos. Aquí hay algunos pasos que puedes intentar para resolver el problema. 

    1. Habilitar macros y VBA en el Centro de confianza: 

    -Ve a Archivo > Opciones > Centro de confianza > Configuración del Centro de confianza > Configuración de macros > selecciona Habilitar todas las macros > Haz clic en Aceptar para aplicar. 

    -También revisa Ubicaciones de confianza: Agrega la carpeta de tu base de datos a la lista en Configuración del Centro de confianza > Ubicaciones de confianza para evitar restricciones de sandbox. 

    1. Verificar la referencia de la biblioteca DAO: 

    -En el Editor de VBA (Alt+F11): ve a Herramientas > Referencias 

    -Asegúrate de que Microsoft DAO 3.6 Object Library (o una más reciente, como 14.0 para Access 2010+) esté marcada. Si falta, búscala (normalmente en C:\Program Files\Common Files\Microsoft Shared\DAO\dao360.dll). 

    1. Permisos del archivo y carpeta de la base de datos: 

    -Haz clic derecho en tu archivo .accdb > Propiedades > Seguridad (o desbloquéalo desde Propiedades > General > Desbloquear si fue descargado). 

    -Asegúrate de que tu usuario de Windows tenga Control total sobre el archivo y su carpeta. 

    -Si la base de datos está en una red o recurso compartido, cópiala localmente y prueba. 

    -Compacta/repara la base de datos (Archivo > Información > Compactar y reparar base de datos) para eliminar cualquier corrupción que pueda causar errores de permisos. 

    1. Ejecutar en una base de datos nueva/vacía para pruebas: 

    -Crea un archivo .accdb nuevo. 

    -Pega tu SQL en una nueva consulta (en vista SQL) y ejecútala para crear/poblar las tablas de configuración. 

    -Pega el módulo VBA en un nuevo módulo estándar. 

    -Llama a Normalizar_Expandir desde la ventana Inmediata (Ctrl+G): Normalizar_Expandir. 

    -Si funciona aquí, el problema está en tu base de datos original: importa los objetos o revisa si hay formularios/informes bloqueados que impidan la automatización. 

    1. Manejar errores correctamente en el código: 

    -Envuelve las secciones de riesgo (por ejemplo, creación de tablas, eliminaciones) en manejo de errores para identificar la línea exacta que falla. Agrega esto al inicio de tu sub Normalizar_Expandir (después de Option Explicit):

    On Error GoTo ErrorHandler

    Y al final:

    Exit Sub

    ErrorHandler:

    MsgBox "Error " & Err.Number & ": " & Err.Description & vbCrLf & "Line: " & Erl, vbCritical

    -Esto mostrará detalles específicos, como Error 3044 (base de datos de solo lectura) o 3265 (elemento no encontrado en esta colección) por tablas faltantes.  

    Espero que esto te ayude. Si el problema persiste, no dudes en avisarme.


    Nota: Por favor sigue los pasos en nuestra documentación para habilitar las notificaciones por correo electrónico si deseas recibir notificaciones relacionadas con este hilo.

    ¿Le resultó útil esta respuesta?


Su respuesta

Las respuestas pueden ser marcadas como Respuestas aceptadas por el autor de la pregunta, lo que indica a los usuarios que la respuesta resolvió su problema.