MSSQL lapozás létrehozása LIMIT

Default book

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