Modèles de données physiques (niveau interne). Création et utilisation de valeurs par défaut, de contraintes et de règles avec T-SQL La valeur correspondant à la clé n'est pas définie

De quoi parle l'article

Cet article continue la série d'articles "Premiers pas de développement sur 1C". Il traite des principes de travail avec des collections génériques. Après avoir lu l'article, vous saurez :

  • Que sont les collections génériques, quand et dans quels cas les utiliser ?
  • Quel est le point commun entre toutes les collections universelles ? Quelles techniques peuvent être utilisées pour travailler avec chacun d'eux?
  • Qu'est-ce qu'un tableau, comment et quand l'utiliser ? Quelles méthodes a-t-il ?
  • Pourquoi utiliser une structure ? Quelle est la différence avec un tableau ?
  • Quand utiliser une liste de valeurs ? Comment l'afficher sur le formulaire ?
  • Conformité - qu'est-ce que c'est et quand l'utiliser ? Quels sont les avantages en termes de structure ?
  • A quoi sert un tableau de valeurs ? Comment décrire sa structure ? Comment ajouter/supprimer des lignes ? Comment l'amener au formulaire?
  • Arbre de valeur - à quoi sert-il ? Comment remplir et afficher sur le formulaire ? Comment travailler avec lui ?

Applicabilité

L'article traite de la plateforme 1C:Enterprise 8.3 de l'édition actuelle.

Comment travailler avec des collections universelles en 1C

Une collection de valeurs est une sorte de conteneur qui peut généralement contenir n'importe quel nombre d'éléments. Dans le même temps, il n'y a souvent pas de restrictions strictes sur le type de données.

Vous pouvez ajouter des valeurs à une collection générique. Toutes les valeurs de la collection peuvent être parcourues. Ces collections sont principalement utilisées pour certains types de traitement dans les algorithmes. Ceux. ce sont des structures dynamiques qui existent pendant la durée de l'algorithme.

Il est important de comprendre que les collections ne sont pas stockées dans la base de données (nous ne parlons pas du type de données Value Store, qui peut stocker presque tous les types de données).

Exister différentes sortes collections génériques : Array, Structure, Mapping, Fixed Array, Value Table, partie tabulaire etc. Mais toutes les collections ont un comportement similaire.

Une collection peut être créée à la suite d'une fonction (la fonction renvoie une collection générique en tant que valeur).

Disponible nouvelle collection manuellement en appelant le constructeur et en créant une instance de la classe.

Par exemple: NotreTableau = Nouveau Tableau ;

Les constructeurs de nombreuses collections génériques sont paramétrés.

Ainsi, dans le constructeur de vous pouvez spécifier le nombre d'éléments dans les dimensions correspondantes. Ceux. vous pouvez immédiatement déclarer multidimensionnel .

La description correspondante du constructeur se trouve dans l'assistant de syntaxe.

Ainsi, à l'aide des paramètres du constructeur, vous pouvez immédiatement définir le comportement souhaité de cet objet.

Mais les paramètres sont facultatifs, le développeur ne peut pas les définir et définir plus avant le comportement du Array comme il l'entend.

Presque toutes les collections génériques peuvent être créées à l'aide d'un constructeur (à l'exception des tableparts, qui agissent comme des objets de configuration).

Pour les collections génériques, il existe concepts généraux comme l'index et le numéro. Chaque élément de la collection a un index. L'indice commence à zéro.

Pour accéder à un élément Notretableau, vous pouvez utiliser l'accès à l'index, pour cela l'index est indiqué entre crochets.

Par exemple, Notretableau. Notez que dans ce cas, le système renvoie l'élément du tableau à l'index 3, et dans l'ordre, il s'agit du quatrième élément du tableau.

Pour certaines collections, il existe également le concept de numéro de ligne. Le numéro de ligne commence par un. Par exemple, pour une section tabulaire, il existe une propriété telle qu'un numéro de ligne. Il est important de garder à l'esprit que si nous connaissons le numéro de ligne et que nous voulons y accéder par index, la valeur un de moins que le numéro de ligne doit être utilisée comme index.

La notion de numéro de ligne n'existe pas pour toutes les collections, mais principalement pour celles qui peuvent être affichées dans l'interface utilisateur.

Pour toutes les collections, le parcours des éléments de la collection est utilisé. Le contournement est possible de deux manières : cycle pour et cycle Pour chaque.

Pour la plupart des collections génériques, les méthodes suivantes s'appliquent : Count, Index, Add, Insert, Delete et Find.

Count est une fonction qui renvoie le nombre d'éléments d'une collection. Il peut être utilisé avant la boucle Pour, comme le montre la figure.

La méthode Index n'existe pas pour toutes les collections, mais uniquement pour celles dont les éléments peuvent être référencés. Un exemple est Tableau des valeurs.

Tableau des valeurs est une collection spécifique de chaînes, les chaînes peuvent contenir différentes colonnes avec différents types valeurs.

Chaque ligne est une entité indépendante. Vous pouvez obtenir un lien vers celui-ci, via cette ligne, vous pouvez accéder aux valeurs des colonnes de cette ligne.

La méthode Index vous permet de déterminer quel index correspond à une ligne donnée (c'est-à-dire la position actuelle de la ligne dans la table). Les valeurs d'index commencent à zéro.

Des méthodes pour ajouter de nouvelles valeurs à cette collection existent dans presque tous collection universelle. La figure montre comment remplir un tableau avec des valeurs de 0 à 10 de deux manières.

Pour ajouter un élément à un Array, on peut utiliser la méthode Ajouter, indiquez la valeur ajoutée entre parenthèses. Dans ce cas, la valeur sera ajoutée à la fin de la liste, c'est-à-dire Le tableau augmentera constamment en raison de la dernière position.

Une autre méthode qui permet d'ajouter des valeurs à une collection est la méthode Insérer. Elle diffère de la méthode Ajouter afin que vous puissiez spécifier où insérer l'élément ajouté.

Syntaxe: Insérer (,)

Le premier paramètre spécifie l'index dans lequel la nouvelle valeur sera insérée. Ceux. nous pouvons, par exemple, spécifier que chaque valeur doit être insérée au début de la liste (la deuxième manière dans la figure ci-dessus).

La méthode est utilisée pour supprimer des éléments d'une collection. Effacer. Dans la méthode Delete, il est indiqué par index quel élément nous allons supprimer.

Syntaxe: Effacer()
Exemple d'utilisation : OurArray.Delete(5);

Il convient de noter que pour les collections où les chaînes représentent une entité indépendante (par exemple, pour ValeursTable), nous pouvons également utiliser la méthode get index pour supprimer la ligne donnée ultérieurement.

Presque toutes les collections ont une méthode pour trouver une valeur - Trouver. La méthode reçoit la valeur que nous voulons trouver. Dans certaines collections, vous pouvez mettre des restrictions.

Par exemple, dans Tableau des valeurs vous pouvez spécifier ces lignes, ces colonnes dans lesquelles vous souhaitez rechercher.

Si la valeur est trouvée, cette méthode renvoie l'index ou une chaîne spécifique. Si aucune valeur n'est trouvée, une valeur de type est renvoyée. Indéfini. Lorsqu'il est appliqué à un tableau, renvoie Indice, ou la valeur Indéfini.

Exemple d'utilisation : NotreVariable = NotreTableau.Trouver(8);

Les collections génériques peuvent être nettoyées très rapidement, c'est-à-dire supprimer absolument tous les éléments. Pour cela, la méthode est utilisée dégager(), qui supprime les éléments d'un tableau, les chaînes ValeursTable, ou des données d'autres collections.

Méthodes supplémentaires pour Array

Méthode Blimite() renvoie le nombre d'éléments moins un. Ceux. si nous utilisons une boucle Pour, alors au lieu de la méthode Quantité, nous pouvons immédiatement utiliser la méthode La frontière().

En particulier, la variable NumberInArray aurait pu être définie différemment :

NumberInArray = OurArray.InBorder();
Ensuite, lors de la description du cycle lui-même, il ne faut pas soustraire à cette variable.

La méthode Set vous permet d'affecter une valeur à un élément Array par index.

Syntaxe: Installer(,)

Exemple: OurArray.Set(2,8);

Option alternative : NotreTableau = 8 ;

Vous pouvez utiliser la méthode pour un Array Obtenir, afin de lire la valeur à index sans recourir à l'utilisation de crochets.

Syntaxe: Obtenir()

Exemple: NotreVariable = NotreTableau.Get(2);

Option alternative : NotreVariable = NotreTableau ;

Structure de collecte universelle

Une structure, comme un Array, peut avoir un nombre illimité d'éléments, mais le contenu d'un élément diffère d'un Array.

La structure est une collection dont chaque valeur consiste en une paire. Le premier élément d'une paire est appelé Clé. Le deuxième élément de la paire est Sens.

Clé est un type de données strictement chaîne qui décrit une valeur. Par exemple, clé"Code" peut correspondre à la valeur 113 ; clé"Nom" signifiant "Vasya". Il n'y a pas de contrainte de type de données sur la valeur elle-même.

La structure est très pratique à utiliser si nous voulons créer une liste de paramètres. Si cela Structure appelé NotreStructure, alors nous nous référerons à ses deux valeurs comme suit : OurStructure.Code et OurStructure.Name.

Un tel appel est beaucoup plus pratique que si nous définissions tous les paramètres dans un Array et y accédions par index.

La structure rend le code du programme lisible (compréhensible). La structure est utilisée assez souvent, beaucoup plus souvent que le Array.

Il est utilisé pour décrire certains paramètres, qui sont souvent assez grands dans tous les algorithmes.

De plus, la Structure est utilisée si la procédure et la fonction contiennent un grand nombre de paramètres passés.

Ensuite, il est beaucoup plus pratique d'écrire tous les paramètres dans la structure et de les transmettre. Ceux. il y a un "packing" de paramètres de procédures et de fonctions.

Par ailleurs, il convient de noter que, comme clé absolument aucune chaîne ne peut apparaître dans la structure. Certaines restrictions s'appliquent.

Clé doit servir d'identifiant. Cela signifie qu'en clé il ne doit pas y avoir d'espaces et il ne peut pas commencer par un chiffre.

Démarrage autorisé clé avec une lettre ou un trait de soulignement. De cette façon, Clé doivent satisfaire aux exigences de création d'identifiants.

Notons en quoi la structure diffère du tableau. La structure a une méthode Insérer, Array a deux méthodes d'insertion : Insérer(à une certaine position) et Ajouter(en fin de liste). Dans un tableau, tous les éléments sont ordonnés.

Une structure est une sorte d'ensemble non ordonné. C'est pourquoi il n'y a qu'une méthode d'insertion pour un Struct.

La valeur est insérée non pas à une position spécifique, mais dans l'ensemble spécifié. Un Struct ne peut pas être référencé par index comme d'autres collections génériques.

Les éléments de la Structure ne sont désignés que par le nom de la Clé. Cependant, la boucle For each of fonctionne également pour la structure, mais vous ne devez pas vous fier à l'ordre des éléments de la structure.

Une structure est créée de la même manière que les autres collections génériques à l'aide du constructeur New, en spécifiant le type de données de Structure.

Comme un Array, le constructeur d'un Struct peut avoir des paramètres. Ceux. il est possible de décrire le contenu de la Structure elle-même à l'aide d'un constructeur.

Contrairement à un tableau, où vous pouvez simplement spécifier le nombre d'éléments pour toutes les dimensions, dans une structure, il est possible de définir le contenu lui-même.

Par exemple: NotreStructure = Nouvelle Structure("Code,Nom", 133, "Vasya");

Tout d'abord, les noms des clés sont répertoriés séparés par des virgules, puis, respectivement, dans le même ordre, les valeurs des paramètres.

Pour ajouter une nouvelle valeur à la Structure, il existe une méthode Insérer, qui insère une nouvelle paire (Clé et Valeur).

Par exemple: OurStructure.Insert("Membres de la famille",3);

La structure se caractérise par une autre méthode qui est utilisée assez souvent. C'est la méthode Propriété.

Grâce à cette méthode, vous pouvez comprendre s'il existe un tel élément dans cette Structure, dont la Clé porte tel ou tel nom.

Si un tel élément existe, le système renverra True, sinon il renverra False.

Par exemple, l'expression OurStructure.Property ("Membres de la famille") sera égal à Vrai. Cette méthode est utilisée assez souvent dans l'analyse de la structure.

Comme pour toute collection universelle, il est permis d'accéder aux propriétés de la Structure par index. Mais l'index de la structure est une valeur de chaîne.

Par exemple: Report(OurStructure["Family Members"]);

Cependant, il ne faut pas oublier qu'une Structure n'est pas un ensemble ordonné d'objets, c'est pourquoi l'accès par index 0, 1, 2 est inacceptable.

Liste de valeurs de collection générique

Liste de valeurs est une liste linéaire d'éléments de n'importe quel type de données.

Chaque élément est composé de plusieurs valeurs. Schématiquement, une liste de valeurs peut être représentée sous la forme d'une liste à quatre colonnes.

Première colonne - marque. Il a un type de données booléen et permet à l'utilisateur de cocher ou de décocher les cases.

L'autre colonne est une image qui peut en quelque sorte représenter visuellement cet élément, c'est-à-dire faire correspondre cette ligne avec n'importe quelle image.

La troisième colonne est la valeur stockée elle-même, c'est-à-dire il s'agit de n'importe quel type de données, et il peut être différent dans différentes lignes.

La quatrième colonne est la vue, c'est-à-dire c'est une description de chaîne de la valeur donnée. La vue sera affichée à l'utilisateur lorsqu'il visualisera cet élément. Dans ce cas, si la vue n'est pas définie, le système essaiera d'obtenir des vues pour l'élément contenu dans cette position.

Liste de valeurs- c'est l'objet avec lequel l'utilisateur peut travailler visuellement. Ceux. Liste de valeurs peuvent être affichés sur le formulaire.

L'utilisateur peut effectuer certaines actions avec. Outre, Liste de valeurs peuvent être déduits indépendamment à l'aide de méthodes, c'est-à-dire afficher à l'écran dans certaines branches de l'algorithme (sauf pour code serveur) afin que l'utilisateur sélectionne une ligne ou coche certaines cases.

Allons trouver Liste de valeurs dans l'aide de sitax. Constructeur Liste de valeurs non paramétrable (aucune valeur par défaut ne peut être définie).

Il existe des méthodes comme :

  • Insérer(,) ;
  • Ajouter(,);
  • Quantité();
  • Indice().

Il existe également des méthodes spéciales, par exemple, DéchargerValeurs(). Cela crée un tableau dans lequel la liste de valeurs est copiée. Par exemple:

ArrayElements = ListPriceTypes.UnloadValues();

Il existe aussi une méthode inverse :
PriceTypeList.LoadValues(ElementsArray);

Il existe des méthodes de recherche :
FindByValue(); FindByIdentifier().

Il existe une méthode de copie :
CopyList = ListPriceTypes.Copy();
Cette méthode est destiné à apporter une sorte de modification avec une copie.

Il existe des méthodes :
SortByValue();
TrierParVue().

Méthodes Sélectionnez l'élément(,) et Marquer les éléments () appeler une boîte de dialogue modale qui arrête l'exécution de l'algorithme jusqu'à ce que l'utilisateur ferme cette fenêtre.

Pour utiliser ces méthodes dans les propriétés de configuration Mode d'utilisation de la modalité doit être réglé sur Utilisation.

Exemple de code appelé à partir d'un module d'application gérée :

Affichez ce code en mode utilisateur (boîte de dialogue modale).

Dessous Liste de valeurs utilisé comme type de données disponible pour l'attribut de formulaire. Nous créons un nouvel attribut pour le formulaire de traitement, déterminons son type Liste de valeurs et affichez-le sur le formulaire.

Nous créons nouvelle équipe StoreGifts, transférez-le dans le formulaire et définissez un gestionnaire d'action pour celui-ci.

En mode utilisateur, lorsque vous cliquez sur le bouton Remplir les cadeaux dans le formulaire de traitement, une liste complétée apparaîtra.

Si vous le souhaitez, la liste peut être modifiée : ajoutez des éléments, en supprimez d'autres.

Conformité de collecte universelle

Cette collection ressemble beaucoup à structure. Tout comme un Struct, un Match est un ensemble de valeurs composé d'une clé et de la valeur elle-même.

La principale différence est que n'importe quel type de données peut être spécifié en tant que clé, ainsi que pour une valeur. Compte tenu de cette fonctionnalité, il est nécessaire d'accéder à la valeur de correspondance par index, la valeur clé est spécifiée comme valeur d'index.

La clé peut être un type de données autre qu'une chaîne. Les propriétés et les méthodes de travail avec Matching sont presque les mêmes que celles de la Structure.

Le Match Constructor, contrairement à un Struct, ne contient pas la possibilité de spécifier des paramètres.

Exemple d'utilisation :

La correspondance est utile lorsqu'il est nécessaire de relier deux structures quelconques. Par exemple, chaque ligne de la partie tabulaire doit correspondre à une ligne du tableau des valeurs.
Dans ce cas, la ligne de la section tabulaire est utilisée comme clé de correspondance et la valeur correspondante est indiquée.

Lors de l'insertion d'éléments dans une collection Match autre que la méthode Insérer(,) Il existe une autre façon d'insérer une valeur, et c'est d'utiliser l'opérateur d'affectation normal.

Par exemple: OurMatch = Nouvelle correspondance ;
Correspondance = 999 ;

Ceux. si l'élément n'était pas présent dans la collection, alors il sera ajouté à l'aide de l'opérateur d'affectation, et s'il est présent, il sera mis à jour.

Ceci est différent de Structure.

Tableau des valeurs de la collection générique

Tableau des valeurs est une table avec un nombre arbitraire de lignes et un nombre arbitraire de colonnes. Une intersection peut stocker des valeurs de n'importe quel type de données. Si nécessaire, les colonnes peuvent être typées, c'est-à-dire déterminer dans quelle colonne quel type de données est stocké.

Vous pouvez laisser les colonnes non typées, puis la même colonne dans différentes lignes peut stocker des valeurs de types différents.

Différences ValeursTableà partir d'un tableau 2D :

  • c'est un objet avec lequel l'utilisateur peut travailler (le tableau des valeurs peut être affiché à l'écran, l'utilisateur peut le remplir, à l'avenir les données saisies peuvent être lues);
  • création d'index pour une recherche rapide ;
  • clonage, remplissage de la colonne entière avec une certaine valeur, déchargement de toutes les colonnes dans un tableau.

Tableau des valeurs utilisé comme une sorte de tampon pour stocker des informations. Tableau des valeurs est renvoyé et accepté comme paramètre par de nombreuses méthodes du système. Il est possible de construire une requête vers le tableau des valeurs.

Alors, Tableau des valeurs se compose d'un ensemble de lignes et d'un ensemble de colonnes. Les lignes et les colonnes sont des collections.

Ceux. à l'intérieur de la collection Tableau des valeurs il y a deux autres collections. Passons à l'assistant de syntaxe et trouvons Tableau des valeurs.

Types de données pris en charge : lui-même Tableau des valeurs, composé de chaînes. Chaque ligne est représentée par un type de données RowTableValues, qui a ses propres propriétés et méthodes. Disponible CollectionColumns TableValues possède également certaines propriétés.

Point important! La procédure qui génère Tableau des valeurs, devrait compiler & OnServer.

Avant de commencer à travailler avec Tableau des valeurs, vous devez déterminer quelles colonnes il contiendra (c'est-à-dire les créer). Syntaxe:

Ajouter(,)
(optionnel)
Tapez : Chaîne.
(optionnel)
Type : Types de description
(optionnel)
Tapez : Chaîne.
(optionnel)
Tapez : Nombre.

Par exemple:

Pour appeler cette procédure, nous allons utiliser la commande.

Dans le descriptif ValeursTable car les éléments de la collection sont exactement RowsTableValues.

Contrairement aux colonnes, qui se composent uniquement de propriétés (Nom, Type, Titre, Largeur), dans RowTableValues il existe à la fois des propriétés (référence par nom de colonne) et des méthodes (vous pouvez obtenir et définir une valeur, travailler avec les propriétaires).

Ajouter nouvelle ligneà la table, vous devez utiliser la méthode soit Ajouter(), ou Insérer(). Dans le second cas, vous devez spécifier la position dans laquelle la chaîne requise doit être placée.

Pour attribuer une valeur à une colonne, nous y faisons référence par le nom ou l'index de la colonne (entre crochets) séparés par un point.

Pour remplissage ValeursTable les méthodes suivantes peuvent être utilisées :

dégager()- pour supprimer toutes les lignes de ValeursTable.

RemplirValeurs(,)– vous permet de remplir toutes les colonnes ou les colonnes sélectionnées avec une seule valeur.
ChargerColonne(,)– charge une colonne à partir d'un tableau.
DéchargerColonne()– décharge une colonne dans un tableau.

Les deux dernières méthodes sont utiles lorsque vous devez déplacer une colonne d'un tableau de valeurs à un autre.

Copie(,)- vous permet de créer une nouvelle table basée sur une table existante Tableau des valeurs, tout en spécifiant non pas toutes les lignes et toutes les colonnes, mais seulement certaines d'entre elles. Valeur de retour - Tableau des valeurs.

Vous pouvez copier la structure ValeursTable. Il existe une méthode correspondante pour cela. CopierColonnes(). Nous recevrons un vide Tableau des valeurs avec la structure souhaitée.

À Tableau des valeurs il y a une méthode total(). Vous pouvez spécifier la colonne dans laquelle vous souhaitez additionner les valeurs numériques. En ce qui concerne le code affiché précédemment dans le Tableau, vous pouvez calculer la valeur : TK.Total ("Somme").

À Tableau des valeurs il est possible de regrouper (effondrer) des valeurs numériques par les mêmes valeurs de certaines colonnes à l'aide de la méthode Effondrement(,).

En ce qui concerne le code affiché précédemment dans le Tableau, vous pouvez calculer la valeur : TK.Collapse("Jour de la semaine", "Montant").

Tableau des valeurs peut être affiché sur l'écran de l'utilisateur afin que vous puissiez effectuer toutes les actions avec. Mais contrairement à Liste de valeursà partir du code du programme, vous ne pouvez pas simplement appeler la table à l'écran.

Afficher Tableau des valeursà l'écran, créez un attribut de formulaire et attribuez-lui un type de données Tableau des valeurs.

Après cela, le tableau résultant doit être affiché sur le formulaire.

Dans le module formulaire, à la fin de l'algorithme précédemment compilé (dans la Procédure de création d'un tableau de valeurs), ajoutez :
ValueVFormData(TK, Table);

Arbre de valeurs de collection générique

une collection polyvalente qui ressemble beaucoup à Tableau des valeurs. La différence avec le tableau est que les lignes de l'arbre peuvent être subordonnées les unes aux autres, c'est-à-dire une sorte de hiérarchie peut se former.

Il peut également être affiché à l'écran. L'arborescence de valeurs consiste explicitement en une collection de lignes et une collection de colonnes. Il y a deux propriétés dans l'arborescence, Rows et Columns.

Étant donné que les lignes peuvent être subordonnées les unes aux autres, un parent peut être spécifié pour chaque ligne, ainsi que des lignes qui lui sont subordonnées.

Créons la commande Tree appropriée et sa procédure de traitement.

créons dans lequel il y a une ligne parente et deux lignes subordonnées.

Créer un attribut de formulaire DerZn(type de données - Arbre de valeurs).

Pour cet attribut, nous allons créer les colonnes Année et Mois.

Déplacer l'élément correspondant DerZn au formulaire.

À la fin Procédures TreeOnServer() ajouter:

ValueVFormData(TreeZn, DerZn);

Vérifions ce qui s'est passé en mode utilisateur.

Avec bouton Ajouter vous pouvez ajouter de nouvelles lignes. Ils peuvent également former une hiérarchie.

Pour itérer sur tous les éléments de l'arbre de valeurs, nous devons utiliser la récursivité, c'est-à-dire appeler une procédure à partir d'elle-même. Par exemple, le traitement d'un arbre de valeurs pourrait ressembler à ceci :

Ceci conclut notre première introduction aux collections universelles.

Dans le prochain article, nous verrons quel mécanisme important un développeur peut utiliser pour simplifier l'accès à un élément du dictionnaire à partir du code du programme.

Il est construit comme suit. La séquence d'enregistrements correspondant aux enregistrements de la table source est ordonnée par les valeurs de la clé primaire. Les enregistrements logiques sont combinés en blocs (k enregistrements dans les blocs).

La valeur de clé de bloc est la valeur de clé minimale des enregistrements inclus dans le bloc. La séquence de blocs est le dernier niveau du B-tree. Un index du niveau précédent est construit. Les enregistrements de ce niveau contiennent la valeur de clé du bloc du niveau suivant et l'adresse du pointeur de lien du bloc correspondant ; les enregistrements de ce niveau sont également combinés en blocs (k enregistrements chacun). Ensuite, un index de niveau supérieur est construit de la même manière, et ainsi de suite, jusqu'à ce que le nombre d'entrées d'index à un certain niveau ne dépasse pas k .

Considérez la procédure pour travailler avec un arbre B en utilisant un exemple. Soit un fichier d'instances d'enregistrements logiques dont les clés prennent les valeurs 2, 7, 8, 12, 15, 27, 28, 40, 43, 50. Pour la précision, on prend k=2 (on combiner 2 instance d'enregistrements). Celui construit pour cet exemple est illustré à la Fig. 9.7 (pour simplifier la figure, seules les clés des enregistrements logiques sont présentées au niveau 4 et les valeurs des autres champs de ces enregistrements ne sont pas présentées).


Riz. 9.7.

Les blocs contiennent la valeur clé du bloc correspondant. La valeur de k est prise égale à 2.

En construisant un arbre B, tous les enregistrements source sont à la même distance de l'index supérieur (l'arbre est équilibré).

Considérons la mise en œuvre des principales opérations.

Rechercher et lire un enregistrement à partir de valeur de consigne clé

L'exposant est lu. Comparez la valeur de clé donnée avec la valeur de clé dernière entrée indice. Si la valeur de clé spécifiée est supérieure ou égale à la valeur de clé de l'entrée d'index suivante (si une telle entrée existe), alors le bloc d'entrées d'index du niveau suivant est lu à l'adresse de lien spécifiée dans l'entrée courante. Ensuite, le processus est répété.

Nous supposons que tous les blocs sont situés dans le VP. Le nombre d'appels au VI lors de la recherche d'informations sera alors égal au nombre de niveaux de l'arborescence. Le nombre de niveaux d'arbre est égal à la valeur minimale l , à laquelle la condition k l >= N (N est le nombre d'enregistrements logiques) est satisfaite.

Modification (correction) de l'entrée

Après la recherche et la lecture de l'enregistrement, les champs ajustables sont modifiés. Si ce n'est pas la clé de l'enregistrement qui est corrigé, alors l'enregistrement modifié est mis à sa place. Si la valeur de la clé est modifiée, alors l'ancien enregistrement est supprimé (un enregistrement "vide" apparaît dans le bloc correspondant), et l'enregistrement modifié est saisi de la même manière que le nouvel enregistrement.

Suppression d'une entrée

Après la recherche, l'enregistrement trouvé est supprimé (un enregistrement "vide" est inscrit dans le bloc correspondant à la place de cet enregistrement).

Ajout d'une entrée

Tout d'abord, il est déterminé où l'entrée ajoutée avec la valeur de clé donnée doit être située. La procédure pour trouver le bloc où cet enregistrement doit être situé est similaire à la procédure décrite ci-dessus pour rechercher des enregistrements avec une valeur de clé donnée. S'il y a une entrée "vide" dans le bloc de niveau inférieur trouvé, l'entrée ajoutée est ajoutée à ce bloc (avec la réorganisation nécessaire des entrées dans le bloc).

S'il n'y a pas d'espace vide dans le bloc de niveau inférieur correspondant, le bloc est divisé en deux blocs. Les enregistrements sont saisis dans le premier d'entre eux, les autres sont saisis dans le second. La valeur de clé de chacun des blocs spécifiés sera, comme décrit précédemment, la valeur minimale des clés des enregistrements inclus dans le bloc. L'enregistrement en cours d'ajout est entré dans le bloc dont la valeur de clé est inférieure à la valeur de clé de l'enregistrement en cours d'ajout. L'apparition d'un nouveau bloc avec une nouvelle valeur de clé nécessite la formation d'un nouvel enregistrement dans l'index au niveau précédent. Cette entrée contient la nouvelle valeur de clé du nouveau bloc et un pointeur vers son emplacement. La procédure d'ajout d'une telle entrée est similaire à celle décrite ci-dessus. Le bloc du niveau précédent est situé là où cet enregistrement doit être placé. S'il y a un espace vide dans le bloc, l'entrée est ajoutée au bloc, si le bloc est plein, il est divisé en deux blocs, l'entrée est entrée dans l'un des blocs, une entrée d'index du niveau précédent est formée , etc.

Une variante est possible lorsqu'il faut diviser le bloc du haut niveau et forment un autre niveau de l'arbre.

Considérons pour l'exemple illustré à la Fig. 9.7 , en ajoutant une entrée avec la touche 10.

1. Comparaison au premier niveau.

Mouvement sur la branche gauche.

2. Comparaison au deuxième niveau.

Mouvement sur la branche gauche.

3. Comparaison au troisième niveau.

Mouvement le long de la branche droite.

Le bloc souhaité

4. Le bloc est plein.

Il est divisé en 2 blocs

Comparaison 8<10<12.

L'enregistrement avec la touche 10 est entré dans le bloc 1

Au niveau le plus bas, une nouvelle entrée est apparue avec une valeur de clé de 12. Il faut ajouter une nouvelle entrée avec une clé de 12 et un pointeur vers l'entrée du niveau le plus bas vers l'index du niveau précédent.

5. Une entrée avec une clé de niveau 3 de 12 doit être ajoutée au bloc. Le bloc est plein, il est divisé en deux blocs

Comparaison 8<12.

L'entrée est ajoutée au deuxième bloc

6. Au niveau 3, un bloc est apparu avec une nouvelle clé 8. Il faut ajouter une nouvelle entrée avec une clé de 8 et un pointeur vers le bloc correspondant de niveau 3 au niveau 2.

7. Une entrée avec une clé de niveau 2 de 8 doit être ajoutée au bloc. Le bloc est plein, il est divisé en deux blocs.

L'entrée est ajoutée au bloc 1.

8. Au niveau 2, un bloc avec une nouvelle clé 15 est apparu, il faut ajouter une nouvelle entrée avec une clé de 15 et un pointeur vers le bloc correspondant de niveau 2 au niveau 1.

Valeurs par défaut, restrictions et règles - ce sont des attributs facultatifs qui peuvent être définis sur les colonnes et les tables de la base de données. À le silence(valeurs par défaut) - ce sont les valeurs qui sont entrées dans une colonne spécifique. Restrictions(contraintes) sont utilisées comme moyen d'identifier les valeurs valides pour une colonne (pour rejeter les valeurs invalides), ainsi que comme moyen d'assurer l'intégrité des données dans les tables de base de données et entre les tables liées. Une contrainte sur une seule colonne est appelée contrainte de valeur (colonne) : elle limite les valeurs de cette colonne uniquement. Une contrainte qui affecte plusieurs colonnes est appelée contrainte référentielle : dans ce cas, la combinaison de valeurs pour les colonnes spécifiées dans la contrainte doit satisfaire aux exigences de la contrainte. Il existe cinq types de contraintes : NOT NULL, UNIQUE, PRIMARY KEY, FOREIGN KEY et CHECK.

Valeur nulle(valeur nulle) est une valeur inconnue pour laquelle la notation NULL s'applique . Une valeur nulle dans une colonne signifie généralement qu'il n'y a pas de données pour la ligne de cette colonne car la valeur est inconnue, ou n'a pas de sens, n'est pas définie ou sera définie à l'avenir. Les valeurs nulles ne sont pas des valeurs vides et non des valeurs du nombre 0, leurs valeurs réelles sont inconnues (inconnues), donc deux valeurs nulles ne sont pas égales.

IDENTITÉ Propriété. Lorsque vous créez une table, vous pouvez spécifier l'une des colonnes en tant que colonne d'identité en ajoutant la propriété IDENTITY à la définition de colonne. Si une colonne est créée avec la propriété IDENTITY, SQL Server génère automatiquement une valeur de ligne pour cette colonne, calculée à partir de la valeur de départ et de la valeur d'incrément. La valeur de départ est la valeur d'identité de la première ligne insérée dans la table. L'incrément est la quantité par laquelle SQL Server incrémente la valeur d'identité pour les lignes consécutives. Chaque fois qu'une ligne est entrée, SQL Server attribue la valeur d'identité actuelle à l'élément de données dans la colonne d'identité entrée sur la nouvelle ligne. La ligne suivante saisie recevra une valeur d'identité supérieure à la valeur d'identité maximale actuelle d'un incrément. Les colonnes d'identité sont couramment utilisées dans les contraintes de clé primaire sur les tables qui permettent aux lignes d'être identifiées de manière unique. Par exemple, si vous spécifiez IDENTITY(1, 10), alors la valeur de la colonne d'identification pour la première ligne saisie sera 1, pour la deuxième ligne ce sera 10, pour la troisième ligne ce sera 20, et ainsi de suite . Si vous ne spécifiez pas de valeur de départ ou d'incrément, ils utiliseront les valeurs par défaut de 1 et 1. Les colonnes d'identité ne peuvent pas contenir de valeurs par défaut et ne sont pas autorisées à être nulles. Chaque table ne peut avoir qu'une seule colonne d'identification.


Par défaut, les colonnes d'identification ne peuvent pas être saisies directement et ne peuvent pas être modifiées. Si vous souhaitez retaper une chaîne supprimée et conserver l'ancienne valeur d'identification de cette chaîne, vous pouvez remplacer le paramètre par défaut à l'aide de cette instruction :

SET IDENTITY INSERT table.name ON

Avec cet opérateur, vous pouvez insérer une ligne et attribuer la valeur de la colonne d'identification dont vous avez besoin. Lorsque vous avez fini de saisir la chaîne, vous devez supprimer la possibilité d'insérer dans la colonne d'identification à l'aide de l'opérateur suivant :

SET IDENTITYINSERT nom_table OFF

Après cela, SQL Server prendra la plus grande valeur de cette colonne comme valeur initiale utilisée lors de l'ajout des lignes suivantes.

Créer une valeur par défaut pour une colonne à l'aide de l'instruction CREATE TABLE est la méthode standard préférée. L'instruction suivante crée une table dans la base de données MyDB contenant les valeurs par défaut pour les deux colonnes, columnA (de type char) et columnB (de type int) :

CRÉER TABLE MaTable

(columnA char(15) NULL DEFAULT "pcs",

colonneB int NULL DEFAULT 0)

La valeur par défaut "pcs" pour la colonne columnA est compatible avec le type de données char de cette colonne, et la valeur par défaut 0 pour columnB est compatible avec le type de données int. Si une valeur spécifique n'est pas spécifiée pour une ou les deux colonnes lors de l'insertion d'une nouvelle ligne dans une table, la valeur par défaut appropriée est utilisée. Par conséquent, la seule façon d'affecter NULL à ces colonnes consiste à insérer explicitement NULL. Les valeurs nulles sont valides car l'attribut NULL est spécifié pour les deux colonnes. Si les colonnes ont été définies comme NOT NULL, vous ne pouvez pas insérer explicitement une valeur NULL.

Contrainte PRIMARY KEY est utilisé pour spécifier la clé primaire de la table, qui est une colonne ou un ensemble de colonnes qui identifie de manière unique une ligne de table. Étant donné que la clé primaire identifie une ligne, la colonne correspondante ne contiendra jamais de valeur NULL. Si vous définissez une contrainte PRIMARY KEY sur un ensemble de colonnes, cette contrainte spécifie que la combinaison de valeurs pour ces colonnes doit être unique pour chaque ligne. La contrainte PRIMARY KEY n'autorise pas les valeurs en double. Si une contrainte PRIMARY KEY est affectée à une colonne ou à un ensemble de colonnes, un index unique est automatiquement créé sur cette ou ces colonnes de clé primaire. Une table ne peut avoir qu'une seule contrainte PRIMARY KEY. Une colonne avec un attribut IDENTITY convient parfaitement à une clé primaire. L'instruction T-SQL suivante est un moyen de spécifier la colonne SSN comme clé primaire lorsque vous définissez une table.

Client CRÉER TABLE

caractère midinit(1) NULL,

nom_de_famille char(20) NON NULL,

Custom_phone char(10) NULL)

Vous pouvez également nommer cette contrainte en ajoutant le mot-clé CONSTRAINT. Pour attribuer le nom PK_SSN à votre contrainte PRIMARY KEY, utilisez l'instruction suivante :

Client CRÉER TABLE

(prénom char(20) NON NULL,

caractère midinit(1) NULL,

nom_de_famille char(20) NON NULL,

SSN char(11) CONTRAINTE PK_SSN CLÉ PRIMAIRE,

cust_phone char(10) NULL)

Vous pouvez également spécifier une contrainte PRIMARY KEY une fois que toutes les colonnes de la table ont été définies. Lorsque vous utilisez cette syntaxe, le nom de la colonne doit être placé entre parenthèses et spécifié après la clause CONSTRAINT, comme indiqué dans l'instruction suivante :

Client CRÉER TABLE

(prénom char(20) NON NULL,

caractère midinit(1) NULL,

nom_de_famille char(20) NON NULL,

cust_phone char(10) NULL,

CONTRAINTE PK_SSN CLÉ PRIMAIRE (SSN))

Contrainte unique garantit qu'aucune valeur en double n'est autorisée dans une colonne ou un ensemble de colonnes ; en d'autres termes, l'unicité des valeurs dans cette colonne ou cet ensemble de colonnes est assurée. Pour prendre en charge cette unicité, SQL Server crée, par défaut, un index unique sur la ou les colonnes spécifiées dans la contrainte UNIQUE. Une contrainte UNIQUE peut être utilisée sur n'importe quelle colonne qui ne fait pas partie d'une contrainte PRIMARY KEY. Une contrainte UNIQUE peut être utilisée sur des colonnes qui autorisent des valeurs nulles, tandis que les contraintes PRIMARY KEY ne peuvent pas être utilisées sur de telles colonnes. Une colonne avec une contrainte UNIQUE peut être référencée par une contrainte FOREIGN KEY. Plusieurs contraintes UNIQUE peuvent être définies sur une seule table, tant que le nombre total d'index pour cette table ne dépasse pas 250 index.

Pour créer une contrainte UNIQUE sur une table à l'aide de T-SQL, utilisez l'instruction CREATE TABLE. Par exemple, l'instruction suivante crée une table client avec une contrainte UNIQUE sur la colonne SSN en tant qu'index :

Client CRÉER TABLE

(prénom char(20) NON NULL,

caractère midinit(1) NULL,

nom_de_famille char(20) NON NULL,

SSN char(11) NOT NULL UNIQUE CLUSTERED,

cust_phone char(10) NULL)

Contrainte CHECK est utilisé pour limiter l'ensemble des valeurs autorisées pour une colonne à certaines valeurs. Les valeurs utilisées lors de l'insertion dans une colonne ou de la mise à jour d'une colonne sont vérifiées par rapport à la vérité (valeur TRUE) de la condition de recherche booléenne spécifiée dans la contrainte. Par exemple, si nous voulions limiter la plage de valeurs possibles autorisées pour la colonne de prix de la table des articles entre 0,01 $ et 500,00 $, nous utiliserions l'instruction suivante :

Éléments CRÉER TABLE

(nom de l'élément char(15) NOT NULL,

itemid smallint IDENTITÉ NON NULLE(1,1),

prix smallmoney NULL,

item_desc varchar(30) NOT NULL DEFAULT "aucun",

CONTRAINTE PK_ itemid CLÉ PRIMAIRE (itemid),

CONTRAINTE CK_prix CHECK (prix >=0.01 ET prix<= 500.00))

Création et modification de contraintes à l'aide de Management Studio

Pour créer une table, développez le dossier du serveur et le dossier de la base de données dans le volet gauche de Management Studio, cliquez avec le bouton droit sur le dossier Tables, puis sélectionnez Nouvelle table dans le menu contextuel. Pour afficher la fenêtre Design Table pour une table existante, cliquez d'abord sur le dossier Tables, cliquez avec le bouton droit sur le nom de cette table dans le volet de droite, puis sélectionnez Design Table dans le menu contextuel.

Pour indiquer s'il faut ou non utiliser valeurs nulles dans n'importe quelle colonne, cochez ou décochez simplement la case appropriée dans la colonne Autoriser les valeurs nulles de la fenêtre Table de conception. Vous pouvez définir cette option lors de la création d'un tableau ou lors de sa modification.

Pour créer ou modifier Contrainte unique à l'aide de Management Studio , procédez comme suit :

1. Dans la barre d'outils de la fenêtre Table de conception, cliquez sur le bouton Index/Clés.

  1. La fenêtre suivante apparaîtra vous permettant de créer, modifier et supprimer les contraintes associées aux clés primaires et uniques

Sélectionnez les noms de colonne que vous souhaitez inclure dans la contrainte et définissez ses propriétés.

Vous pouvez demander Contrainte PRIMARY KEY une colonne ou plusieurs colonnes. Cette ou ces colonnes doivent identifier de manière unique chaque ligne du tableau. Pour définir une contrainte PRIMARY KEY, procédez comme suit :

  1. Dans la fenêtre Design Table, sélectionnez une colonne en cliquant sur l'une des cellules de sa ligne. (Vous pouvez sélectionner plusieurs colonnes en maintenant la touche Ctrl enfoncée et en cliquant sur les cellules grises à gauche des noms de colonne.)

  1. Cliquez avec le bouton droit sur l'une des colonnes sélectionnées et sélectionnez Définir la clé primaire dans le menu contextuel. Une image d'une petite clé apparaîtra à gauche des colonnes que vous avez définies pour la clé primaire.
  2. Si vous devez déplacer la contrainte PRIMARY KEY vers une autre colonne, définissez simplement cette nouvelle colonne comme clé primaire. Vous n'êtes pas obligé de supprimer explicitement la clé primaire d'origine en premier - SQL Server supprimera et recréera l'index PRIMARY KEY pour vous. Vous pouvez également modifier l'index PRIMARY KEY dans la fenêtre Propriétés. Vos modifications prendront effet une fois que vous aurez enregistré votre travail en cliquant sur le bouton Enregistrer dans la barre d'outils.

Créer Contrainte CHECK à l'aide de la fenêtre Design Table, ouvrez cette fenêtre pour la table avec laquelle vous souhaitez travailler et suivez les étapes ci-dessous.

1. Cliquez avec le bouton droit sur la fenêtre Table de conception et sélectionnez Propriétés dans le menu contextuel pour afficher la fenêtre Propriétés. Cliquez sur l'onglet Vérifier les contraintes et cliquez sur le bouton Nouveau pour le tableau.

3. Remarquez les trois cases à cocher au bas de cette fenêtre. Cocher la case Vérifier les données existantes à la création signifie que les données de la table existante seront vérifiées par rapport à la contrainte CHECK, et si elles ne correspondent pas, la contrainte ne sera pas créée. Cocher la case Appliquer la contrainte pour la réplication signifie que cette contrainte sera vérifiée lors de la réplication des données. Cocher la case Appliquer la contrainte pour les INSERTS et les MISES À JOUR signifie simplement que la contrainte CHECK sera activée. Si vous ne cochez pas cette case, alors cette restriction sera créée, mais elle ne sera pas activée, c'est-à-dire n'aura aucun effet.

4. Cliquez sur le bouton Fermer puis cliquez sur le bouton Enregistrer pour enregistrer la nouvelle contrainte. Pour modifier une contrainte CHECK, utilisez l'onglet Vérifier la contrainte pour modifier le nom de la contrainte, l'expression de la contrainte et les indicateurs.

Vous pouvez également utiliser l'onglet Vérifier les contraintes pour supprimer une contrainte CHECK en sélectionnant le nom de la contrainte que vous souhaitez supprimer dans la liste Contrainte sélectionnée et en cliquant sur le bouton Supprimer.

Travail de laboratoire est conçu pour 3 heures de cours en classe et consiste à étudier le matériel théorique et à acquérir des compétences pratiques dans la définition de tables de base de données, la création de règles, de restrictions, de valeurs par défaut, de types de données personnalisés, d'index. La livraison des travaux de laboratoire consiste à répondre à des questions de contrôle et à démontrer une tâche individuelle sur un PC.

  1. Titre et objet de l'ouvrage
  2. Tâche individuelle
  3. Scripts pour créer un type de données personnalisé et des tables de base de données, conformément à une tâche individuelle

question test

  1. Liste des types de données pris en charge ?
  2. Type de données personnalisé. But et méthodes de création ?
  3. Façons de définir des tables ?
  4. Attribuer des valeurs par défaut, des règles et des restrictions ?
  5. Liste des valeurs par défaut, restrictions, règles prises en charge ?
  6. Méthodes d'attribution des valeurs par défaut, restrictions, règles
  7. Qu'est-ce qu'une valeur nulle ?
  8. Propriété de la colonne IDENTITY ?

n. (pzegt (pape fois (K, h))

Insère la valeur de h dans l'objet n en position, étiqueté avec la touche 1c.

S'il existe déjà une valeur ieportable correspondant à la clé 1c, alors elle n'est pas modifiée. Renvoie un objet de type pamphlet::stringtor, boo1>, dont le premier composant pointe vers l'élément avec la clé donnée, et le second indique si un nouvel élément a été inséré. Faites attention au fait que selon la valse droite, pa1 r génère un objet de type pa(r sk, h ”, qui est converti après le début de la fonction snzegm en un objet de type raz r

p.uzpb (1s)

Renvoie un ptérateur lié à l'élément (le cas échéant) couvert par la clé 1c. Si un tel élément n'existe pas, renvoie la valeur de n.enb0 Génère un objet typ r qui smermit la clé et la valeur avec laquelle cet élément est fusionné, à la position indiquée par l'itérateur me. Ainsi, l'élément me->r(gm est de type conn k et prgl fixe la clé, et l'élément me->jesnb est de type y et prgl fixe la valeur correspondant à cette clé

B.Z. Algorithmes

La bibliothèque stud comprend de nombreux algorithmes génériques écrits en pensant aux itérateurs ; ainsi, les algorithmes deviennent indépendants des structures de données spécifiques sur lesquelles ils opèrent et des types de leurs membres. Notez que les conteneurs associatifs ont des itérateurs qui font référence à des types composites tels que la classe pa(r. A l'aveuglette, l'utilisation de ces algorithmes avec des conteneurs associatifs nécessite une conception soignée.

La plupart des algorithmes se concentrent sur des séquences délimitées par une paire d'itérateurs, le premier itérateur pointant vers le premier élément et le second pointant vers la zone mémoire située après le dernier élément de cet après-élément. Sauf indication contraire, tous les algorithmes sont définis dans l'en-tête.

Inclut des déclarations d'algorithmes généraux

accppite(b, e, t)

accipate(b, e, t, r)

Dégonflé dans le titre. Crée un objet temporaire o1y de même type et de même valeur que l'objet m. Pour toute entrée de l'itérateur me dans l'intervalle (b, e), calcule ady" = aby + *mt ou aby" = T(ab) ", *3m), selon la forme de la fonction accpplyate qui a été appelée. Le résultat est une copie de l'objet aby. Notez que parce que l'opérateur "+" peut être surchargé, même la première forme de la fonction accpplyate peut fonctionner sur les types non intégrés. type arithmeticguskill Par exemple, nous pouvons utiliser l'algorithme Assppp1ate pour concaténer toutes les chaînes dans le copieur

B.Z. Algorithmes

b(na~y sevgsp(b, e, c)

Renvoie une valeur de type boo1 indiquant si la valeur c appartient à la pastlglobalness (triée) délimitée par les itérateurs unidirectionnels b et e

copie(b, e, b)

Copie les valeurs de la séquence spécifiée par les itérateurs d'entrée b et e dans la zone de destination, appelée l'itérateur d. Renvoie une valeur qui spécifie la position derrière le dernier élément du receveur

epv1(b, e, b2)

epv1(b, e, b2, p)

Une valeur exponentielle de type bao1, indiquant si les éléments de l'ordre de grandeur donné par les itérateurs d'entrée b et e sont égaux aux éléments d'une séquence de même taille dont le début est donné par l'itérateur d'entrée b2. Utilise le prédicat p pour tester, ou l'opérateur "=" si le prédicat p n'est pas spécifié.

H 11(b, e, c)

Définit les éléments de la cécité donnés par les itérateurs canins b et e égaux à la valeur c. Renvoie la valeur de r(nb(b, e, c)

r(n0 (r(b, e, p)

Renvoie un iterpore désignant la première itération de la valeur c, ou un itérateur pointant vers l'élément pour lequel le prévicat p est vrai (s'il en existe un) dans la séquence donnée par les itérateurs b et e. Renvoie e si cet élément n'est pas exister

1ex(condgvr sv1 conpvge(b, e, b2, e2)

1ex(condgvp(c1 conp(b, e, b2, e2, p)

Renvoie une valeur booléenne indiquant si la succession d'éléments dans la plage [b, e) est inférieure à la succession d'éléments dans la plage [b2, e2). Pour comparer des éléments, utilisez le prédicat p ou l'opérateur "

pvc(s1, s2)

Renvoie la plus grande (deux fonctions pvc) ou la plus petite (en fonction de la fonction bn) k3 valeurs données par les arguments c1 et c2 qui ont tous deux pvc pdig type e1epeps(b.e) nmp e1epeps(b, e) Renvoie un itérateur pointant au plus grand (plus petit) ) un élément de la pastelgabilité donnée par les éléments de jeu à sens unique b n'est pas

Appendice B Bibliothèque standard(courte critique)