Underligheder i listevisninger
Har du nogensinde prøvet at trykke en side frem på en hjemmesides søgeside, bare for at se det sidste resultat fra den foregående side, stå øverst på den næste side du kommer til?
Billedet er lavet af mcmurryjulie og hentet fra PixaBay.
I forbindelse med et projekt, har jeg kigget lige på præcis den funktionalitet. Normalt ser databasekoden åbenbart sådan her ud, for de første 10 resultater:
SELECT * FROM product LIMIT 10;
Sagt på dansk, så skal alle resultaterne fra tabellen produkter hentes, omend kun de første 10 skal overføres fra databasen til programmet. Man bør dog fortælle databasen at resultaterne skal sorteres, for der er ikke nogen garanti for, at den overstående kode henter de samme 10 resultater hver gang. Det kan gøres med ORDER:
SELECT * FROM products ORDER BY price DESC LIMIT 10;
Ok, så langt så godt. Nu hentes de 10 første produkter, sorteret efter pris. Trykker man så på “Vis næste side”-knappen, kunne koden se sådan her ud:
SELECT * FROM products ORDER BY price DESC LIMIT 10 OFFSET 10;
Der bliver stadig kun hentet 10 resultater, men nu bliver de første 10 sprunget over, så det er resultaterne 11 til 20 der bliver hentet. Og det er her problemet kommer ind.
For hvis man går ind på hjemmesiden og sidder og læser på de 10 første resultater, så kan en eller anden jo ligge et nyt produkt ind i databasen imens, som har en pris der gør at den bliver vist blandt de første 10 resultater, som jo også er de 10 billigste resultater. Når der så bliver trykket “Næste”, vil det 10. produkt være blevet det 11., og dermed både blive vist som det sidste produkt på den første side, og det første produkt på den anden side.
Umiddelbart har jeg ikke kunne søge mig frem til en løsning. Jeg ser jævnligt at det sker på store og aktive hjemmesider, så det er åbenbart ikke noget man normalt løser. I det store og hele betyder det nok heller ikke så meget, men alligevel. Det gør mig lidt nysgerrig efter at finde en mulig løsning.
HTTP, altså den protokol computere bruger til at udveksle hjemmesider med, kan ikke bruges til at differentiere de besøgende. Så hvis serveren skal holde styr på hvem der ser hvad, skal klienten være logget ind. Og det er ikke sikkert at det er en god idé, at man skal være logget ind for at se en webshops sortiment.
Så løsningen bør nok ligge i den hjemmeside der bliver sendt til klienten. Man kunne fx indlejre en ikke-standard attribut i den HTML-formular, som skal vise næste side, hvor tidspunktet for hvornår klienten fik vist listen er inkluderet. UNIX-time ville være en oplagt mulighed, og ville kunne udnytte WHERE i databasekoden:
SELECT * FROM products WHERE date <= $time ORDER BY price DESC LIMIT 10 OFFSET 10;
Nogle væsentlige pointer inkluderer
- Nej, du må aldrig bruge variabler direkte i SQL
- Brug placeholders i stedet for
- Den returnerede UNIX-time skal valideres grundigt
- Ligesom alt andet data
- Koden er ment som et koncept; den skal ikke bruges som den står
Desuden virker koden ganske givet ikke, for indholdet af variablen skal konverteres til korrekt SQL format inden den kan afvikles. Men som koncept burde det være en mulig løsning. Der er sikkert også andre løsninger, hvis det overhovedet giver mening at løse det. I stedet for at skubbe til resultatlisten, bliver et nyt produkt måske vist til brugeren, og giver et salg.
// Nicky