Еквівалент LIMIT для DB2


91

Як ви працюєте 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 ().
Paul Morgan,

RRN () абсолютно відрізняється від row_number ().
Брендон Петерсон,

не працював у мене. Помилка Sytanx.
elcool

1
Спробуйте RRN (ім'я файлу), який дасть фізичний відносний номер запису рядка. RRN не буде послідовним і може пропускати числа, якщо рядки були видалені. RRN також не буде послідовним за ключем, але буде послідовним на основі додавання, якщо видалення не відбулося. У будь-якому випадку RRN буде унікальним для рядка і може бути використаний для вибору підмножин таблиці.
Paul Morgan,

1
DB2 забезпечуючи підтримку обмеження ключових слів з DB2 9.7.2 в відповідно до programmingzen.com/2010/06/02 / ...
Лакшмана

Відповіді:


139

Використання 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

2
Ви повинні зробити щось подібне з РЯДКОМ НОМЕР
Джо

ROW_NUMBERне є дійсним ключовим словом. Але за посилання, це дало мені уявлення, і воно працює.
elcool

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_ рядка () ЗА (ЗАМОВИТИ ПО).
мануна

9

Підтримка OFFSET та LIMIT нещодавно була додана до DB2 для i 7.1 та 7.2. Вам потрібні наступні рівні групи PTF DB, щоб отримати цю підтримку:

  • SF99702 рівень 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очевидно, буде проблематично, якщо стовпець містить від’ємне значення. Буде потрібна обережність з нулями. Не буде працювати, якщо сторінки пропускатимуться.
Завод-муза

Дякую за коментар. Я думаю, існує неявне припущення, що поле, яке ми використовуємо для управління запитом, є унікальним і монотонно зростаючим. Я погоджуюсь, що якщо ці припущення не виконуються, це не спрацює, щоб переглянути всі записи в таблиці. І, звичайно, ви праві, що вам довелося б почати з LASTVAL, який має сенс. Загалом, я думаю, ви хотіли б почати з того, що повертається "виберіть МІНІМУМ (ПОЛЕ) з ТАБЛИЦІ". Якщо поле проіндексовано, більшість двигунів db буде працювати краще, ніж читати всю таблицю послідовно.
Том Баррон

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 оголошує про намір отримати лише підмножину результату або надати пріоритет отриманню лише перших кількох рядків. Потім оптимізатор може вибрати плани доступу, які мінімізують час відгуку на отримання перших кількох рядків.


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

Вибачте, але цей документ є лише французькою.


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.  
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.