| 1 |
<!-- $Header: /var/lib/cvs/pgsql-fr/sgml/array.sgml,v 1.17 2005/07/15 06:14:20 guillaume Exp $ --> |
|---|
| 2 |
|
|---|
| 3 |
<sect1 id="arrays"> |
|---|
| 4 |
<title>Tableaux</title> |
|---|
| 5 |
|
|---|
| 6 |
<indexterm> |
|---|
| 7 |
<primary>tableau</primary> |
|---|
| 8 |
<secondary>array</secondary> |
|---|
| 9 |
</indexterm> |
|---|
| 10 |
|
|---|
| 11 |
<para> |
|---|
| 12 |
<productname>PostgreSQL</productname> autorise de définir des colonnes d'une |
|---|
| 13 |
table comme des tableaux multidimensionnels à longueur variable. Des tableaux |
|---|
| 14 |
de n'importe quel type, même défini par l'utilisateur, peuvent être créés. |
|---|
| 15 |
(Néanmoins, les tableaux de type composite ou de domaines ne sont pas encore |
|---|
| 16 |
supportés.) |
|---|
| 17 |
</para> |
|---|
| 18 |
|
|---|
| 19 |
<sect2> |
|---|
| 20 |
<title>Déclaration des types de tableaux</title> |
|---|
| 21 |
|
|---|
| 22 |
<para> |
|---|
| 23 |
Pour illustrer l'utilisation des types de tableaux, créons cette table : |
|---|
| 24 |
<programlisting> |
|---|
| 25 |
CREATE TABLE sal_emp ( |
|---|
| 26 |
nom text, |
|---|
| 27 |
paye_par_semaine integer[], |
|---|
| 28 |
planning text[][] |
|---|
| 29 |
); |
|---|
| 30 |
</programlisting> |
|---|
| 31 |
Comme indiqué ci-dessus, un type de donnée tableau est nommé en ajoutant des |
|---|
| 32 |
crochets (<literal>[]</>) au type de donnée des éléments du tableau. La |
|---|
| 33 |
commande ci-dessus créera une table nommée <structname>sal_emp</structname> |
|---|
| 34 |
avec une colonne de type <type>text</type> (<structfield>nom</structfield>), |
|---|
| 35 |
un tableau à une dimension de type <type>integer</type> |
|---|
| 36 |
(<structfield>paye_par_semaine</structfield>), représentant le salaire d'un |
|---|
| 37 |
employé par semaine et un tableau à deux dimensions de type |
|---|
| 38 |
<type>text</type> (<structfield>planning</structfield>), représentant le |
|---|
| 39 |
planning hebdomadaire de l'employé. |
|---|
| 40 |
</para> |
|---|
| 41 |
|
|---|
| 42 |
<para> |
|---|
| 43 |
La syntaxe pour <command>CREATE TABLE</command> permet de spécifier la taille |
|---|
| 44 |
exacte des tableaux, par exemple : |
|---|
| 45 |
|
|---|
| 46 |
<programlisting> |
|---|
| 47 |
CREATE TABLE tictactoe ( |
|---|
| 48 |
carres integer[3][3] |
|---|
| 49 |
); |
|---|
| 50 |
</programlisting> |
|---|
| 51 |
|
|---|
| 52 |
Néanmoins, l'implémentation actuelle n'oblige pas au respect des limites en |
|---|
| 53 |
taille du tableau -- le comportement est identique à celui des tableaux dont |
|---|
| 54 |
la longueur n'a pas été spécifiée. |
|---|
| 55 |
</para> |
|---|
| 56 |
|
|---|
| 57 |
<para> |
|---|
| 58 |
En fait, l'implémentation actuelle n'oblige pas non plus à déclarer le |
|---|
| 59 |
nombre de dimensions. Les tableaux d'un type d'élément particulier sont tous |
|---|
| 60 |
considérés comme étant du même type, sans vérification de la taille ou du |
|---|
| 61 |
nombre de dimensions. Donc, déclarer le nombre de dimensions ou la taille dans |
|---|
| 62 |
<command>CREATE TABLE</command> a uniquement un but de documentation, cela |
|---|
| 63 |
n'affecte pas le comportement lors de l'exécution. |
|---|
| 64 |
</para> |
|---|
| 65 |
|
|---|
| 66 |
<para> |
|---|
| 67 |
Une syntaxe alternative, conforme au standard SQL:1999, pourrait être |
|---|
| 68 |
utilisée pour les tableaux à une dimension. |
|---|
| 69 |
<structfield>paye_par_semaine</structfield> pourrait avoir été définie ainsi : |
|---|
| 70 |
<programlisting> |
|---|
| 71 |
paye_par_semaine integer ARRAY[4], |
|---|
| 72 |
</programlisting> |
|---|
| 73 |
Cette syntaxe nécessite une constante de type entier pour indiquer la taille |
|---|
| 74 |
du tableau. Néanmoins, comme indiqué précédemment, <productname>PostgreSQL</> |
|---|
| 75 |
n'impose aucune restriction sur la taille. |
|---|
| 76 |
</para> |
|---|
| 77 |
</sect2> |
|---|
| 78 |
|
|---|
| 79 |
<sect2> |
|---|
| 80 |
<title>Saisie de valeurs de type tableau</title> |
|---|
| 81 |
|
|---|
| 82 |
<indexterm> |
|---|
| 83 |
<primary>tableau</primary> |
|---|
| 84 |
<secondary>constante</secondary> |
|---|
| 85 |
</indexterm> |
|---|
| 86 |
|
|---|
| 87 |
<para> |
|---|
| 88 |
Pour écrire une valeur de type tableau comme une constante littérale, |
|---|
| 89 |
encadrez les valeurs des éléments par des accolades et séparez-les par des |
|---|
| 90 |
virgules. (Si vous connaissez le C, ce n'est pas différent de la syntaxe C |
|---|
| 91 |
pour initialiser les structures.) Vous pouvez mettre des guillemets doubles |
|---|
| 92 |
autour des valeurs des éléments, et devez le faire si elles |
|---|
| 93 |
contiennent des virgules ou des accolades. (Plus de détails ci-dessous.) |
|---|
| 94 |
Le format général d'une constante de type tableau est donc le |
|---|
| 95 |
suivant : |
|---|
| 96 |
<synopsis> |
|---|
| 97 |
'{ <replaceable>val1</replaceable> <replaceable>delim</replaceable> <replaceable>val2</replaceable> <replaceable>delim</replaceable> ... }' |
|---|
| 98 |
</synopsis> |
|---|
| 99 |
où <replaceable>delim</replaceable> est le caractère de délimitation pour ce |
|---|
| 100 |
type, tel qu'il est enregistré dans son entrée <literal>pg_type</literal>. |
|---|
| 101 |
Parmi les types de données standards fournis par la distribution |
|---|
| 102 |
<productname>PostgreSQL</productname>, le type <literal>box</> utilise un |
|---|
| 103 |
point-virgule (<literal>;</>) mais tous les autres utilisent une virgule |
|---|
| 104 |
(<literal>,</>). Chaque <replaceable>val</replaceable> est soit une constante |
|---|
| 105 |
du type des éléments du tableau ou un sous-tableau. Voici un exemple d'une |
|---|
| 106 |
constante tableau |
|---|
| 107 |
<programlisting> |
|---|
| 108 |
'{{1,2,3},{4,5,6},{7,8,9}}' |
|---|
| 109 |
</programlisting> |
|---|
| 110 |
Cette constante a deux dimensions, un tableau 3 par 3 consistant en trois |
|---|
| 111 |
sous-tableaux d'entiers. |
|---|
| 112 |
</para> |
|---|
| 113 |
|
|---|
| 114 |
<para> |
|---|
| 115 |
(Ces types de constantes de tableau sont en fait un cas particulier |
|---|
| 116 |
des constantes de type générique abordées dans la <xref |
|---|
| 117 |
linkend="sql-syntax-constants-generic">. La constante est traitée |
|---|
| 118 |
initialement comme une chaîne et passée à la routine de conversion d'entrées |
|---|
| 119 |
de tableau. Une spécification explicite du type pourrait être nécessaire.) |
|---|
| 120 |
</para> |
|---|
| 121 |
|
|---|
| 122 |
<para> |
|---|
| 123 |
Maintenant, nous pouvons montrer quelques instructions |
|---|
| 124 |
<command>INSERT</command>. |
|---|
| 125 |
|
|---|
| 126 |
<programlisting> |
|---|
| 127 |
INSERT INTO sal_emp |
|---|
| 128 |
VALUES ('Bill', |
|---|
| 129 |
'{10000, 10000, 10000, 10000}', |
|---|
| 130 |
'{{"rendez-vous", "repas"}, {}}'); |
|---|
| 131 |
|
|---|
| 132 |
INSERT INTO sal_emp |
|---|
| 133 |
VALUES ('Carol', |
|---|
| 134 |
'{20000, 25000, 25000, 25000}', |
|---|
| 135 |
'{{"rencontre", "repas"}, {"rencontre"}}'); |
|---|
| 136 |
ERROR: multidimensional arrays must have array expressions with matching dimensions |
|---|
| 137 |
</programlisting> |
|---|
| 138 |
|
|---|
| 139 |
Notez que les tableaux à plusieurs dimensions doivent avoir des limites |
|---|
| 140 |
correspondantes pour chaque dimension. Une différence provoque une erreur à |
|---|
| 141 |
l'exécution. |
|---|
| 142 |
|
|---|
| 143 |
<programlisting> |
|---|
| 144 |
INSERT INTO sal_emp |
|---|
| 145 |
VALUES ('Bill', |
|---|
| 146 |
'{10000, 10000, 10000, 10000}', |
|---|
| 147 |
'{{"rencontre", "repas"}, {"entrainement", "présentation"}}'); |
|---|
| 148 |
|
|---|
| 149 |
INSERT INTO sal_emp |
|---|
| 150 |
VALUES ('Carol', |
|---|
| 151 |
'{20000, 25000, 25000, 25000}', |
|---|
| 152 |
'{{"petit-déjeuner", "consulting"}, {"rencontre", "repas"}}'); |
|---|
| 153 |
</programlisting> |
|---|
| 154 |
</para> |
|---|
| 155 |
|
|---|
| 156 |
<para> |
|---|
| 157 |
Une limitation de l'implémentation actuelle des tableaux existe, les éléments |
|---|
| 158 |
individuels d'un tableau ne peuvent avoir la valeur SQL NULL. Le tableau |
|---|
| 159 |
entier peut être NULL mais vous ne pouvez pas avoir des éléments NULL dans |
|---|
| 160 |
un tableau avec d'autres éléments non NULL. (Ceci est susceptible de changer |
|---|
| 161 |
dans le futur.) |
|---|
| 162 |
</para> |
|---|
| 163 |
|
|---|
| 164 |
<para> |
|---|
| 165 |
Le résultat des deux insertions précédentes ressemble à ceci : |
|---|
| 166 |
<programlisting> |
|---|
| 167 |
SELECT * FROM sal_emp; |
|---|
| 168 |
nom | paye_par_semaine | planning |
|---|
| 169 |
-------+---------------------------+-------------------- |
|---|
| 170 |
Bill | {10000,10000,10000,10000} | {{rencontre,repas},{entrainement,présentation}} |
|---|
| 171 |
Carol | {20000,25000,25000,25000} | {{petit-déjeuner,consulting},{rencontre,repas}} |
|---|
| 172 |
(2 rows) |
|---|
| 173 |
</programlisting> |
|---|
| 174 |
</para> |
|---|
| 175 |
|
|---|
| 176 |
<para> |
|---|
| 177 |
La syntaxe du constructeur <literal>ARRAY</literal> peut aussi être |
|---|
| 178 |
utilisée : |
|---|
| 179 |
<programlisting> |
|---|
| 180 |
INSERT INTO sal_emp |
|---|
| 181 |
VALUES ('Bill', |
|---|
| 182 |
ARRAY[10000, 10000, 10000, 10000], |
|---|
| 183 |
ARRAY[['rendez-vous', 'repas'], ['entrainement','présentation']]); |
|---|
| 184 |
|
|---|
| 185 |
INSERT INTO sal_emp |
|---|
| 186 |
VALUES ('Carol', |
|---|
| 187 |
ARRAY[20000, 25000, 25000, 25000], |
|---|
| 188 |
ARRAY[['petit-déjeuner', 'consulting'], ['rencontre', 'repas']]); |
|---|
| 189 |
</programlisting> |
|---|
| 190 |
Notez que les éléments du tableau sont des constantes SQL ordinaires ou |
|---|
| 191 |
des expressions ; par exemple, les chaînes de caractères littérales sont |
|---|
| 192 |
encadrées par des guillemets simples au lieu de guillemets doubles comme cela |
|---|
| 193 |
serait le cas dans un tableau littéral. La syntaxe du constructeur |
|---|
| 194 |
<literal>ARRAY</> est discutée plus en profondeur dans la <xref |
|---|
| 195 |
linkend="sql-syntax-array-constructors">. |
|---|
| 196 |
</para> |
|---|
| 197 |
|
|---|
| 198 |
</sect2> |
|---|
| 199 |
|
|---|
| 200 |
<sect2> |
|---|
| 201 |
<title>Accès aux tableaux</title> |
|---|
| 202 |
|
|---|
| 203 |
<para> |
|---|
| 204 |
Maintenant, nous pouvons lancer quelques requêtes sur la table. Tout d'abord, |
|---|
| 205 |
montrons comment accéder à un seul élément du tableau à la fois. Cette |
|---|
| 206 |
requête retrouve le nom des employés dont la paye a changé la deuxième |
|---|
| 207 |
semaine : |
|---|
| 208 |
|
|---|
| 209 |
<programlisting> |
|---|
| 210 |
SELECT nom FROM sal_emp WHERE paye_par_semaine[1] <> paye_par_semaine[2]; |
|---|
| 211 |
|
|---|
| 212 |
nom |
|---|
| 213 |
------- |
|---|
| 214 |
Carol |
|---|
| 215 |
(1 row) |
|---|
| 216 |
</programlisting> |
|---|
| 217 |
|
|---|
| 218 |
Les nombres du tableau sont écrit entre crochets. Par défaut, |
|---|
| 219 |
<productname>PostgreSQL</productname> utilise la convention des nombres |
|---|
| 220 |
commençant à 1 pour les tableaux, c'est-à-dire un tableau à |
|---|
| 221 |
<replaceable>n</> éléments commence avec <literal>array[1]</literal> et finit |
|---|
| 222 |
avec <literal>array[<replaceable>n</>]</literal>. |
|---|
| 223 |
</para> |
|---|
| 224 |
|
|---|
| 225 |
<para> |
|---|
| 226 |
Cette requête récupère la paye de la troisième semaine pour tous les |
|---|
| 227 |
employés : |
|---|
| 228 |
|
|---|
| 229 |
<programlisting> |
|---|
| 230 |
SELECT paye_par_semaine[3] FROM sal_emp; |
|---|
| 231 |
|
|---|
| 232 |
paye_par_semaine |
|---|
| 233 |
------------------ |
|---|
| 234 |
10000 |
|---|
| 235 |
25000 |
|---|
| 236 |
(2 rows) |
|---|
| 237 |
</programlisting> |
|---|
| 238 |
</para> |
|---|
| 239 |
|
|---|
| 240 |
<para> |
|---|
| 241 |
Nous pouvons aussi accéder à des parties rectangulaires arbitraires ou à des |
|---|
| 242 |
sous-tableaux. Une partie d'un tableau est notée par l'écriture |
|---|
| 243 |
<literal><replaceable>extrémité basse</replaceable>:<replaceable>extrémité haute</replaceable></literal> |
|---|
| 244 |
quelle que soit la dimension des tableaux. Par exemple, cette requête retrouve |
|---|
| 245 |
le premier élément du planning de Bill pour les deux premiers jours de la |
|---|
| 246 |
semaine : |
|---|
| 247 |
|
|---|
| 248 |
<programlisting> |
|---|
| 249 |
SELECT planning[1:2][1:1] FROM sal_emp WHERE nom = 'Bill'; |
|---|
| 250 |
|
|---|
| 251 |
planning |
|---|
| 252 |
-------------------- |
|---|
| 253 |
{{rendez-vous},{entrainement}} |
|---|
| 254 |
(1 row) |
|---|
| 255 |
</programlisting> |
|---|
| 256 |
|
|---|
| 257 |
Nous aurions aussi pu écrire |
|---|
| 258 |
|
|---|
| 259 |
<programlisting> |
|---|
| 260 |
SELECT planning[1:2][1] FROM sal_emp WHERE nom = 'Bill'; |
|---|
| 261 |
</programlisting> |
|---|
| 262 |
|
|---|
| 263 |
en ayant le même résultat. Une opération d'indiçage de rangée est toujours |
|---|
| 264 |
prise pour représenter une tranche de rangée si un indice quelconque est |
|---|
| 265 |
écrit sous la forme |
|---|
| 266 |
<literal><replaceable>inférieur</replaceable>:<replaceable>supérieur</replaceable></literal>. |
|---|
| 267 |
Une limite basse de 1 est supposée pour toute tranche dont seule une valeur |
|---|
| 268 |
est spécifiée. Voici un autre exemple : |
|---|
| 269 |
<programlisting> |
|---|
| 270 |
SELECT planning[1:2][2] FROM sal_emp WHERE nom = 'Bill'; |
|---|
| 271 |
|
|---|
| 272 |
planning |
|---|
| 273 |
--------------------------- |
|---|
| 274 |
{{rendez-vous,repas},{entrainement,présentation}} |
|---|
| 275 |
(1 row) |
|---|
| 276 |
</programlisting> |
|---|
| 277 |
</para> |
|---|
| 278 |
|
|---|
| 279 |
<para> |
|---|
| 280 |
Récupérer en dehors des limites actuelles d'un tableau amène une valeur SQL |
|---|
| 281 |
NULL, pas une erreur. Par exemple, si <literal>planning</> a les dimensions |
|---|
| 282 |
<literal>[1:3][1:2]</>, alors référencer <literal>planning[3][3]</> a un |
|---|
| 283 |
résultat NULL. De la même façon, une référence sur un tableau avec le mauvais |
|---|
| 284 |
nombre d'indices amène une valeur NULL plutôt qu'une erreur. Récupérer une |
|---|
| 285 |
partie d'un tableau complètement en dehors des limites actuelles renvoie un |
|---|
| 286 |
tableau NULL ; mais si la partie demandée est partiellement intégrée aux |
|---|
| 287 |
limites du tableau, alors il est silencieusement réduit à la région |
|---|
| 288 |
d'intersection. |
|---|
| 289 |
</para> |
|---|
| 290 |
|
|---|
| 291 |
<para> |
|---|
| 292 |
Les dimensions actuelles de toute valeur d'un tableau sont disponibles avec la |
|---|
| 293 |
fonction <function>array_dims</function> : |
|---|
| 294 |
|
|---|
| 295 |
<programlisting> |
|---|
| 296 |
SELECT array_dims(planning) FROM sal_emp WHERE nom = 'Carol'; |
|---|
| 297 |
|
|---|
| 298 |
array_dims |
|---|
| 299 |
------------ |
|---|
| 300 |
[1:2][1:2] |
|---|
| 301 |
(1 row) |
|---|
| 302 |
</programlisting> |
|---|
| 303 |
|
|---|
| 304 |
<function>array_dims</function> donne un résultat de type <type>text</type>, |
|---|
| 305 |
ce qui est pratique à lire mais peut-être moins simple à interpréter pour les |
|---|
| 306 |
programmes. Les dimensions sont aussi récupérables avec |
|---|
| 307 |
<function>array_upper</function> et <function>array_lower</function>, qui |
|---|
| 308 |
renvoient respectivement la limite haute et basse d'un tableau spécifié. |
|---|
| 309 |
|
|---|
| 310 |
<programlisting> |
|---|
| 311 |
SELECT array_upper(planning, 1) FROM sal_emp WHERE nom = 'Carol'; |
|---|
| 312 |
|
|---|
| 313 |
array_upper |
|---|
| 314 |
------------- |
|---|
| 315 |
2 |
|---|
| 316 |
(1 row) |
|---|
| 317 |
</programlisting> |
|---|
| 318 |
</para> |
|---|
| 319 |
</sect2> |
|---|
| 320 |
|
|---|
| 321 |
<sect2> |
|---|
| 322 |
<title>Modification de tableaux</title> |
|---|
| 323 |
|
|---|
| 324 |
<para> |
|---|
| 325 |
La valeur d'un tableau peut être complètement remplacée : |
|---|
| 326 |
|
|---|
| 327 |
<programlisting> |
|---|
| 328 |
UPDATE sal_emp SET paye_par_semaine = '{25000,25000,27000,27000}' |
|---|
| 329 |
WHERE nom = 'Carol'; |
|---|
| 330 |
</programlisting> |
|---|
| 331 |
|
|---|
| 332 |
ou en utilisant la syntaxe de l'expression <literal>ARRAY</literal> : |
|---|
| 333 |
|
|---|
| 334 |
<programlisting> |
|---|
| 335 |
UPDATE sal_emp SET paye_par_semaine = ARRAY[25000,25000,27000,27000] |
|---|
| 336 |
WHERE nom = 'Carol'; |
|---|
| 337 |
</programlisting> |
|---|
| 338 |
|
|---|
| 339 |
On peut aussi mettre à jour un seul élément d'un tableau : |
|---|
| 340 |
|
|---|
| 341 |
<programlisting> |
|---|
| 342 |
UPDATE sal_emp SET paye_par_semaine[4] = 15000 |
|---|
| 343 |
WHERE nom = 'Bill'; |
|---|
| 344 |
</programListing> |
|---|
| 345 |
|
|---|
| 346 |
ou faire une mise à jour par tranche : |
|---|
| 347 |
|
|---|
| 348 |
<programlisting> |
|---|
| 349 |
UPDATE sal_emp SET paye_par_semaine[1:2] = '{27000,27000}' |
|---|
| 350 |
WHERE nom = 'Carol'; |
|---|
| 351 |
</programlisting> |
|---|
| 352 |
|
|---|
| 353 |
</para> |
|---|
| 354 |
|
|---|
| 355 |
<para> |
|---|
| 356 |
Une valeur de tableau enregistrée peut être agrandie pour affecter un élément |
|---|
| 357 |
adjacent à ceux déjà présents ou en affectant à une partie adjacente |
|---|
| 358 |
une partie des données déjà présentes. Par exemple, si le tableau |
|---|
| 359 |
<literal>mon_tableau</> a pour le moment quatre éléments, il en aura cinq après |
|---|
| 360 |
une mise à jour qui a affecté <literal>mon_tableau[5]</>. Actuellement, |
|---|
| 361 |
l'agrandissement de cette façon est seulement autorisé pour les tableaux à |
|---|
| 362 |
une dimension, et non pas pour les tableaux multidimensionnels. |
|---|
| 363 |
</para> |
|---|
| 364 |
|
|---|
| 365 |
<para> |
|---|
| 366 |
L'affectation de parties d'un tableau permet la création de tableaux dont |
|---|
| 367 |
l'indice de départ n'est pas 1. Par exemple, vous pourriez affecter |
|---|
| 368 |
<literal>mon_tableau[-2:7]</> pour créer un tableau avec les valeurs d'indices |
|---|
| 369 |
allant de -2 à 7. |
|---|
| 370 |
</para> |
|---|
| 371 |
|
|---|
| 372 |
<para> |
|---|
| 373 |
Les valeurs de nouveaux tableaux peuvent aussi être construites en utilisant |
|---|
| 374 |
l'opérateur de concaténation, |
|---|
| 375 |
<literal>||</literal>. |
|---|
| 376 |
<programlisting> |
|---|
| 377 |
SELECT ARRAY[1,2] || ARRAY[3,4]; |
|---|
| 378 |
?column? |
|---|
| 379 |
--------------- |
|---|
| 380 |
{1,2,3,4} |
|---|
| 381 |
(1 row) |
|---|
| 382 |
|
|---|
| 383 |
SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]]; |
|---|
| 384 |
?column? |
|---|
| 385 |
--------------------- |
|---|
| 386 |
{{5,6},{1,2},{3,4}} |
|---|
| 387 |
(1 row) |
|---|
| 388 |
</programlisting> |
|---|
| 389 |
</para> |
|---|
| 390 |
|
|---|
| 391 |
<para> |
|---|
| 392 |
L'opérateur de concaténation autorise un élément à être placé au début ou à |
|---|
| 393 |
la fin d'un tableau à une dimension. Il accepte aussi deux tableaux à |
|---|
| 394 |
<replaceable>N</> dimensions, ou un tableau à <replaceable>N</> dimensions |
|---|
| 395 |
et un à <replaceable>N+1</> dimensions. |
|---|
| 396 |
</para> |
|---|
| 397 |
|
|---|
| 398 |
<para> |
|---|
| 399 |
Lorsqu'un élément seul est placé au début d'un tableau à une dimension, le |
|---|
| 400 |
résultat est un tableau disposant d'une limite inférieure égale à la limite |
|---|
| 401 |
inférieure de l'opérande du côté droit moins un. Lorsqu'un élément est placé |
|---|
| 402 |
à la fin d'un tableau à une dimension, le résultat est un tableau contenant la |
|---|
| 403 |
limite inférieure de l'opérande gauche. Par exemple : |
|---|
| 404 |
<programlisting> |
|---|
| 405 |
SELECT array_dims(1 || ARRAY[2,3]); |
|---|
| 406 |
array_dims |
|---|
| 407 |
------------ |
|---|
| 408 |
[0:2] |
|---|
| 409 |
(1 row) |
|---|
| 410 |
|
|---|
| 411 |
SELECT array_dims(ARRAY[1,2] || 3); |
|---|
| 412 |
array_dims |
|---|
| 413 |
------------ |
|---|
| 414 |
[1:3] |
|---|
| 415 |
(1 row) |
|---|
| 416 |
</programlisting> |
|---|
| 417 |
</para> |
|---|
| 418 |
|
|---|
| 419 |
<para> |
|---|
| 420 |
Lorsque deux tableaux ayant un même nombre de dimensions sont concaténés, le |
|---|
| 421 |
résultat conserve la limite inférieure de l'opérande gauche. Le résultat est |
|---|
| 422 |
un tableau comprenant chaque élément de l'opérande gauche suivi de chaque |
|---|
| 423 |
élément de l'opérande droit. Par exemple : |
|---|
| 424 |
<programlisting> |
|---|
| 425 |
SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]); |
|---|
| 426 |
array_dims |
|---|
| 427 |
------------ |
|---|
| 428 |
[1:5] |
|---|
| 429 |
(1 row) |
|---|
| 430 |
|
|---|
| 431 |
SELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]); |
|---|
| 432 |
array_dims |
|---|
| 433 |
------------ |
|---|
| 434 |
[1:5][1:2] |
|---|
| 435 |
(1 row) |
|---|
| 436 |
</programlisting> |
|---|
| 437 |
</para> |
|---|
| 438 |
|
|---|
| 439 |
<para> |
|---|
| 440 |
Lorsqu'un tableau à <replaceable>N</> dimensions est placé au début ou à la |
|---|
| 441 |
fin d'un tableau à <replaceable>N+1</> dimensions, le résultat est analogue au |
|---|
| 442 |
cas ci-dessus. Chaque sous-tableau de dimension <replaceable>N</> est en |
|---|
| 443 |
quelque sorte un élément de la dimension externe d'un tableau à |
|---|
| 444 |
<replaceable>N+1</> dimensions. Par exemple : |
|---|
| 445 |
<programlisting> |
|---|
| 446 |
SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]); |
|---|
| 447 |
array_dims |
|---|
| 448 |
------------ |
|---|
| 449 |
[0:2][1:2] |
|---|
| 450 |
(1 row) |
|---|
| 451 |
</programlisting> |
|---|
| 452 |
</para> |
|---|
| 453 |
|
|---|
| 454 |
<para> |
|---|
| 455 |
Un tableau peut aussi être construit en utilisant les fonctions |
|---|
| 456 |
<function>array_prepend</function>, <function>array_append</function> |
|---|
| 457 |
ou <function>array_cat</function>. Les deux premières supportent seulement les |
|---|
| 458 |
tableaux à une dimension alors que <function>array_cat</function> supporte les |
|---|
| 459 |
tableaux multidimensionnels. |
|---|
| 460 |
|
|---|
| 461 |
Notez que l'opérateur de concaténation vu ci-dessus est préféré à |
|---|
| 462 |
l'utilisation directe de ces fonctions. En fait, les fonctions sont utilisées |
|---|
| 463 |
principalement pour l'implémentation de l'opérateur de concaténation. |
|---|
| 464 |
Néanmoins, elles pourraient être directement utiles dans la création |
|---|
| 465 |
d'agrégats définis par l'utilisateur. Quelques exemples : |
|---|
| 466 |
|
|---|
| 467 |
<programlisting> |
|---|
| 468 |
SELECT array_prepend(1, ARRAY[2,3]); |
|---|
| 469 |
array_prepend |
|---|
| 470 |
--------------- |
|---|
| 471 |
{1,2,3} |
|---|
| 472 |
(1 row) |
|---|
| 473 |
|
|---|
| 474 |
SELECT array_append(ARRAY[1,2], 3); |
|---|
| 475 |
array_append |
|---|
| 476 |
-------------- |
|---|
| 477 |
{1,2,3} |
|---|
| 478 |
(1 row) |
|---|
| 479 |
|
|---|
| 480 |
SELECT array_cat(ARRAY[1,2], ARRAY[3,4]); |
|---|
| 481 |
array_cat |
|---|
| 482 |
--------------- |
|---|
| 483 |
{1,2,3,4} |
|---|
| 484 |
(1 row) |
|---|
| 485 |
|
|---|
| 486 |
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]); |
|---|
| 487 |
array_cat |
|---|
| 488 |
--------------------- |
|---|
| 489 |
{{1,2},{3,4},{5,6}} |
|---|
| 490 |
(1 row) |
|---|
| 491 |
|
|---|
| 492 |
SELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]); |
|---|
| 493 |
array_cat |
|---|
| 494 |
--------------------- |
|---|
| 495 |
{{5,6},{1,2},{3,4}} |
|---|
| 496 |
</programlisting> |
|---|
| 497 |
</para> |
|---|
| 498 |
</sect2> |
|---|
| 499 |
|
|---|
| 500 |
<sect2> |
|---|
| 501 |
<title>Recherche dans des tableaux</title> |
|---|
| 502 |
|
|---|
| 503 |
<para> |
|---|
| 504 |
Pour rechercher une valeur dans un tableau, vous devez vérifier chaque valeur |
|---|
| 505 |
dans le tableau. Ceci peut se faire à la main si vous connaissez la taille du |
|---|
| 506 |
tableau. Par exemple : |
|---|
| 507 |
|
|---|
| 508 |
<programlisting> |
|---|
| 509 |
SELECT * FROM sal_emp WHERE paye_par_semaine[1] = 10000 OR |
|---|
| 510 |
paye_par_semaine[2] = 10000 OR |
|---|
| 511 |
paye_par_semaine[3] = 10000 OR |
|---|
| 512 |
paye_par_semaine[4] = 10000; |
|---|
| 513 |
</programlisting> |
|---|
| 514 |
|
|---|
| 515 |
Néanmoins, ceci devient rapidement fastidieux pour les gros tableaux et n'est |
|---|
| 516 |
pas très utile si la taille du tableau n'est pas connue. Une autre méthode |
|---|
| 517 |
est décrite dans <xref linkend="functions-comparisons">. La requête ci-dessus |
|---|
| 518 |
est remplaçable par : |
|---|
| 519 |
|
|---|
| 520 |
<programlisting> |
|---|
| 521 |
SELECT * FROM sal_emp WHERE 10000 = ANY (paye_par_semaine); |
|---|
| 522 |
</programlisting> |
|---|
| 523 |
|
|---|
| 524 |
De plus, vous pouvez trouvez les lignes où le tableau n'a que des valeurs |
|---|
| 525 |
égales à 10000 avec : |
|---|
| 526 |
|
|---|
| 527 |
<programlisting> |
|---|
| 528 |
SELECT * FROM sal_emp WHERE 10000 = ALL (paye_par_semaine); |
|---|
| 529 |
</programlisting> |
|---|
| 530 |
|
|---|
| 531 |
</para> |
|---|
| 532 |
|
|---|
| 533 |
<tip> |
|---|
| 534 |
<para> |
|---|
| 535 |
Les tableaux ne sont pas toujours initialisés ; rechercher des éléments |
|---|
| 536 |
spécifiques d'un tableau pourrait être un signe d'une mauvaise conception de |
|---|
| 537 |
la base de données. Utilisez plutôt une table séparée avec une |
|---|
| 538 |
ligne pour chaque élément faisant parti du tableau. Cela sera plus simple |
|---|
| 539 |
pour une recherche et fonctionnera mieux dans le cas d'un grand nombre |
|---|
| 540 |
d'éléments. |
|---|
| 541 |
</para> |
|---|
| 542 |
</tip> |
|---|
| 543 |
</sect2> |
|---|
| 544 |
|
|---|
| 545 |
<sect2> |
|---|
| 546 |
<title>Syntaxe d'entrée et de sortie des tableaux</title> |
|---|
| 547 |
|
|---|
| 548 |
<para> |
|---|
| 549 |
La représentation externe du type texte d'une valeur d'un tableau consiste en |
|---|
| 550 |
des éléments interprétés suivant les règles de conversion d'entrées/sorties |
|---|
| 551 |
pour le type de l'élément du tableau, plus des décorations indiquant la |
|---|
| 552 |
structure du tableau. L'affichage consiste en des accolades (<literal>{</> |
|---|
| 553 |
et <literal>}</>) autour des valeurs du tableau et des caractères de |
|---|
| 554 |
délimitation entre éléments adjacents. Le caractère délimiteur est |
|---|
| 555 |
habituellement une virgule (<literal>,</>) mais peut être autre chose : |
|---|
| 556 |
il est déterminé par le paramètre <literal>typdelim</> du type de l'élément |
|---|
| 557 |
tableau (parmi les types de données standards supportés par l'implémentation |
|---|
| 558 |
de <productname>PostgreSQL</productname>, le type <literal>box</> utilise un |
|---|
| 559 |
point-virgule (<literal>;</>) mais tous les autres utilisent la virgule). |
|---|
| 560 |
Dans un tableau multidimensionnel, chaque dimension (row, plane, cube, etc.) |
|---|
| 561 |
utilise son propre niveau d'accolades et les délimiteurs doivent être |
|---|
| 562 |
utilisés entre des entités adjacentes au sein d'accolades de même niveau. |
|---|
| 563 |
</para> |
|---|
| 564 |
|
|---|
| 565 |
<para> |
|---|
| 566 |
La routine de sortie du tableau placera des guillemets doubles autour des |
|---|
| 567 |
valeurs des éléments si elles sont des chaînes vides ou contiennent des |
|---|
| 568 |
accolades, des caractères délimiteurs, des guillemets doubles, des antislash |
|---|
| 569 |
ou des espaces. Les guillemets doubles et les antislash intégrés aux valeurs |
|---|
| 570 |
des éléments seront échappés avec un antislash. Pour les types de données |
|---|
| 571 |
numériques, on peut supposer sans risque que les doubles guillemets |
|---|
| 572 |
n'apparaîtront jamais, mais pour les types de données texte, vous devez vous |
|---|
| 573 |
préparer à gérer la présence et l'absence de guillemets. (Ceci est un |
|---|
| 574 |
changement du comportement à partir de la version pré-7.2 de |
|---|
| 575 |
<productname>PostgreSQL</productname>.) |
|---|
| 576 |
</para> |
|---|
| 577 |
|
|---|
| 578 |
<para> |
|---|
| 579 |
Par défaut, la valeur de la limite basse d'un tableau est initialisée à 1. |
|---|
| 580 |
Si une des dimensions du tableau a une limite basse différente de 1, un |
|---|
| 581 |
affichage supplémentaire indiquant les dimensions réelles du tableau |
|---|
| 582 |
précède l'affichage de la structure du tableau. Cet affichage consiste |
|---|
| 583 |
en des crochets (<literal>[]</>) autour de chaque limite basse et haute d'une |
|---|
| 584 |
dimension avec un délimiteur deux-points (<literal>:</>) entre chaque. |
|---|
| 585 |
L'affichage des dimensions du tableau est suivie par un signe d'égalité |
|---|
| 586 |
(<literal>=</>). Par exemple : |
|---|
| 587 |
<programlisting> |
|---|
| 588 |
SELECT 1 || ARRAY[2,3] AS array; |
|---|
| 589 |
|
|---|
| 590 |
array |
|---|
| 591 |
--------------- |
|---|
| 592 |
[0:2]={1,2,3} |
|---|
| 593 |
(1 row) |
|---|
| 594 |
|
|---|
| 595 |
SELECT ARRAY[1,2] || ARRAY[[3,4]] AS array; |
|---|
| 596 |
|
|---|
| 597 |
array |
|---|
| 598 |
-------------------------- |
|---|
| 599 |
[0:1][1:2]={{1,2},{3,4}} |
|---|
| 600 |
(1 row) |
|---|
| 601 |
</programlisting> |
|---|
| 602 |
</para> |
|---|
| 603 |
|
|---|
| 604 |
<para> |
|---|
| 605 |
Cette syntaxe peut aussi être utilisée pour spécifier des indices de tableau |
|---|
| 606 |
différents des indices par défaut. Par exemple : |
|---|
| 607 |
<programlisting> |
|---|
| 608 |
SELECT f1[1][-2][3] AS e1, f1[1][-1][5] AS e2 |
|---|
| 609 |
FROM (SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[] AS f1) AS ss; |
|---|
| 610 |
|
|---|
| 611 |
e1 | e2 |
|---|
| 612 |
----+---- |
|---|
| 613 |
1 | 6 |
|---|
| 614 |
(1 row) |
|---|
| 615 |
</programlisting> |
|---|
| 616 |
</para> |
|---|
| 617 |
|
|---|
| 618 |
<para> |
|---|
| 619 |
Comme indiqué précédemment, lors de l'écriture d'une valeur de tableau, vous |
|---|
| 620 |
pourriez écrire des guillemets doubles autour de chaque élément individuel de |
|---|
| 621 |
tableau. Vous <emphasis>devez</> le faire si leur absence autour d'un élément |
|---|
| 622 |
induit en erreur l'analyseur de la valeur du tableau. Par exemple, les |
|---|
| 623 |
éléments contenant des crochets, virgules (ou un caractère délimiteur), |
|---|
| 624 |
guillemets doubles, antislashs ou espace (en début comme en fin) doivent |
|---|
| 625 |
avoir des guillemets doubles. Pour placer un guillemet double ou un antislash |
|---|
| 626 |
dans une valeur d'élément d'un tableau, faites-le précéder d'un antislash. |
|---|
| 627 |
Autrement, vous pouvez échapper tous les caractères de données qui sont |
|---|
| 628 |
utilisés dans la syntaxe du tableau. |
|---|
| 629 |
</para> |
|---|
| 630 |
|
|---|
| 631 |
<para> |
|---|
| 632 |
Vous pouvez ajouter des espaces avant un crochet gauche ou après un crochet |
|---|
| 633 |
droit. Vous pouvez aussi ajouter des espaces avant tout élément individuel. |
|---|
| 634 |
Dans tous les cas, les espaces seront ignorés. Par contre, les espaces à |
|---|
| 635 |
l'intérieur des éléments entre guillemets doubles ou entourés par des |
|---|
| 636 |
caractères autres que des espaces ne sont pas ignorés. |
|---|
| 637 |
</para> |
|---|
| 638 |
|
|---|
| 639 |
<note> |
|---|
| 640 |
<para> |
|---|
| 641 |
Rappelez-vous que ce que vous écrivez comme commande SQL sera tout d'abord |
|---|
| 642 |
interprété en tant que chaîne littérale puis en tant que tableau. Ceci |
|---|
| 643 |
double le nombre d'antislash dont vous aurez besoin. Par exemple, pour |
|---|
| 644 |
insérer une valeur de tableau de type <type>text</> contenant un antislash |
|---|
| 645 |
et un guillemet double, vous aurez besoin d'écrire |
|---|
| 646 |
<programlisting> |
|---|
| 647 |
INSERT ... VALUES ('{"\\\\","\\""}'); |
|---|
| 648 |
</programlisting> |
|---|
| 649 |
Le processeur de la chaîne littérale supprime un niveau d'antislash, donc |
|---|
| 650 |
ce qui arrive à l'analyseur de tableau ressemble à <literal>{"\\","\""}</>. |
|---|
| 651 |
À la place, les chaînes remplissant l'entrée du type de données |
|---|
| 652 |
<type>text</> deviennent respectivement <literal>\</> et <literal>"</>. |
|---|
| 653 |
(Si nous travaillions avec un type de données dont la routine d'entrée |
|---|
| 654 |
traitait aussi les antislash de manière spéciale, <type>bytea</> par |
|---|
| 655 |
exemple, nous pourrions avoir besoin d'au plus huit antislash dans la |
|---|
| 656 |
commande pour en obtenir un dans l'élément stocké.) |
|---|
| 657 |
Les guillemets dollar (voir <xref linkend="sql-syntax-dollar-quoting">) |
|---|
| 658 |
pourraient être utilisés pour éviter le besoin des doubles antislashs. |
|---|
| 659 |
</para> |
|---|
| 660 |
</note> |
|---|
| 661 |
|
|---|
| 662 |
<tip> |
|---|
| 663 |
<para> |
|---|
| 664 |
La syntaxe du constructeur <literal>ARRAY</> (voir <xref |
|---|
| 665 |
linkend="sql-syntax-array-constructors">) est souvent plus facile à utiliser |
|---|
| 666 |
que la syntaxe du tableau littéral lors de l'écriture de valeurs du tableau |
|---|
| 667 |
en commandes SQL. Avec <literal>ARRAY</>, les valeurs de l'élément individuel |
|---|
| 668 |
sont écrites de la même façon qu'elles auraient été écrites si elles |
|---|
| 669 |
n'avaient pas fait partie d'un tableau. |
|---|
| 670 |
</para> |
|---|
| 671 |
</tip> |
|---|
| 672 |
</sect2> |
|---|
| 673 |
|
|---|
| 674 |
</sect1> |
|---|