Эквивалент LIMIT для DB2

94

Как у вас дела LIMITс DB2 для iSeries?

У меня есть таблица с более чем 50 000 записей, и я хочу вернуть записи от 0 до 10 000 и записи от 10 000 до 20 000.

Я знаю, что в SQL вы пишете LIMIT 0,10000в конце запроса от 0 до 10000 и LIMIT 10000,10000в конце запроса от 10000 до 20000.

Итак, как это делается в DB2? Какой код и синтаксис? (приветствуется полный пример запроса)

охладиться
источник
ROW_NUMBER () реализован только в iSeries DB2 V5R4. Для предыдущих версий попробуйте использовать аналогичный RRN ().
Пол Морган
RRN () полностью отличается от row_number ().
Брэндон Петерсон,
у меня не сработало. Ошибка Sytanx.
elcool
1
Попробуйте RRN (имя файла), которое даст физический относительный номер записи строки. RRN не будет последовательным и может пропускать числа, если строки были удалены. RRN также не будет последовательным по ключу, но будет последовательным на основе добавления, если никаких удалений не произошло. В любом случае RRN будет уникальным для строки и может использоваться для выбора подмножеств таблицы.
Пол Морган,
1
DB2 обеспечивает поддержку ключевого слова limit из DB2 9.7.2 в соответствии с Programmingzen.com/2010/06/02/…
lakshman

Ответы:

142

Использование FETCH FIRST [n] ROWS ONLY:

http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/index.jsp?topic=/com.ibm.db29.doc.perf/db2z_fetchfirstnrows.htm

SELECT LASTNAME, FIRSTNAME, EMPNO, SALARY
  FROM EMP
  ORDER BY SALARY DESC
  FETCH FIRST 20 ROWS ONLY;

Чтобы получить диапазоны, вам нужно будет использовать ROW_NUMBER()(начиная с v5r4) и использовать это в WHEREпредложении: (украдено отсюда: http://www.justskins.com/forums/db2-select-how-to-123209.html )

SELECT code, name, address
FROM ( 
  SELECT row_number() OVER ( ORDER BY code ) AS rid, code, name, address
  FROM contacts
  WHERE name LIKE '%Bob%' 
  ) AS t
WHERE t.rid BETWEEN 20 AND 25;
Джо
источник
да, я тоже нашел это, хе-хе. Одновременно я редактировал вопрос, чтобы указать, что мне тоже нужны средние строки.
elcool 07
2
Вы должны сделать что-то подобное с ROW_NUMBER: justskins.com/forums/db2-select-how-to-123209.html
Джо,
ROW_NUMBERне является допустимым ключевым словом. Но спасибо за ссылку, это дало мне идею, и она работает.
elcool 07
13

Разработал этот метод:

Вам НУЖНА таблица с уникальным значением, которую можно заказать.

Если вам нужны строки от 10 000 до 25 000, а ваша таблица имеет 40 000 строк, сначала вам нужно получить начальную точку и общее количество строк:

int start = 40000 - 10000;

int total = 25000 - 10000;

А затем передайте их по коду в запрос:

SELECT * FROM 
(SELECT * FROM schema.mytable 
ORDER BY userId DESC fetch first {start} rows only ) AS mini 
ORDER BY mini.userId ASC fetch first {total} rows only
охладиться
источник
Обратите внимание, что 10000-я строка исключена из набора результатов, первая строка - это 10001-я.
голубоватый
1
Интересное решение. Я собирался использовать его для совместимости с тестовой базой данных H2 ... Но, к сожалению, он работает примерно в 30 раз медленнее, чем подход SELECT row_number () OVER (ORDER BY code).
мануна
9

Поддержка OFFSET и LIMIT была недавно добавлена ​​в DB2 for i 7.1 и 7.2. Для получения этой поддержки вам потребуются следующие уровни групп DB PTF:

  • SF99702 level 9 для IBM i 7.2
  • SF99701 уровень 38 для IBM i 7.1

Смотрите здесь для получения дополнительной информации: OFFSET и LIMIT документации , DB2 для я Enhancement Wiki

Кевин Адлер
источник
7

Вот решение, которое я придумал:

select FIELD from TABLE where FIELD > LASTVAL order by FIELD fetch first N rows only;

Инициализируя LASTVAL значением 0 (или '' для текстового поля), а затем устанавливая его на последнее значение в самом последнем наборе записей, это будет проходить через таблицу кусками по N записей.

Том Бэррон
источник
(Сначала я думал, что вы устанавливаете значение в таблице, что было бы чрезвычайно проблематично в параллельной системе) Да, это должно работать в тех случаях, когда вы выполняете последовательное чтение таблицы, хотя вам понадобится какой-то столбец разрешения конфликтов в случае, когда Nон меньше, чем количество идентичных значений в столбце (хотя это верно и при использовании ROW_NUMBER()). Начальные значения также следует выбирать с осторожностью - 0очевидно, это будет проблематично, если столбец содержит отрицательное значение. С нулевыми значениями потребуется осторожность. Не будет работать, если страницы будут пропущены.
Clockwork-Muse
Спасибо за комментарий. Я думаю, есть неявное предположение, что поле, которое мы используем для управления запросом, уникально и монотонно увеличивается. Я согласен с тем, что если эти предположения не верны, это не сработает для просмотра всех записей в таблице. И, конечно, вы правы в том, что вам нужно начать с ЛАСТВАЛА, который имеет смысл. В общем, я думаю, вы захотите начать с того, что возвращается командой «выберите МИНИМУМ (ПОЛЕ) из ТАБЛИЦЫ». Если поле проиндексировано, большинство движков БД будут работать лучше, чем читать всю таблицу последовательно.
Том Бэррон,
2

Решение @elcool - разумная идея, но вам нужно знать общее количество строк (которое может даже измениться во время выполнения запроса!). Поэтому я предлагаю модифицированную версию, которая, к сожалению, требует 3 подзапроса вместо 2:

select * from (
    select * from (
        select * from MYLIB.MYTABLE
        order by MYID asc 
        fetch first {last} rows only 
        ) I 
    order by MYID desc
    fetch first {length} rows only
    ) II
order by MYID asc

где {last}следует заменить на номер последней нужной мне записи и {length}заменить на количество строк, которое мне нужно, рассчитанное как last row - first row + 1.

Например, если мне нужны строки от 10 до 25 (всего 16 строк), {last}будет 25 и {length}будет 25-10 + 1 = 16.

голубоватый
источник
Я презираю тех, кто голосует против, когда другому человеку нужно время, чтобы ответить на их вопрос.
jp2code
1

Вам также следует рассмотреть предложение OPTIMIZE FOR n ROWS. Подробнее обо всем этом можно прочитать в документации DB2 LUW в разделе Рекомендации по ограничению операторов SELECT :

  • Предложение OPTIMIZE FOR объявляет намерение получить только подмножество результата или отдать приоритет извлечению только первых нескольких строк. Затем оптимизатор может выбрать планы доступа, которые минимизируют время отклика для получения первых нескольких строк.
Дэвид Скай
источник
1

Попробуй это

SELECT * FROM
    (
        SELECT T.*, ROW_NUMBER() OVER() R FROM TABLE T
    )
    WHERE R BETWEEN 10000 AND 20000
Лючио Менси
источник
0

Есть 2 решения для эффективной разбивки на страницы в таблице DB2:

1 - метод, использующий функцию row_number () и предложение OVER, которое было представлено в другом посте («SELECT row_number () OVER (ORDER BY ...)»). На некоторых больших столах я иногда замечал снижение производительности.

2 - техника с использованием прокручиваемого курсора. Реализация зависит от используемого языка. Этот метод кажется более надежным на больших столах.

Я представил 2 метода, реализованные в PHP, на семинаре в следующем году. Слайд доступен по этой ссылке: http://gregphplab.com/serendipity/uploads/slides/DB2_PHP_Best_practices.pdf

Извините, но этот документ только на французском языке.

gregphplab
источник
0

Доступны следующие варианты: -

DB2 has several strategies to cope with this problem.
You can use the "scrollable cursor" in feature.
In this case you can open a cursor and, instead of re-issuing a query you can FETCH forward and backward.
This works great if your application can hold state since it doesn't require DB2 to rerun the query every time.
You can use the ROW_NUMBER() OLAP function to number rows and then return the subset you want.
This is ANSI SQL 
You can use the ROWNUM pseudo columns which does the same as ROW_NUMBER() but is suitable if you have Oracle skills.
You can use LIMIT and OFFSET if you are more leaning to a mySQL or PostgreSQL dialect.  
Гектор
источник