domingo, 1 de febrero de 2009

FIRST Y LAST


Si utilizamos estas funciones en una instrucción sql que apunte directamente sobre una tabla :

Create Table MiTabla (Campo1 Text (100));

Insert Into MiTabla Values ('Hola mundo');
Insert Into MiTabla Values ('Prueba first y last');
Insert Into MiTabla Values ('Fin de la prueba');

Select First(Campo1) As Primero, Last(Campo1) As Último
From MiTabla;

Drop Table MiTabla;

... vemos que los resultados son absolutamente coherentes : first devuelve el valor para dicho campo del primer registro insertado en la tabla, y viceversa ...
Sin embargo, estos resultados no se ven afectados si establecemos un orden concreto desde la vista 'hoja de datos' de la tabla. Es decir, si desde dicha vista establecemos un orden ascendente (alfabético) para campo1, y guardamos los cambios, First sigue devolviendo 'Hola mundo' en vez de 'Fin de prueba'. ¿ Significa esto que no podemos definir otro criterio de ordenación para establecer qué valor es primero o último ?. En la ayuda de Access podemos leer :

"... Devuelven simplemente el valor de un campo especificado en el primer o el último registro, respectivamente, del conjunto de resultados devueltos por una consulta. Debido a que los registros se devuelven normalmente sin un orden determinado (a no ser que la consulta incluya una cláusula ORDER BY), los registros devueltos por estas funciones son arbitrarios."

... vamos a probar :

Select First(Campo1) As Primero, Last(Campo1) As Último
From
(
Select Campo1
From MiTabla
Order By Campo1
);

... pues no, no es cierto, o no quiere decir lo que parece; nada ha cambiado. Y da igual que guardemos la consulta embebida dentro de la cláusula From como una nueva consulta, que establezcamos también el orden desde la vista 'hoja de datos' de esta nueva consulta, ... nada, ¡ es inútil !. Sencillamente : el orden establecido en una instrucción 'Select', no es persistente para posteriores llamadas a la misma.
Si pensamos en ello detenidamente, este comportamiento es del todo lógico, ya que el orden de los resultados solo debe ser relevante en cuanto a una mejor interpretación de los mismos, pero no para la validez de los datos devueltos. Y en cambio, ordenar los registros para cada 'Select' en una serie de llamadas entre consultas, penalizaría sin duda el rendimiento. Sin embargo hay un escenario en donde los registros devueltos pueden ser distintos según el criterio establecido en 'Order By' : ... cuando usamos la cláusula Top para restringir los resultados a un determinado número de registros. ¿ Solucionará también la cláusula Top nuestro problema ?. Efectivamente, si utilizamos dicha cláusula, el orden permanece para una posterior llamada a la consulta :

Select First(Campo1) As Primero, Last(Campo1) As Último
From
(
Select Top 100 Percent Campo1
From MiTabla
Order By Campo1
);

... y ahora sí, el valor devuelto por First es 'Fin de la prueba' y Last : 'Prueba first y last'. Valores coherentes si ordenamos alfabéticamente 'Campo1'. En conclusión : siempre que utilicemos dichas funciones, si queremos resultados consistentes y fiables debemos basar la sql sobre una consulta previa que incorpore la cláusula 'Top' (a no ser que deseemos recuperar valores directamente de la tabla según el orden de inserción).

Ramon Poch. Terrassa a 20/12/2008.