Abbiamo detto in precedenza che lo standard SQL non prevede una sintassi per ottenere solo una parte dei record estratti da una SELECT. Inoltre abbiamo visto come MySQL adotti una soluzione proprietaria attraverso le clausole LIMIT e OFFSET.
Del resto MySQL non è l'unico RDBMS con cui PHP può interagire quindi vediamo ora come risolvere il problema dell'estrazione di una pagina di dati con i più diffusi database relazionali.
PostgreSQL e SQLite adottano una sintassi molto simile a quella di MySQL, basata su LIMIT e OFFSET:
SELECT ... LIMIT n OFFSET m
Maggiori informazioni si trovano sulle rispettive documentazioni ufficiali:
http://www.postgresql.org/docs/8.2/interactive/queries-limit.html
http://www.sqlite.org/lang_select.html
Oracle, Microsoft SQL Server e IBM DB2 invece non adottano una sintassi particolare per l'estrazione paginata dei dati pertanto è necessario adottare qualche stratagemma.
Con Microsoft SQL Server 2005 è stata introdotta la funzione ROW_NUMBER() in grado di assegnare un numero crescente ad ogni record estratto dalla SELECT secondo il particolare ordinamento dichiarato. Grazie a questo numero è poi possibile utilizzare la clausola WHERE per selezionare i record da estrarre:
SELECT *
FROM (
SELECT TOP 30 ROW_NUMBER() OVER (ORDER BY ...) AS row, ... FROM ...
) AS tab1
WHERE row >= 21 AND row <= 30
Il TOP 30 serve a migliorare le prestazioni della SELECT più interna, poiché indica al DB che siamo interessati solo alle prime 30 righe.
Con le versioni precedenti di Microsoft SQL Server è necessario seguire altre strategie, ad esempio la seguente che fa uso del SELECT TOP e dell'inversione dell'ordinamento
SELECT *
FROM (
SELECT TOP 10 *
FROM (
SELECT TOP 30 ... FROM ...ORDER BY ... ASC
) AS inner_tbl
ORDER BY DESC
) AS outer_tbl
ORDER BY ... ASC
Con Oracle possiamo seguire 2 principali tecniche, una basata sul ROWNUM e l'altra sulla funzione ROW_NUMBER(). Di seguito viene riportato un esempio per ciascuna tecnica, seguito da un link utile per ottenere maggiori informazioni.
SELECT tab2.*
FROM (
SELECT ROWNUM AS rn, tab1.*
FROM (
SELECT ... FROM ... WHERE ... ORDER BY ...
) tab1
) tab2
WHERE tab2.rn BETWEEN 21 AND 30
http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
oppure
SELECT *
FROM (
SELECT ..., ROW_NUMBER() OVER(ORDER BY ...) rn FROM ...
)
WHERE rn BETWEEN 21 and 30
ORDER BY rn
http://www.oracle.com/technology/oramag/oracle/07-jan/o17asktom.html
Anche IBM DB2 possiede la funzione ROW_NUMBER(), pertanto possiamo utilizzare un approccio simile a quelli visti in precedenza.
SELECT *
FROM
(
SELECT ..., ROW_NUMBER() OVER (ORDER BY ...) AS rn FROM ...
) AS tab1
WHERE rn BETWEEN 21 AND 30;