web-dev-qa-db-fra.com

Équivalent de LIMIT pour DB2

Comment procédez-vous LIMIT dans DB2 pour iSeries? 

J'ai une table avec plus de 50 000 enregistrements et je veux renvoyer des enregistrements de 0 à 10 000 et des enregistrements de 10 000 à 20 000.

Je sais qu'en SQL, vous écrivez LIMIT 0,10000 à la fin de la requête pour 0 à 10 000 et LIMIT 10000,10000 à la fin de la requête pour 10 000 à 20 000 

Alors, comment cela se fait-il dans DB2? Quel est le code et la syntaxe? (Un exemple de requête complet est apprécié)

83
elcool

Développé cette méthode:

Vous avez besoin d'une table qui a une valeur unique qui peut être commandée.

Si vous voulez des rangées 10 000 à 25 000 et que votre table compte 40 000 rangées, vous devez d’abord obtenir le point de départ et le total des rangées:

int start = 40000 - 10000;

int total = 25000 - 10000;

Et puis passez ces par code à la requête:

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
12
elcool

Utiliser 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;

Pour obtenir des plages, vous devez utiliser ROW_NUMBER() (depuis la v5r4) et utiliser celui-ci dans la clause WHERE: (volé à partir d'ici: 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;
132
Joe

La prise en charge de OFFSET et LIMIT a récemment été ajoutée à DB2 pour i 7.1 et 7.2. Vous avez besoin des niveaux de groupe DB PTF suivants pour obtenir cette prise en charge:

  • SF99702 niveau 9 pour IBM i 7.2
  • SF99701 niveau 38 pour IBM i 7.1

Voir ici pour plus d'informations: OFFSET et LIMIT documentation , DB2 for i Enhancement Wiki

8
Kevin Adler

Voici la solution que j'ai trouvée:

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

En initialisant LASTVAL sur 0 (ou '' pour un champ de texte), puis en le définissant sur la dernière valeur du dernier ensemble d'enregistrements, la table sera divisée en morceaux de N.

5
Tom Barron

La solution de @ elcool est une bonne idée, mais vous devez connaître le nombre total de lignes (qui peut même changer pendant l'exécution de la requête!). Je propose donc une version modifiée, qui nécessite malheureusement 3 sous-requêtes au lieu de 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} doit être remplacé par le numéro de ligne du dernier enregistrement dont j'ai besoin et {length} doit être remplacé par le nombre de lignes dont j'ai besoin, calculé sous la forme last row - first row + 1.

Par exemple. si je veux des lignes de 10 à 25 (au total 16 lignes), {last} sera 25 et {length} sera 25-10 + 1 = 16.

2
bluish

Vous devriez également envisager la clause OPTIMIZE FOR n ROWS. Plus de détails sur tout cela dans la documentation DB2 LUW dans le Instructions pour restreindre les instructions SELECT topic:

  • La clause OPTIMIZE FOR déclare l'intention de ne récupérer qu'un sous-ensemble du résultat ou de donner la priorité à la récupération des premières lignes. L'optimiseur peut ensuite choisir des plans d'accès qui minimisent le temps de réponse pour l'extraction des premières lignes.
1
David Sky

Essaye ça

SELECT * FROM
    (
        SELECT T.*, ROW_NUMBER() OVER() R FROM TABLE T
    )
    WHERE R BETWEEN 10000 AND 20000
1
Lucio Menci

Il existe 2 solutions pour paginer efficacement sur une table DB2:

1 - la technique utilisant la fonction row_number () et la clause OVER qui a été présentée sur un autre poste ("SELECT row_number () OVER (ORDER BY ...)"). Sur certaines grandes tables, j'ai parfois remarqué une dégradation des performances.

2 - la technique utilisant un curseur déroulant. L'implémentation dépend du langage utilisé. Cette technique semble plus robuste sur les grandes tables.

J'ai présenté les 2 techniques mises en œuvre dans PHP lors d'un séminaire l'année prochaine. La diapositive est disponible sur ce lien: http://gregphplab.com/serendipity/uploads/slides/DB2_PHP_Best_practices.pdf

Désolé mais ce document n'est qu'en français.

0
gregphplab

Theres ces options disponibles: -

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.  
0
Hector