Когда я работал над компонентом базы данных 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 @offset+@count;
Однако Microsoft SQL Server 2000 не имеет функции ROW_NUMBER()
.
Итак, мой вопрос: вы можете придумать способ эмулировать функциональность LIMIT
в Microsoft SQL Server 2000, используя только SQL? Без использования курсоров или T-SQL или хранимой процедуры. Он должен поддерживать оба аргумента для LIMIT
, как количество, так и смещение. Решения с использованием временной таблицы также неприемлемы.
Изменить:
Наиболее распространенное решение для 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
);
Вывод:
Похоже, что нет универсального решения для эмуляции LIMIT
в MS SQL Server 2000. Хорошее решение существует, если вы можете использовать функцию ROW_NUMBER()
в MS SQL Server 2005.