L4G >  Forf  

Afficher tout Masquer tout

"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

 
Syntaxe 1
 
 For clé1 [ hint-cl]] [ From clé_deb ] [ To clé_fin ] [ where-cl ] [ With Lock | With Stability ]
 
    ..... instructions
 
   Next [ clé ]
 

 

Paramètres

Elément

Description

Restrictions

clé1

Désignation de la clé d'un fichier utilisée pour l'ordre de tri, sous l'une des formes :

  • classe
  • classe id_clé1
  • classe id_clé '(' exp_ind ')'
  • reckey

classe désigne l'abréviation du fichier qui doit être ouvert

id_clé1

nom_de_variable désignant la clé

Aucune.

exp_ind

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).

hint_cl

Voir instruction Hint

Aucune.

clé_deb

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é_fin

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é.

where_cl

Voir instruction Where

Aucune.

 

Exemples

# 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

 

Description

"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 :

  • lorsqu'on parcourt une table en utilisant l'abréviation définie dans l'ordre File (de façon explicite ou implicite) :
  • 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.
  • lorsqu'on parcourt une table avec l'abréviation de lien :
  • 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é :

  • dans le premier cas, le fichier utilisé est le premier dans la liste des tables par défaut;
  • dans le deuxième cas, la clé utilisée est la clé courante, c'est-à-dire :
  • 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é :

  • dans ce cas, aucune clé n'est utilisée pour le tri. Si un order by a été précisé auparavant, il n'est pas pris en compte lorsque reckey est précisé. Ceci permet d'optimiser la requête, s'il n'y a pas de besoin trier les enregistrements. 
  • par contre, rien n'empêche d'utiliser une clé pour optimiser la clause where.

On sort d'une boucle "For" si :

  • on est en fin de fichier ou de sélection
  • on est en rupture par rapport au niveau précédent
  • l'enregistrement courant a une valeur de clé supérieure à clé_fin
  • on utilise Break (qui interrompt la boucle).

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" :

  • avec Oracle, la totalité des lignes est verrouillée lors du début de l'instruction et il y a blocage tant que ce n'est pas possible.
  • Avec Sql-server, les lignes sont bloquées une par une au fur et à mesure de leurs parcours et le blocage intervient le cas échéant sur la ligne qui ne peut être verrouillée.
  • Dans tous les cas, cette instruction est déconseillée, car s'il y a une tentative de lecture d'un enregistrement verrouillé, il y a attente puis nouvelles tentatives jusqu'à ce que l'enregistrement soit déverrouillé.

 

Remarques

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 For With Lock est faite à l'intérieur d'une transaction, les enregistrements ne seront déverrouillés qu'après Commit. En dehors d'une transaction, l'enregistrement verrouillé par For ... With Lock est déverrouillé par Next. Ce n'est pas le cas sous Oracle. Il faudra garder à l'esprit que les verrous sont une ressource limitée. Se reporter à la documentation sur l'instruction Readlock pour plus de détails.

 

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 FLG

For [XXX]KEY with stability
 If CHP1 =
'AAA'
  CHP1 =
'BBB'
  Rewrite [XXX]
 endif
Next

Avec 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
Next

Stable 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.

 

Evolutions

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.

 

Erreurs associées

Erreur

Description

ERCLAS (7) :

Abréviation non trouvée.

ERRET (32)

Mauvaise imbrication des boucles For (ForCLE(2) suivi de ForCLE(1) par exemple) ou clause Where à l'intérieur d'une boucle For.

FISLOCK(43)

Plus assez de verrous (avec With Lock).

 

Mots-clés associés

FORV - BREAK - WHILE - REPEAT - READ - LINK - LOCKWAIT - READLOCKCOLUMNS

CURRIND  -   CURRLEN - WHERE - HINT