viernes, 17 de octubre de 2008

NUMERAR REGISTROS EN BASE A UN CAMPO CON REPETICIONES


En el ejemplo anterior : http://sqlraipon.blogspot.com/2008/09/devolver-n-registros.html, utilizábamos una subconsulta para contar los registros con un valor 'menor', tomando como referencia uno de los campos. Este campo, debía cumplir dos condiciones : que el orden que se establece al utilizarlo como referencia, coincida con nuestro criterio para numerar los resultados de la consulta, y que no tenga valores duplicados.

Vamos a intentar numerar los resultados de una consulta, tomando como referencia para la precedencia entre registros uno de sus campos :

Create Table MiTbl (Id Counter Primary Key, Fecha DateTime);

Insert Into MiTbl (Fecha) Values(#10/02/2007#);
Insert Into MiTbl (Fecha) Values(#10/01/2008#);
Insert Into MiTbl (Fecha) Values(#10/03/2007#);
Insert Into MiTbl (Fecha) Values(#10/04/2007#);
Insert Into MiTbl (Fecha) Values(#10/10/2007#);
Insert Into MiTbl (Fecha) Values(#01/20/2007#);

SELECT * FROM(
Select(
Select Count(*) From MiTbl As T Where T.Fecha <= MiTbl.Fecha
) As Numerador,
MiTbl.*
From MiTbl
)
ORDER BY Numerador;

Drop Table MiTbl;

... los resultados devueltos son correctos (si queremos numerar según fecha), pero qué ocurre si hay fechas duplicadas ...

Create Table MiTbl (Id Counter Primary Key, Fecha DateTime);

Insert Into MiTbl (Fecha) Values(#10/02/2007#);
Insert Into MiTbl (Fecha) Values(#10/01/2008#);
Insert Into MiTbl (Fecha) Values(#10/03/2007#);
Insert Into MiTbl (Fecha) Values(#10/04/2007#);
Insert Into MiTbl (Fecha) Values(#10/10/2007#);
Insert Into MiTbl (Fecha) Values(#10/10/2007#);

SELECT * FROM
(
Select
(
Select Count(*) From MiTbl As T Where T.Fecha <= MiTbl.Fecha
) As Numerador,
MiTbl.*
From MiTbl
)
ORDER BY Numerador;

Drop Table MiTbl;

... no hay Numerador = 4 y sin embargo hay dos registros con Numerador = 5. ¿ Cómo solucionarlo ? ... Tomando para la comparación tantos campos como sea preciso para crear valores únicos. En este caso incorporaremos el campo Id a la subconsulta :
Create Table MiTbl (Id Counter Primary Key, Fecha DateTime);

Insert Into MiTbl (Fecha) Values(#10/02/2007#);
Insert Into MiTbl (Fecha) Values(#10/01/2008#);
Insert Into MiTbl (Fecha) Values(#10/03/2007#);
Insert Into MiTbl (Fecha) Values(#10/04/2007#);
Insert Into MiTbl (Fecha) Values(#10/10/2007#);
Insert Into MiTbl (Fecha) Values(#10/10/2007#);

SELECT * FROM(
Select
(
Select Count(*) From MiTbl As T
Where CSng(T.Fecha) & T.Id <= CSng(MiTbl.Fecha) & MiTbl.Id
) As Numerador,
MiTbl.*
From MiTbl
)
ORDER BY Numerador;

Drop Table MiTbl;

... los valores del campo Numerador ya son coherentes, a pesar de que ordenemos por Fecha, y que para esta columna existan valores repetidos. Cabe destacar que Access realiza de forma implícita cambios en el tipo de datos (en campos calculados). Por ejemplo esta expresión : UnaFecha & UnNúmero lo convierte en texto. Para establecer un orden correcto, esto no supone ningún problema excepto si empleamos campos Fecha/Hora (nuestro caso, ¡ Qué mala suerte !), en cuyo caso el orden alfabético no coincide con el orden según Fecha (#20/10/2008# > #21/10/2007#, pero '20/10/2008' < '21/10/2007'). Para sortear esta dificultad, es preferible convertir las fechas a Single (CSng(#20/10/2008#) = 39741, CSng(#21/10/2007#) = 39376), de hecho, Access almacena internamente las Fechas como Single, siendo la parte entera los dias transcurridos desde el 31 de Diciembre de 1899, y la fracción decimal : Horas, minutos, segundos ...

Ramon Poch. Terrassa a 10/10/2008.