Как ограничить количество строк, возвращаемых запросом Oracle после заказа?
Есть ли способ заставить запрос Oracle
вести себя так, как будто он содержит условие MySQL limit
?
В MySQL
я могу это сделать:
select *
from sometable
order by name
limit 20,10
чтобы получить 21-е и 30-е ряды (пропустите первые 20, дайте следующие 10). Строки выбираются после order by
, поэтому он действительно начинается с 20-го имени в алфавитном порядке.
В Oracle
единственное, о чем люди rownum
псевдо-столбец rownum
, но он оценивается перед order by
, что означает:
select *
from sometable
where rownum <= 10
order by name
вернет случайный набор из десяти строк, упорядоченных по имени, что обычно не является тем, что я хочу. Он также не позволяет указывать смещение.
Ответы
Ответ 1
Начиная с Oracle 12c R1 (12.1) существует предложение ограничения строки. Он не использует знакомый синтаксис LIMIT
, но он может улучшить работу с большим количеством опций. Здесь вы можете найти полный синтаксис .
Чтобы ответить на исходный вопрос, вот запрос:
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
(Для более ранних версий Oracle см. другие ответы в этом вопросе)
Примеры:
Следующие примеры были указаны на странице связанной с тем, чтобы предотвратить гниение ссылки.
Настройка
CREATE TABLE rownum_order_test (
val NUMBER
);
INSERT ALL
INTO rownum_order_test
SELECT level
FROM dual
CONNECT BY level <= 10;
COMMIT;
Что в таблице?
SELECT val
FROM rownum_order_test
ORDER BY val;
VAL
----------
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
20 rows selected.
Получить первые N
строки
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY;
VAL
----------
10
10
9
9
8
5 rows selected.
Получить первые строки N
, если строка N
th имеет связи, получить все связанные строки
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS WITH TIES;
VAL
----------
10
10
9
9
8
8
6 rows selected.
Верх x
% строк
SELECT val
FROM rownum_order_test
ORDER BY val
FETCH FIRST 20 PERCENT ROWS ONLY;
VAL
----------
1
1
2
2
4 rows selected.
Использование смещения, очень полезно для разбивки на страницы
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY;
VAL
----------
3
3
4
4
4 rows selected.
Вы можете комбинировать смещение с процентами
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 20 PERCENT ROWS ONLY;
VAL
----------
3
3
4
4
4 rows selected.
Ответ 2
Вы можете использовать подзапрос для этого, например
select *
from
( select *
from emp
order by sal desc )
where ROWNUM <= 5;
Также посмотрите дополнительную информацию о теме В ROWNUM и ограничьте результаты в Oracle/AskTom.
Обновление:
Чтобы ограничить результат как нижними, так и верхними границами, все становится немного раздутым с помощью
select * from
( select a.*, ROWNUM rnum from
( <your_query_goes_here, with order by> ) a
where ROWNUM <= :MAX_ROW_TO_FETCH )
where rnum >= :MIN_ROW_TO_FETCH;
(скопировано из указанной статьи AskTom)
Обновление 2:
Начиная с Oracle 12c (12.1) существует синтаксис, доступный для ограничения строк или запуска при смещениях.
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
Подробнее см. этот ответ. Спасибо Крумии за подсказку.
Ответ 3
Я провел несколько тестов производительности для следующих подходов:
Asktom
select * from (
select a.*, ROWNUM rnum from (
<select statement with order by clause>
) a where rownum <= MAX_ROW
) where rnum >= MIN_ROW
аналитический
select * from (
<select statement with order by clause>
) where myrow between MIN_ROW and MAX_ROW
Короткая альтернатива
select * from (
select statement, rownum as RN with order by clause
) where a.rn >= MIN_ROW and a.rn <= MAX_ROW
Результаты
В таблице было 10 миллионов записей, сортировка была в неиндексированной строке datetime:
- Объяснение плана показало одинаковое значение для всех трех выборок (323168)
- Но победитель - AskTom (с аналитикой, близким позади)
Выбор первых 10 строк:
- AskTom: 28-30 секунд
- Аналитический: 33-37 секунд
- Короткий вариант: 110-140 секунд
Выбор строк между 100 000 и 100,010:
- AskTom: 60 секунд
- Аналитический: 100 секунд
Выбор строк между 9,000,000 и 9,000,010:
- AskTom: 130 секунд
- Аналитический: 150 секунд
Ответ 4
Аналитическое решение с одним вложенным запросом:
SELECT * FROM
(
SELECT t.*, Row_Number() OVER (ORDER BY name) MyRow FROM sometable t
)
WHERE MyRow BETWEEN 10 AND 20;
Rank()
может быть заменен на Row_Number()
, но может возвращать больше записей, чем вы ожидаете, если есть повторяющиеся значения для имени.
Ответ 5
В Oracle 12c (см. предложение ограничения строки в ссылка SQL):
SELECT *
FROM sometable
ORDER BY name
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY;
Ответ 6
Запросы разбивки на страницы с упорядочением действительно сложны в Oracle.
Oracle предоставляет псевдокоманду ROWNUM, которая возвращает номер, указывающий порядок, в котором база данных выбирает строку из таблицы или набора объединенных представлений.
ROWNUM - это псевдоколонка, в которую попадают многие люди. Значение ROWNUM не назначается подряд подряд (это общее недоразумение). Это может сбивать с толку, когда действительно назначено значение ROWNUM. Значение ROWNUM присваивается строке после передачи предикатов фильтра запроса, но до агрегации или сортировки запроса.
Кроме того, значение ROWNUM увеличивается только после его назначения.
Вот почему запрос followin не возвращает строк:
select *
from (select *
from some_table
order by some_column)
where ROWNUM <= 4 and ROWNUM > 1;
Первая строка результата запроса не проходит предикат ROWNUM > 1, поэтому ROWNUM не увеличивается до 2. По этой причине значение ROWNUM не превышает 1, следовательно, запрос не возвращает строк.
Правильно определенный запрос должен выглядеть так:
select *
from (select *, ROWNUM rnum
from (select *
from skijump_results
order by points)
where ROWNUM <= 4)
where rnum > 1;
Узнайте больше о запросах разбивки на страницы в статьях Vertabelo:
Ответ 7
Меньше операторов SELECT. Кроме того, снижение производительности. Кредиты к: [email protected]
SELECT *
FROM (SELECT t.*,
rownum AS rn
FROM shhospede t) a
WHERE a.rn >= in_first
AND a.rn <= in_first;
Ответ 8
Если вы не используете Oracle 12C, вы можете использовать запрос TOP N, например, ниже.
SELECT *
FROM
( SELECT rownum rnum
, a.*
FROM sometable a
ORDER BY name
)
WHERE rnum BETWEEN 10 AND 20;
Вы можете даже перенести это из предложения в с предложением следующим образом
WITH b AS
( SELECT rownum rnum
, a.*
FROM sometable a ORDER BY name
)
SELECT * FROM b
WHERE rnum BETWEEN 10 AND 20;
Здесь мы фактически создаем встроенный просмотр и переименование rownum как rnum. Вы можете использовать rnum в основном запросе в качестве критериев фильтра.
Ответ 9
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID=5
больше значений, найденных
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID>5
меньше значений, найденных
select * FROM (SELECT
ROW_NUMBER() OVER (ORDER BY sal desc),* AS ROWID,
FROM EMP ) EMP where ROWID=5
Ответ 10
В качестве расширения принятого ответа Oracle внутренне использует функции ROW_NUMBER/RANK
. Синтаксис OFFSET FETCH
является синтаксическим сахаром.
Это можно наблюдать с помощью процедуры DBMS_UTILITY.EXPAND_SQL_TEXT
:
Подготовка образца:
CREATE TABLE rownum_order_test (
val NUMBER
);
INSERT ALL
INTO rownum_order_test
SELECT level
FROM dual
CONNECT BY level <= 10;
COMMIT;
запрос:
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY;
регулярно:
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
ROW_NUMBER() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rownumber"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rownumber"<=5 ORDER BY "A1"."rowlimit_$_0" DESC;
db & lt;> демонстрация скрипки
Извлечение расширенного текста SQL:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS ONLY',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
WITH TIES
расширяется как RANK
:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val DESC
FETCH FIRST 5 ROWS WITH TIES',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
RANK() OVER ( ORDER BY "A2"."VAL" DESC ) "rowlimit_$$_rank"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rank"<=5 ORDER BY "A1"."rowlimit_$_0" DESC
и смещение:
declare
x VARCHAR2(1000);
begin
dbms_utility.expand_sql_text(
input_sql_text => '
SELECT val
FROM rownum_order_test
ORDER BY val
OFFSET 4 ROWS FETCH NEXT 4 ROWS ONLY',
output_sql_text => x);
dbms_output.put_line(x);
end;
/
SELECT "A1"."VAL" "VAL"
FROM (SELECT "A2"."VAL" "VAL","A2"."VAL" "rowlimit_$_0",
ROW_NUMBER() OVER ( ORDER BY "A2"."VAL") "rowlimit_$$_rownumber"
FROM "ROWNUM_ORDER_TEST" "A2") "A1"
WHERE "A1"."rowlimit_$$_rownumber"<=CASE WHEN (4>=0) THEN FLOOR(TO_NUMBER(4))
ELSE 0 END +4 AND "A1"."rowlimit_$$_rownumber">4
ORDER BY "A1"."rowlimit_$_0"
Ответ 11
I'v начал подготовку к экзамену Oracle 1z0-047, проверенному против 12c
Во время подготовки к этому я наткнулся на расширение 12c, известное как "FETCH FIRST"
Это позволяет вам извлекать строки/ограничивать строки в соответствии с вашим удобством.
Доступно несколько опций
- FETCH FIRST n ROWS ONLY
- OFFSET n ROWS FETCH NEXT N1 ROWS ONLY // leave the n rows and display next N1 rows
- n % rows via FETCH FIRST N PERCENT ROWS ONLY
Пример:
Select * from XYZ a
order by a.pqr
FETCH FIRST 10 ROWS ONLY
Ответ 12
Для каждой строки, возвращаемой запросом, псевдостолбец ROWNUM возвращает число, указывающее порядок, в котором Oracle выбирает строку из таблицы или набора соединенных строк. Первый выбранный ряд имеет ROWNUM, равный 1, второй - 2 и т.д.
SELECT * FROM sometable1 so
WHERE so.id IN (
SELECT so2.id from sometable2 so2
WHERE ROWNUM <=5
)
AND ORDER BY so.somefield AND ROWNUM <= 100
Я реализовал это на сервере oracle
11.2.0.1.0
Ответ 13
Стандарт SQL
Как я объяснял в этой статье, стандарт SQL: 2008 предоставляет следующий синтаксис для ограничения набора результатов SQL:
SELECT
title
FROM
post
ORDER BY
id DESC
FETCH FIRST 50 ROWS ONLY
Oracle 11g и более ранние версии
До версии 12c для получения записей Top-N необходимо было использовать производную таблицу и псевдостолбец ROWNUM:
SELECT *
FROM (
SELECT
title
FROM
post
ORDER BY
id DESC
)
WHERE ROWNUM <= 50
Ответ 14
В оракуле
SELECT val FROM rownum_order_test ORDER BY val DESC FETCH FIRST 5 ROWS ONLY;
VAL
10
10
9
9
8
Выбрано 5 строк.
SQL >
Ответ 15
Я использовал Oracle SQL Developer следующую инструкцию для извлечения первых 10 строк и работает для меня:
SELECT * FROM <table name> WHERE ROWNUM < = 10 ORDER BY <column name>;
Ответ 16
(непроверенный) что-то вроде этого может выполнить работу
WITH
base AS
(
select * -- get the table
from sometable
order by name -- in the desired order
),
twenty AS
(
select * -- get the first 30 rows
from base
where rownum < 30
order by name -- in the desired order
)
select * -- then get rows 21 .. 30
from twenty
where rownum > 20
order by name -- in the desired order
Существует также ранг аналитической функции, который вы можете использовать для заказа.
Ответ 17
То же, что и выше, с исправлениями. Работает, но определенно не очень.
WITH
base AS
(
select * -- get the table
from sometable
order by name -- in the desired order
),
twenty AS
(
select * -- get the first 30 rows
from base
where rownum <= 30
order by name -- in the desired order
)
select * -- then get rows 21 .. 30
from twenty
where rownum < 20
order by name -- in the desired order
Честно говоря, лучше использовать приведенные выше ответы.