Когда я работал над компонентом базы данных Zend Framework, мы попытались абстрагировать функциональность предложения LIMIT
, поддерживаемого MySQL, PostgreSQL, и SQLite. То есть создание запроса может быть выполнено следующим образом:
$select = $db->select();
$select->from('mytable');
$select->order('somecolumn');
$select->limit(10, 20);
Когда база данных поддерживает LIMIT
, это создает SQL-запрос, например:
SELECT * FROM mytable ORDER BY somecolumn LIMIT 10, 20
Это было более сложным для брендов базы данных, которые не поддерживают LIMIT
(это предложение, кстати, не является частью стандартного языка SQL). Если вы можете сгенерировать номера строк, сделайте весь запрос производной таблицей, а во внешнем запросе используйте BETWEEN
. Это было решение для Oracle и IBM DB2. Microsoft SQL Server 2005 имеет аналогичную функцию номера строки, поэтому можно написать запрос таким образом:
SELECT z2.*
FROM (
SELECT ROW_NUMBER OVER(ORDER BY id) AS zend_db_rownum, z1.*
FROM ( ...original SQL query... ) z1
) z2
WHERE z2.zend_db_rownum BETWEEN @offset+1 AND @[email protected];
Однако Microsoft SQL Server 2000 не имеет функции ROW_NUMBER()
.
Итак, мой вопрос: можете ли вы придумать способ эмулировать функциональность LIMIT
в Microsoft SQL Server 2000, используя только SQL? Без использования курсоров или T-SQL или хранимой процедуры. Он должен поддерживать оба аргумента для LIMIT
, как count, так и offset. Решения, использующие временную таблицу, также неприемлемы.
Edit:
Наиболее распространенное решение для MS SQL Server 2000 похоже на приведенное ниже, например, для получения строк с 50 по 75:
SELECT TOP 25 *
FROM (
SELECT TOP 75 *
FROM table
ORDER BY BY field ASC
) a
ORDER BY field DESC;
Однако это не работает, если общий набор результатов, скажем, 60 строк. Внутренний запрос возвращает 60 строк, потому что в верхнем 75. Затем внешний запрос возвращает строки 35-60, которые не соответствуют желаемой "странице" 50-75. В принципе, это решение работает, если вам не нужна последняя "страница" набора результатов, которая не будет кратной размеру страницы.
Edit:
Другое решение работает лучше, но только если вы можете предположить, что набор результатов включает уникальный столбец:
SELECT TOP n *
FROM tablename
WHERE key NOT IN (
SELECT TOP x key
FROM tablename
ORDER BY key
);
Вывод:
В MS SQL Server 2000 не существует универсального решения для эмуляции LIMIT
. Хорошее решение существует, если вы можете использовать функцию ROW_NUMBER()
в MS SQL Server 2005.