FORF |
"For" permet de réaliser des boucles de lecture sur une table.
(Pour les boucles d'affectation d'une variable, se reporter à la documentation de l'instruction notée For(variable)).
Syntaxe 1
For clé1 [ hint-cl ]] [ From clé_deb] [Toclé_fin ] [ where-cl ] [With Lock | With Stability ]
..... instructions
Next [ clé ]
Désignation de la clé d'un fichier utilisée pour l'ordre de tri, sous l'une des formes :
| classe désigne l'abréviation du fichier qui doit être ouvert | |
nom_de_variable désignant la clé | Aucune. | |
Expression entière du nombre de parties de clés utilisées. Par défaut, toute la clé est utilisée. | 0 <=exp_ind<= nombre de composantes de la clé (au plus 8). | |
Voir instruction Hint | Aucune. | |
Clé de début de parcours, sous la forme d'une liste d'expressions séparées par le caractère ';' correspondant aux valeurs des sous-clés. | Le nombre d'expressions est au plus égal au nombre de composantes de la clé. | |
Clé de fin de parcours, sous la forme d'une liste d'expressions séparées par le caractère ';' correspondant aux valeurs des sous-clés. | Le nombre d'expressions est au plus égal au nombre de composantes de la clé. | |
Voir instruction Where | Aucune. |
# chargement à l'écran de tous les champs saisissables d'un masque
For[AMZ]CODE Where CODMSK=[M]MASQUE & SAIAFF=1 &CODTYP<>"ABS"
If !find([F:AMZ]CODZON,[M]ZONE(0..NOL-1))
[M]ZONE(NOL) = [F:AMZ]CODZON
Call TEXTE([F:AMZ]INTIT,[M]INTIT(NOL)) From OBJDIV
[M]CODCTL(NOL) = [F:AMZ]CODCTL
NOL += 1
Endif
Next
"For" permet de faire des boucles de lecture sur une table selon une clé donnée.
L'instruction :
For clé From clé_deb To clé_fin Where expr_l .... Next
est équivalente à :
Read clé >= clé_deb While [S]fstat <= 2 and clé <= clé_fin If expr_l .... Endif Read Next Wend
... mais est beaucoup plus rapide sur une table Oracle.
L'instruction Next est logiquement équivalente à une suite de "Read clé Next" (ou Unlock [FIC] suivis de "Readlock" si on utilise la clause With Lock) tant que la valeur de clé de l'enregistrement lu est identique sur le nombre de parties de clés données. Si la clé est donnée sans précision d'un nombre de composantes, l'instruction Next est équivalente à un seul Read Next (ou Readlock).
Dans le cas où "For" comporte une condition portant sur une expression logique, Adonix peut être amené à faire de façon interne, des Read Next supplémentaires jusqu'à ce que l'expression soit satisfaite.
On peut imbriquer des boucles "For" sur le nombre de parties de la clé, de façon à définir des ruptures, à condition toutefois de respecter le nombre de ses composantes.
Les clés utilisables dans "For" sont :
la clé définie dans la dernière clause Order By (s'il y en a une); sinon, l'une des clés définies en paramétrage du fichier.
l'une des clés définies dans la clause Order By du Link (s'il y en a une) ou dans une instruction Filter; sinon, la clé définie dans la dernière clause Order By correspondant au fichier principal (s'il y en a une); sinon, l'une des clés définies en paramétrage du fichier principal.
Lorsqu'on utilise l'abréviation de lien (définie lors d'un Link précédent) dans un "For", Adonix essaie de lire un enregistrement du fichier principal selon la clé donnée dans l'instruction "For", puis un enregistrement dans chaque fichier lié selon la clé et le mode de lecture donnés dans Link.
La lecture d'un enregistrement, avec la précision d'une partie de clé, positionne automatiquement la variable [G]currlen ; Cette variable contient en effet, le nombre de partie de clé utilisée ; Attention, toute lecture suivante, sans précision de clé, s'effectuera sur la même partie de clé. Pour lire sur une clé entière, préciser la clé ou bien positionner la variable [G]currlen à la valeur 0. La valeur 0 est la valeur par défaut.
On peut omettre dans la syntaxe de "For" l'abréviation du fichier ou le nom de la clé :
la dernière clé utilisée lors d'un accès au fichier (s'il y a eu un accès au fichier); sinon la clé définie dans la dernière clause Order By (si elle a été définie); sinon, la première clé définie en paramétrage du fichier.
On peut utiliser la variable reckey à la place du nom de la clé :
On sort d'une boucle "For" si :
On ne sort pas d'une boucle "For ... With Lock" si on rencontre un enregistrement verrouillé, par contre la variable [S]fstat sera positionnée à 1 juste après Next.
En sortie de boucle, [S]fstat est positionné à 0 sauf lorsqu'on a atteint la fin du fichier, quand il n'y a plus d'enregistrements vérifiant la clause Where ou de clé inférieure ou égale à clé_fin. Dans ces cas [S]fstat vaudra 4.
En sortie de boucle l'enregistrement courant est le dernier parcouru. Ceci reste vrai pour la syntaxe avec verrouillage, l'enregistrement résultant pouvant être verrouillé ou pas.
Le "For ... With Lock" :
Sous Oracle, les temps de réponse dépendant surtout du nombre de requêtes passées au serveur. Chaque ordre Read génère une requête SQL de type "select". Il en est de même pour chaque boucle For (de premier niveau). Dans ce cas une sorte d'index est créé sur les enregistrements sélectionnés rendant les accès suivants quasiment instantanés. Il faut donc utiliser les boucles "For" aussi souvent que possible.
Une requête est d'autant plus longue que le nombre d'enregistrements à explorer est grand. La clause Where (que ce soit sur un Filter placé avant ou sur l'ordre For lui-même) permet de limiter cette recherche.
Exemple :
soit un fichier de commandes client d'abréviation [CCL] ayant une clé CLICCL dont les deux premières parties sont CODCCL et DATCCL. On cherche à lire les clients entre 2 dates.
Si on fait :
For
[CCL]CLICCL(1)
# beaucoup d'enregistrements seront sélectionnés.
[L]CLICUR = [F:CCL]CODCLI
For[CCL]CLICCL
If DATCCL >= DATDEB & DATCCL <= DATFIN
... etc ...
Il faut faire :
Filter [CCL] Where DATCCL >= DATDEB and DATCCL <= DATFIN # on élimine toutes les commandes hors date dès le début. For [CCL]CLICCL(1) For [CCL]CLICCL
Dans le même esprit (et avec le même fichier) :
For [CCL]CLICCL From [L]CLICUR To [L]CLICUR et For [CCL]CLICCL Where CODCLIF = [L]CLICUR
sont deux syntaxes équivalentes (et efficaces).
Il est interdit de d'utiliser la clause Where (ou From to) à l'intérieur d'une boucle For et portant sur la même table. Il faut utiliser les tests If classiques si nécessaire.
Ne jamais initier une transaction par Trbegin (portant sur un fichier de la boucle) dans une boucle For With Lock, car sous Oracle, un seul enregistrement pourrait être lu.
Si la boucle
Sous DB2, il existe une limite sur le nombre de champs restitués par une requête. La lecture d'un fichier dépassant 255 colonnes provoque une erreur, y compris la lecture d'un fichier lié. Nous n'avons pas de problème sur la définition de la table, puisque lors de la saisie des champs, il existe déjà ce contrôle. Par contre, le problème se pose sur la lecture basée sur une abréviation issue de l'instruction Link. La solution est de filtrer les champs nécessaires par l'instruction Columns.
# Filtre de colonnes sur la classe issue du link
Local File ORDERS [ORD]
Local File ITMMASTER [ITM]
Link [ORD] with [ITM]ITM0=[F:ORD]ITMREF as [ORI]
# Position du filtre sur la réf.article, la dés. article, le n° d'ordre
Columns [ORI]([ITM]ITMREF,[ITM]ITMDES1,[ORD]WIPNUM)
For [ORI]
...
Next
Il est a noter une différence de comportement entre Oracle et SQL-server dans les boucles For, lorsqu'on créé des enregistrements vérifiant la clause where et dont la clé est supérieure à la clé courante :
sous Oracle, ces enregistrements ne seront jamais relus
sous SQL-server, ils seront lus à leur tour dans la boucle
Il est donc recommandé de ne pas utiliser de tels algorithmes, ou du moins, de se prémunir contre la relecture des enregistrements créés, par la clause "with stability". Attention, cette clause "With stability" ralentit l'exécution du fait de l' utilisation de tables temporaires pour chaque requête).
exemple sous SQL-serveur :
On admet la table XXX (CH1, CH2, FLG) avec 2 lignes :
'AAA', 'libellé 1', 0
'CCC', 'libellé 2', 1
avec la clé KEY qui porte sur le champ CH1
avec la clé KFL qui porte sur le champ FLGFor [XXX]KEY with stability
If CHP1 ='AAA'
CHP1 ='BBB'
Rewrite [XXX]
endif
NextAvec un curseur stable, on lit 2 lignes : 'AAA, 'CCC'.
Avec un curseur non stable ( donc sans précision de la clause stability) , on lit 3 lignes :
'AAA, 'BBB', 'CCC'.For [XXX]KEY
If CHP1 ='CCC'
CHP1 ='BBB'
Rewrite [XXX]
endif
NextStable ou Non stable, on lit 2 lignes : 'AAA, 'CCC' car la ligne ainsi modifiée n'est plus dans l'ordre normale de sélection.
Il est maintenant possible d'optimiser les lectures d'enregistrements lorsque la clé est composées de 2 éléments. On utilise l'une ou l'autre des 2 syntaxes qui s'appuient sur le principe du multi-requêtes :
Le but est de simplifier les requêtes en évitant les "or" de la clause where de la requêtes.
Il est à noter que la syntaxe For
Exemple :
Local File ACCES[ACC]
For [ACC]CODACC From "AAA";"AAA" to"ZZZ";"ZZZ"
Nextgénère la requête suivante (CODACC étant une clé à 2 partie) :
Select /*+ INDEX(ACC_ ACCES_CODACC) */ACC_.ROWID, ACC_.*
From X3.ACCES ACC_
Where ( ( ACC_.USR_0 = :1 And ACC_.CODACC_0 >= :2 )
Or ( ACC_.USR_0 > :1 ) )
And
( ( ACC_.USR_0 = :3 And ACC_.CODACC_0 <= :4 )
Or ( ACC_.USR_0 < :3 ) )
Order by ACC_.USR_0,ACC_.CODACC_0
Exemple optimisé :
Local File ACCES[ACC]
For [ACC]CODACC From "AAA";"AAA"
Nextgénère la requête suivante :
Select /*+ INDEX(ACC_ ACCES_CODACC) */ ACC_.ROWID, ACC_.*
From X3.ACCES ACC_
Where ( ACC_.USR_0 = :1 And ACC_.CODACC_0 >= :2 )
Order by ACC_.USR_0,ACC_.CODACC_0puis la requête suivante :
Select /*+ INDEX(ACC_ ACCES_CODACC) */ ACC_.ROWID, ACC_.*
From X3.ACCES ACC_
Where ( ACC_.USR_0 > :1 )
Order by ACC_.USR_0,ACC_.CODACC_0
Par défaut, le moteur Adonix laisse la base déterminer la clé de parcours la plus appropriée à la lecture. La clause With Nohint devient l'option par défaut.
Sous SQL-Server, par défaut, le curseur est non stable. La clause With stability permet de le rendre stable.
ERCLAS (7): | Abréviation non trouvée. |
ERRET (32) | Mauvaiseimbrication des boucles |
FISLOCK(43) | Plus assezde verrous (avec With Lock). |
FORV - BREAK - WHILE - REPEAT - READ - LINK - LOCKWAIT - READLOCK - COLUMNS
CURRIND - CURRLEN - WHERE - HINT
Adonix X3(r) L4G |