Régóta kerestem annak a megoldását, hogyan lehet MSSQL-ben megvalósítani általában a MySQL-ben régóta meglévő LIMIT klauzulát. Ezt olyan esetben használjuk, hogyha nem szeretnénk, hogy a szerver oldalról a teljes rekordszet átjöjjön kliens oldalra. Hosszas keresgélés után rátaláltam a Microsoft SQL 2005-ben bevezetett row_number() függvényre, de annak sajnos egy kis szépséghibája van. Ha a sorok nem egyediek, akkor véletlenszerűen ad a soroknak sorszámot. Ekkor jutott eszembe, hogy a Drupal 7-ben írtak mssql adatbázis drivert és annak a kódját nézegetve kaptam az alábbi megoldást:
Tegyük fel, hogy $n jelenti a kezdősorszámot, ahonnan szeretném a rekordokat megkapni és $db jelenti a lekérendő darabszámot. legyen $sql az eredeti sql utasítás, aminek az eredményéből szeretném a megadott rekordokat megjeleníteni. Ekkor PHP-ban az alábbi sql-t kell összeállítani:
$sql1 = "SeleCT * FROM (
SeleCT q2.*, ROW_NUMBER() OVER(ORDER BY q2._l2) AS _l3 FROM (
SeleCT 1 AS _l2, q1.* FROM (' . $sql . ') AS q1
) AS q2
) AS q3
WHERE _l3 BETWEEN ' . ($n + 1) . " AND " . ($n + $db);
Hogyan működik?
Az eredeti lekérdezést, mint allekérdezést használva hozzáteszek egy oszlopot (_l2), amely csupa 1-es értéket tartalmaz.
Az így kapott q1 lekérdezés lesz az allekérdezése a q2 lekérdezésnek, amelyben a sorszámozás sorrendjét a _l2 oszlop határozza meg.
Egyetlen bökkenő van még. Allekérdezésben csak akkor lehet ORDER BY, ha szerepel a TOP is. Az eredeti lekérdezésünknek tehát így kell kinéznie:
"SeleCT TOP 100000000 * FROM tabla WHERE .... ORDER BY ....."
A fentiek után egy működő lapozható lekérdezést kapunk.
Az ötlet innen származik: http://drupal.org/project/sqlsrv