Contador para los registros iguales de una tabla

Me gustaría formular una pregunta que se me antoja sencilla pero para la que no acabo de encontrar la solución.

Tengo una tabla en la que aparecen datos de determinadas personas, entre ellas su nacionalidad. Lo que intento es numerarlos a partir de 1 para cada nacionalidad, de tal forma que el contador se inicie cada vez que cambie el pais. Por ejemplo:

1 ESP

2 ESP

1 FRA

1 USA

2 USA

3 USA

Etc

Respuesta
2

Otra opción: usando una función específica.

Si nos creamos esta función en un módulo independiente:

'---------------------------------------------------------------------------------------------
' Autor : JESUS MANSILLA CASTELLS -Mihura-
'---------------------------------------------------------------------------------------------
Public Function RT_NumerarParcialSQL(nDato) As Long
'variable que no se pierde entre las distintas llamadas
Static nCONTADOR As Long, nANTERIOR As String
If IsNull(nDato) Then 'si nDato es nulo: Iniciamos valor
nCONTADOR = 0
nANTERIOR = ""
Exit Function
End If
'- si nDato es igual al valor memorizado sumamos 1 al contador
If nDato = nANTERIOR Then
nCONTADOR = nCONTADOR + 1
Else '- iniciamos valor y memorizamos el anterior
nCONTADOR = 1
nANTERIOR = nDato
End If
RT_NumerarParcialSQL = nCONTADOR
End Function

La podemos llamar desde nuestra consulta, para numerar e iniciar contador por bloques:

SELECT Pais, Nombre, RT_NumerarParcialSQL(Pais) AS OrdenParcial
FROM TQ
ORDER BY Pais

Partiendo de esto:

Obtenemos esto:

2 respuestas más de otros expertos

Respuesta
2

Una opción alternativa a al que te plantea Icue (aunque bastante similar), sin necesidad de añadir un campo nuevo a la tabla, y con la ventaja de que el orden se calcula solo, sin necesidad de estar pulsando el botón cada vez que añadas un registro.:

1º/ Creas una función pública en un módulo nuevo, que podría ser similar a ésta (habrás de adaptarla a tus nombres):

Public Function fncOrden(elId As Integer, elPais As String) As Long
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("SELECT * FROM TClientes WHERE Pais='" & elPais & "' ORDER BY Id")
rst.MoveLast
rst.MoveFirst
Do Until rst.EOF
    If rst("Id") = elId Then fncOrden = rst.AbsolutePosition + 1
    rst.MoveNext
Loop
rst.Close
Set rst = Nothing
End Function

2º/ Creas una consulta con los campos de la tabla, y añades un nuevo campo con este encabezado:

Orden: fncOrden([Id];[Pais])

Y listo. Al ejecutar la consulta tendrás el orden de cada registro por país. La misma función la puedes usar en cualquier parte de la BD( en un formulario, en un informe, en otro código...)

Te dejo un mini-ejemplo con este método: http://filebig.net/files/RUiwqji9mh 

Un saludo


Muchísimas gracias Icue, Sveinbjorn y Jesús por vuestras magníficas contestaciones.

Aunque voy a comprobar todos los métodos, ya que me servirán para aprender un poco, he decidido empezar por el de Sveinbjorn, ya que me automatiza un poco más el trabajo.

Sveinbjorn, en cuanto a la función en sí, funciona perfectamente pero me surje un pequeño problema. Dado que tengo bastantes tablas para numerar, he intentado crear una función para cada una de ellas con el fin de no tener que estar reescribiendo el nombre de la tabla en el Select cada vez, pero al ejecutarlas me dan error. ¿Existe algún tipo de incompatibilidad al respecto? ¿Tiene algo que ver con el tipo de función?

Muchas gracias a todos de nuevo.

Carlos.

En primer lugar, señalarte que la función que te propone Jesús es "mejor" que la mía, pues realiza el mismo proceso, pero sin necesidad de indicar la tabla o un campo adicional para filtrar los registros, por lo que te funcionará directamente con todas las tablas.

En segundo lugar, y para responder a tu pregunta, a mi función le puedes añadir otro parámetro (por ej.: laTabla As String) para usar una única función para todas las tablas (con estructura similar) y que te quede así:

Public Function fncOrden(elId As Integer, elPais As String, laTabla As String) As Long
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("SELECT * FROM " & laTabla & " WHERE Pais='" & elPais & "' ORDER BY Id")
...
End Function

pero has de tener en cuenta que si no existe el campo Pais o Id en la tabla que le pases te dará un error. 

También has de tener en cuenta el tipo de dato del campo por el que vas a filtrar, por ejemplo, si en vez de país quisieras filtrar por edades (valor numérico), el select sería:

"SELECT * FROM " & laTabla & " WHERE Edad=" & laEdad & " ORDER BY Id"

(Es decir, sin las comillas simples)

Y el parámetro de la función: laEdad As Integer (en vez de String)

Y si quisieras filtrar por un campo de fecha:

"SELECT * FROM " & laTabla & " WHERE Fecha=" & laFecha& " ORDER BY Id"

Y el parámetro: laFecha As Date.

Por último es difícil decirte qué estás haciendo mal si no das más información (código que usas, tipo de error y dónde, campos de las tablas...)

No sé si te aclaré algo o te lié aún más, jejeje

Muchas gracias de nuevo SvenBjorn.

En realidad el error era debido a que no había copiado correctamente la función. Así es que he creado un módulo donde van las funciones correspondientes a cada tabla.

No he acabado de enteder como debo de hacer con el parámetro "laTabla" para que dicha función me valga para todas las tablas. ¿Simplemente sustituir el nombre de la tabla por 

" & laTabla & "

en SELECT y la reconocerá automáticamente?

Un saludo.

Carlos.

Si tienes la función como:

Public Function fncOrden(elId As Integer, elPais As String, laTabla As String) As Long
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("SELECT * FROM " & laTabla & " WHERE Pais='" & elPais & "' ORDER BY Id")
...
End Function

es decir, con un parámetro para elegir la tabla, cuando la ejecutes tienes que pasarle también el valor de la tabla, por ejemplo,:

Orden: fncOrden([Id];[Pais],"TClientesAmerica")

En ese ejemplo supongo que tienes una tabla llamada TCLientesAmerica, y que tiene, entre otros, los campos Id y Pais. Con ese campo en una consulta, te numerará los clientes por país como querías, porque la SQL sobre la que se abre el recordset es:

"SELECT  * FROM TClientesAmerica WHERE....."

Fíjate que el nombre de la tabla se le pasa como cadena de texto, y no como el valor de los campos del registro actual como Id y Pais.

Si tienes otra tabla en la misma BD, llamada TClientesEuropa (tambien con los campos Id y Pais), puedes sacar su orden en una consulta con:

Orden: fncOrden([Id];[Pais],"TClientesEuropa")

Y lo mismo para las tablas TClientesAfrica y TClientesAsia.

Es decir, con una misma función, parametrizando el nombre de la tabla, puedes asignar cualquiera de las que tengas (de nuevo siempre que tengan los dos campos Id y Pais que sirven de orden y filtro, respectivamente)

Si quieres rizar más el rizo, puedes parametrizar tambien esos campos, por ejemplo:

Public Function fncOrden(laTabla As String, elCampoFiltro As String, elCampoOrden As String, elValorFiltro As String, elValorOrden As Integer) As Long
Dim rst As DAO.Recordset
Set rst = CurrentDb.OpenRecordset("SELECT * FROM " & laTabla & " WHERE " & elCampoFiltro & "='" & elValorFiltro & "' ORDER BY " & elCampoOrden)
...
End Function

Pero como te decía, la función de Jesus te evita tener que hacer todo este rollo, y te servirá para cualquier tabla que tengas.

Muchísimas gracias de nuevo Sveinbjorn. Trabajaré sobre tu explicación y también sobre el ejemplo de Jesús.

Una cosa más, en la caí después:

Cuando intentabas crear distintas funciones para cada tabla ¿les ponías nombres distintos a cada función? Cada función y procedimiento tiene que tener un nombre único en su ámbito de actuación. Simplemente para que lo sepas.

Un saludo


Respuesta
1

Supongamos que la tabla Clientes tiene Idcliente, cliente, país y un campo Orden. Con esa tabla haz un formulario(da igual único o continuo) y en vista diseño ponle un botón de comando y en sus propiedades-eventos.al hacer clic, con el generador crea un procedimiento de evento y entre Private Sub y End Sub escribe

DoCmd.SetWarnings False
Dim i As Integer
For i = 1 To Form.Recordset.RecordCount
Orden = DCount("pais", "clientes", "idcliente<=forms!clientes!idcliente and pais=forms!clientes!pais")
DoCmd.GoToRecord , , acNext
Next

Docmd. Gotorecord,, acfirst

Te explico

Al pulsar el botón se va al primer registro. Ahí cuenta cuantos registros hay en la tabla con ese país y CON UN IDCLIENTE menor o igual que el que está activo en ese momento. Le asigna un valor al cuadro Orden. Se va al siguiente registro, etc. hasta que llegue al último, hace lo mismo y se vuelve al primer registro.

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas