La forma básica de tu query es ésta:
Código:
SELECT a.PIN,
a.ACCESS_DATE,
a.TYPE,
a.ACU_NUMBER,
u.USER_CODE,
u.USERS_GROUP_ID,
u.FIRST_NAME,
u.LAST_NAME
FROM access AS a
INNER JOIN users AS u
ON u.USER_CODE = a.PIN
WHERE a.ACCESS_DATE BETWEEN ? AND ?
AND a.PIN = ?
ORDER BY u.LAST_NAME
Lo que te interesa es numerar las filas del resultado de la consulta anterior. Que la consulta venga de una sola tabla o de joins no es importante para asignarles a las filas un número de orden. Incluso, aún cuando no tuvieras una columna o columnas en las cuales ordenar los resultados aún así pueden ser numerados los registros.
Código:
SELECT *
FROM (
SELECT ROW_NUMBER() OVER(ORDER BY u.LAST_NAME) AS rn,
a.PIN,
a.ACCESS_DATE,
a.TYPE,
a.ACU_NUMBER,
u.USER_CODE,
u.USERS_GROUP_ID,
u.FIRST_NAME,
u.LAST_NAME
FROM access AS a
INNER JOIN users AS u
ON u.USER_CODE = a.PIN
WHERE a.ACCESS_DATE BETWEEN ? AND ?
AND a.PIN = ?
) AS sub
WHERE rn >= 10 AND rn <= 20
En caso de no tener columnas de orden, puedes usar algo como:
Código:
ROW_NUMBER() OVER(ORDER BY (SELECT 1))
Sin embargo, lo anterior no es determinístico y es probable que aún para los mismos límites no devuelva lo mismo.
Como puedes ver es realmente sencillo. Sólo que en este momento estás acostumbrado a la forma de MySQL, que como ya te había comentado, ni siquiera es estándar. Las funciones de ranking como ROW_NUMBER() en cambio sí lo es (SQL2003).