Campo alfanumérico consecutivo personalizado para una BBDD en Access
Necesito crear un campo alfanumérico, el cual tenga esta configuración, XXX-0000-00, donde las tres equis sean el prefijo de país, los cuatro ceros el consecutivo y los dos últimos ceros el año en curso, y que cuando termine el año se reinicialice tanto el consecutivo como el año.
No tengo mucha experiencia en código VBA.
2 respuestas
Si disponemos de una tabla (DATOS) que tiene un campo (CLAVE) con las condiciones indicadas, para obtenerlo solo es indispensable el código del país (CodPais) y esta fórmula:
= CodPais & Format(Nz(DMax("Val(Mid(CLAVE, 5, 4))", "DATOS", "LEFT(Clave,3)= '" & CodPais & "' AND RIGHT(Clave, 2)='" & Format(Date, "yy") & "'"), 0) + 1, "-0000-") & Format(Date, "yy")
Hay quienes utilizan la función de dominio DCount en lugar de DMax, si se borrase un registro (o más) de la tabla, se duplicarían datos.
(0001, 0002, 0003, 0004) = 4 registros, el siguiente 0005 con Dmax y DCount
Se 'pierde' uno
(0001, 0002, 0004) = 3 registros, el siguiente el 0005 con Dmax y 0004 con DCount
Se 'pierden' dos
(0002, 0004) = 2 registros, el siguiente el 0005 con Dmax y 0003 con DCount
Gracias Enrique Feijóo pero el prefijo del país habría que seleccionarlo a parte cuando se supiera nacionalidad
Se parte del supuesto de que el código de país ya se tiene a disposición (en una tabla, en un cuadro de lista, en un combo) y según la funcionalidad puede ser el código internacional o el telefónico o ... y un simple CLICK seleccionándolo podrá generar 'el siguiente' para generar (acompañado de mas datos) el nuevo registro.
Un enlace para informarse (por eso de que 'enseñar no cuesta nada'):Normas de codificación
Solo habrá que sustituir 'CodPais ' por la referencia al objeto que tiene la lista de códigos.
La única línea que se utiliza para obtener el siguiente obtiene el mayor filtrando al conjunto por código de país y año, si no lo localiza (el primero de la serie o el cambio de año) reinicia la serie sin modificar sus virtudes.
Lo mismo en forma de función:
Public Function Correlativo(CodPais As String) As String Correlativo = CodPais & Format(Nz(DMax("val(mid(CLAVE,5,4))", "DATOS", "LEFT(Clave,3)= '" & CodPais & "' AND RIGHT(Clave,2)='" & Format(Date, "yy") & "'"), 0) + 1, "-0000-") & Format(Date, "yy") End Function
Su aplicación practica (en el ejemplo la referencia es el codigo de España) sustituible por la referencia al combo cuadro de lista ... etc.
En la ventana de inmediato:
¿? Correlativo("ESP") ESP-0001-22
Enrique Feijóo me coge el ID y no el prefijo del país el resto lo hace perfectamente
Los cuadros de lista (al igual que los Combo Box) devuelven por defecto el valor de su columna dependiente (que suele ser el ID porque lo define como único y normalmente la primera), pero puede ser cualquier columna.
Para este caso (un listado que se supone sus elementos no tiene repeticiones) el ID y el elemento (el código de país) son únicos por lo que el ID no tiene valor practico y se puede prescindir de el o la alternativa de establecer como columna dependiente el 'código de país'.
Opciones:
.- En la vista diseño del formulario y en las propiedades del objeto, pestaña DATOS indicar numéricamente que columna es la predeterminada (si tiene tres columnas, ID, COD_PAIS, NOMBRE_PAIS) indicar que se desea el COD_PAIS (la columna 2) independiente de que sea o no visible
.- En el origen de datos del cuadro de lista eliminar el ID (quedaran dos columnas, COD_PAIS, NOMBRE_PAIS), será la primera la que contiene el dato que nos interesa.
(Y el cuadro de lista será mas ligero al no tener datos sin valor practico para esta funcionalidad)
Private Sub CliNumCliente_GotFocus() CliNumCliente = CliPrefijoPais & Format(Nz(DMax("Val(Mid(CliNumCliente, 5, 4))", "tbl_Clientes", "LEFT(CliNumCliente,3)= '" & CliPrefijoPais & "' AND RIGHT(CliNumCliente, 2)='" & Format(Date, "yy") & "'"), 0) + 1, "-0000-") & Format(Date, "yy") End Sub
Solo a titulo de curiosidad:
¿Qué opción has aplicado?, la de eliminar lo innecesario, la de cambiar la columna dependiente, otras.
- Compartir respuesta
Y ahora con imágenes aunque a muchos no les gusta.
Asumo que tiene una tabla con los códigos de países.
Y tengo una tabla de consecutivos
Y tengo el formulario
Como Colombia ya tiene 2 consecutivos me asigna el 0003. Ahora tomo otro país.
Como Costa Rica no tiene registros me asigna 0001. Ahora tomo Colombia y cambio de año.
Efectivamente la función me asigna 0001 y el año 2023.
Código de la función.
Public Function siguiente(intPais As Integer, mfecha As Date) As String Dim pais As String Dim periodo As String Dim strSQL As String Dim rs As DAO.Recordset pais = Format(Nz(DLookup("codigopais", "tblpaises", "idpais=" & intPais)), "000") periodo = Right(mfecha, 2) strSQL = "SELECT Max(Mid([consecutivo],5,4)) AS numera" & vbCrLf strSQL = strSQL & " FROM tblconsecutivo WHERE ((Mid([consecutivo],1,3)='" & pais & "'" & vbCrLf strSQL = strSQL & " AND Right([consecutivo],2)=" & periodo & "));" Set rs = CurrentDb.OpenRecordset(strSQL) If Nz(rs!numera) = 0 Then siguiente = pais & "-" & "0001" & "-" & periodo Else siguiente = pais & "-" & Format(rs!numera + 1, "0000") & "-" & periodo End If rs.Close Set rs = Nothing End Function
Observe que a la función le paso como parámetros el ID del país y la fecha.
Creo que las imágenes son necesarias y complementarias
Gracias Eduardo Pérez Fernández pero el consecutivo de la tblconsecutivo como lo creas si ya está el id.
y como llamo luego a la función en el cuadro de texto
Digamos que el campo id de la tabla tblconsecutivo sobra. Disculpe se me olvido el código del evento Después de actualizar del cuadro combinado y al recibir el enfoque.
Private Sub cboPais_AfterUpdate() Me.ctlConsecutivo = siguiente(Me.cboPais, Me.ctlFecha) End Sub Private Sub cboPais_GotFocus() If Not IsDate(Me.ctlFecha) Then MsgBox "Indique la fecha!", vbInformation, "Cuidado" Me.ctlFecha.SetFocus End If End Sub
Le aclaro porque no utilizo la función Dmax(). Por que utilizo como backend PostgreSQL y en este servidor y en todos no existe esta función, es propia de bases de datos Jet. Me recomendación trate en lo posible utilizar SQL.
Eduardo Pérez Fernández pero entonces el consecutivo de la tblconsecutivo seria con formato y si es así como sería ese formato
No necesita formato solo fije el campo como texto corto y tamaño 11 caracteres, requerido Sí, indexado Si sin duplicados
Eduardo Pérez Fernández te envié un correo
No llegó revise mi correo es [email protected]
yo Tengo esté mailto:[email protected]
[email protected] es el qué yo tengo
Como no me llegó su correo le explico gráficamente cómo se toma el contenido del campo cboPais del cuadro combinado.
Origen de datos del cuadro combinado
Observe que el SELECT consta de 3 columnas, idpais, pais, codigopais pero la "Columna dependiente" es la 1 (idpais), es decir sería por defecto el valor que toma el cuadro combinado, pero como quiero es el contenido del codigopais y NO es la columna dependiente para tomar este valor debo utilizar Column(indice), en donde indice es 0 para la primera columna 1 para la segunda y 2 para la tercera. Ver figura
Ahora, cuando selecciono el cuadro combinado Pais y quiero utilizar el contenido de la columna codigopais para pasárselo a la función debo hacer referencia como muestra la imagen.
En estas condiciones cambia el código que le había suministrado.
Código del evento "Después de Actualizar"
Private Sub cboPais_AfterUpdate() Me.ctlConsecutivo = siguiente(Me.cboPais.Column(2), Me.ctlFecha) End Sub
Código de la función
Public Function siguiente(StrPais As String, mfecha As Date) As String Dim pais As String Dim periodo As String Dim strSQL As String Dim rs As DAO.Recordset pais = Format(StrPais, "000") periodo = Right(mfecha, 2) strSQL = "SELECT Max(Mid([consecutivo],5,4)) AS numera" & vbCrLf strSQL = strSQL & " FROM tblconsecutivo WHERE ((Mid([consecutivo],1,3)='" & pais & "'" & vbCrLf strSQL = strSQL & " AND Right([consecutivo],2)=" & periodo & "));" Set rs = CurrentDb.OpenRecordset(strSQL) If Nz(rs!numera) = 0 Then siguiente = pais & "-" & "0001" & "-" & periodo Else siguiente = pais & "-" & Format(rs!numera + 1, "0000") & "-" & periodo End If rs.Close Set rs = Nothing End Function
Observe la variable pais que ahora cambio a
pais = Format(StrPais, "000")
Porque le he pasado es una cadena de texto, es decir, la columna 3 de la tabla tblpaises. No obstante, había utilizado el idpais debido a que este valor puede servir para otras consultas etc.
- Compartir respuesta
Muy cierto, son Imprescindibles para los simples (creo que valoras por línea de código por eso tanta paja) - Enrique Feijóo
Enriqueh es un mediocre en conocimientos sobre VBA, aprenda a respetar y reconocer que existen más opciones para una respuesta. - Eduardo Pérez Fernández
Se aprecia que ni con imágenes es capaz de transmitir lo poco que sabe o demuestra, sinceramente: creo que no tiene capacidad para analizar mis respuestas y ... ojo con el SPAM, que puede saltar la liebre si le descubren (en este foro y en otros). - Enrique Feijóo
En ningún momento he dicho que su respuesta a esta pregunta no es acertada pero estoy seguro que ud no tiene idea de programación cliente servidor y menos más allá de solo usar Access. Por esto recomendé sql porque es obligatorio cuando utilizamos como fronend PostgreSQL. Respete si de pronto alguien puede saber más y que no lo diga yo. - Eduardo Pérez Fernández
Tienes muy crecido el ego --- no tengo interés en un simplón almacén de datos que (como el resto de los que conozco MySQL, DBase y SQL Server entre otras) necesitan un entorno de programación para ser funcionales, en definitiva 'sin un entorno externo' (que no tiene que ser necesariamente Access) no tendrían sentido. --- pero estamos en un foro de Access para preguntas sobre Access y con usuarios que suelen iniciar sus preguntas reconociendo su poca experiencia y sobre todo su falta de experiencia en VBA. ---- MADURA un poco y aprende a escuchar para poder aprender y si quieres RESPETO comienza por respetar a los demás e IGNORAME que me aburres. - Enrique Feijóo
Es correcto respetemos pero si hace memoria usted fue quien inicio con comentarios sobre una respuesta que presente. Y por favor no me tenga en cuenta en sus comentarios. - Eduardo Pérez Fernández