| 1 |
<?xml version="1.0" encoding="ISO-8859-15"?> |
|---|
| 2 |
<!-- Dernière modification |
|---|
| 3 |
le $Date$ |
|---|
| 4 |
par $Author$ |
|---|
| 5 |
révision $Revision$ --> |
|---|
| 6 |
<!-- SAS : 20080319, PG831 --> |
|---|
| 7 |
|
|---|
| 8 |
<sect1 id="arrays"> |
|---|
| 9 |
<title>Tableaux</title> |
|---|
| 10 |
|
|---|
| 11 |
<indexterm> |
|---|
| 12 |
<primary>tableau</primary> |
|---|
| 13 |
<secondary>array</secondary> |
|---|
| 14 |
</indexterm> |
|---|
| 15 |
|
|---|
| 16 |
<para> |
|---|
| 17 |
<productname>PostgreSQL</productname> permet de définir des colonnes de |
|---|
| 18 |
table comme des tableaux multidimensionnels de longueur variable. Il est |
|---|
| 19 |
possible de créer des tableaux de n'importe quel type utilisateur : |
|---|
| 20 |
de base, composé, enum. Toutefois, les tableaux de domaines ne sont pas |
|---|
| 21 |
encore supportés. |
|---|
| 22 |
</para> |
|---|
| 23 |
|
|---|
| 24 |
<sect2> |
|---|
| 25 |
<title>Déclaration des types tableaux</title> |
|---|
| 26 |
|
|---|
| 27 |
<para> |
|---|
| 28 |
La création de la table suivante permet d'illustrer l'utilisation des types |
|---|
| 29 |
tableaux : |
|---|
| 30 |
<programlisting>CREATE TABLE sal_emp ( |
|---|
| 31 |
nom text, |
|---|
| 32 |
paye_par_semaine integer[], |
|---|
| 33 |
planning text[][] |
|---|
| 34 |
);</programlisting> |
|---|
| 35 |
Comme indiqué ci-dessus, un type de données tableau est nommé en ajoutant des |
|---|
| 36 |
crochets (<literal>[]</literal>) au type de données des éléments du tableau. La |
|---|
| 37 |
commande ci-dessus crée une table nommée <structname>sal_emp</structname> |
|---|
| 38 |
avec une colonne de type <type>text</type> (<structfield>nom</structfield>), |
|---|
| 39 |
un tableau à une dimension de type <type>integer</type> |
|---|
| 40 |
(<structfield>paye_par_semaine</structfield>), représentant le salaire d'un |
|---|
| 41 |
employé par semaine et un tableau à deux dimensions de type |
|---|
| 42 |
<type>text</type> (<structfield>planning</structfield>), représentant le |
|---|
| 43 |
planning hebdomadaire de l'employé. |
|---|
| 44 |
</para> |
|---|
| 45 |
|
|---|
| 46 |
<para> |
|---|
| 47 |
La syntaxe de <command>CREATE TABLE</command> permet de préciser la taille |
|---|
| 48 |
exacte des tableaux, par exemple : |
|---|
| 49 |
|
|---|
| 50 |
<programlisting>CREATE TABLE tictactoe ( |
|---|
| 51 |
carres integer[3][3] |
|---|
| 52 |
);</programlisting> |
|---|
| 53 |
|
|---|
| 54 |
Néanmoins, les développements actuels n'imposent pas le respect de la |
|---|
| 55 |
taille du tableau -- le comportement est identique à celui des tableaux dont |
|---|
| 56 |
la longueur n'est pas précisée. |
|---|
| 57 |
</para> |
|---|
| 58 |
|
|---|
| 59 |
<para> |
|---|
| 60 |
En fait, l'implantation actuelle n'oblige pas non plus à déclarer le |
|---|
| 61 |
nombre de dimensions. Les tableaux d'un type d'élément particulier sont tous |
|---|
| 62 |
considérés comme étant du même type, quelque soit leur taille ou le |
|---|
| 63 |
nombre de dimensions. Déclarer le nombre de dimensions ou la taille dans |
|---|
| 64 |
<command>CREATE TABLE</command> n'a qu'un but documentaire. Le |
|---|
| 65 |
comportement de l'application n'en est pas affecté. |
|---|
| 66 |
</para> |
|---|
| 67 |
|
|---|
| 68 |
<para> |
|---|
| 69 |
Une autre syntaxe, conforme au standard SQL, peut être |
|---|
| 70 |
utilisée pour les tableaux à une dimension. |
|---|
| 71 |
<structfield>paye_par_semaine</structfield> peut être défini ainsi : |
|---|
| 72 |
<programlisting>paye_par_semaine integer ARRAY[4],</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</productname> |
|---|
| 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 |
on encadre les valeurs des éléments par des accolades et on les sépare par des |
|---|
| 90 |
virgules (ce n'est pas différent de la syntaxe C utilisée |
|---|
| 91 |
pour initialiser les structures). Des guillemets doubles peuvent être |
|---|
| 92 |
positionnés autour des valeurs des éléments. C'est d'ailleurs obligatoire |
|---|
| 93 |
si elles |
|---|
| 94 |
contiennent des virgules ou des accolades (plus de détails ci-dessous). |
|---|
| 95 |
Le format général d'une constante de type tableau est donc le |
|---|
| 96 |
suivant : |
|---|
| 97 |
<synopsis>'{ <replaceable>val1</replaceable> <replaceable>delim</replaceable> <replaceable>val2</replaceable> <replaceable>delim</replaceable> ... }'</synopsis> |
|---|
| 98 |
où <replaceable>delim</replaceable> est le caractère de délimitation pour ce |
|---|
| 99 |
type, tel qu'il est enregistré dans son entrée <literal>pg_type</literal>. |
|---|
| 100 |
Parmi les types de données standard fournis par la distribution |
|---|
| 101 |
<productname>PostgreSQL</productname>, le type <literal>box</literal> utilise un |
|---|
| 102 |
point-virgule (<literal>;</literal>) mais tous les autres utilisent une virgule |
|---|
| 103 |
(<literal>,</literal>). Chaque <replaceable>val</replaceable> est soit une constante |
|---|
| 104 |
du type des éléments du tableau soit un sous-tableau. |
|---|
| 105 |
</para> |
|---|
| 106 |
|
|---|
| 107 |
<para> |
|---|
| 108 |
Exemple de constante tableau : |
|---|
| 109 |
<programlisting>'{{1,2,3},{4,5,6},{7,8,9}}'</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 |
Pour initialiser un élément d'un tableau à NULL, on écrit <literal>NULL</literal> |
|---|
| 116 |
pour la valeur de cet élément. (Toute variante majuscule et/ou minuscule de |
|---|
| 117 |
<literal>NULL</literal> est acceptée.) Si <quote>NULL</quote> doit être |
|---|
| 118 |
utilisé comme valeur de chaîne, on place des guillemets doubles autour. |
|---|
| 119 |
</para> |
|---|
| 120 |
|
|---|
| 121 |
<para> |
|---|
| 122 |
Ces types de constantes de tableau sont en fait un cas particulier |
|---|
| 123 |
des constantes de type générique abordées dans la <xref |
|---|
| 124 |
linkend="sql-syntax-constants-generic"/>. La constante est traitée |
|---|
| 125 |
initialement comme une chaîne et passée à la routine de conversion d'entrées |
|---|
| 126 |
de tableau. Une spécification explicite du type peut être nécessaire. |
|---|
| 127 |
</para> |
|---|
| 128 |
|
|---|
| 129 |
<para> |
|---|
| 130 |
Quelques instructions <command>INSERT</command> : |
|---|
| 131 |
|
|---|
| 132 |
<programlisting>INSERT INTO sal_emp |
|---|
| 133 |
VALUES ('Bill', |
|---|
| 134 |
'{10000, 10000, 10000, 10000}', |
|---|
| 135 |
'{{"rendez-vous", "repas"}, {"entrainement", "présentation"}}'); |
|---|
| 136 |
|
|---|
| 137 |
INSERT INTO sal_emp |
|---|
| 138 |
VALUES ('Carol', |
|---|
| 139 |
'{20000, 25000, 25000, 25000}', |
|---|
| 140 |
'{{"petit-déjeuner", "consultation"}, {"rendez-vous", "repas"}}');</programlisting> |
|---|
| 141 |
</para> |
|---|
| 142 |
|
|---|
| 143 |
<para> |
|---|
| 144 |
Le résultat des deux insertions précédentes ressemble à : |
|---|
| 145 |
<programlisting>SELECT * FROM sal_emp; |
|---|
| 146 |
nom | paye_par_semaine | planning |
|---|
| 147 |
-------+---------------------------+-------------------- |
|---|
| 148 |
Bill | {10000,10000,10000,10000} | {{rendez-vous,repas},{entrainement,présentation}} |
|---|
| 149 |
Carol | {20000,25000,25000,25000} | {{petit-déjeuner,consultation},{rendez-vous,repas}} |
|---|
| 150 |
(2 rows)</programlisting> |
|---|
| 151 |
</para> |
|---|
| 152 |
|
|---|
| 153 |
<para> |
|---|
| 154 |
La syntaxe du constructeur <literal>ARRAY</literal> peut aussi être |
|---|
| 155 |
utilisée : |
|---|
| 156 |
<programlisting>INSERT INTO sal_emp |
|---|
| 157 |
VALUES ('Bill', |
|---|
| 158 |
ARRAY[10000, 10000, 10000, 10000], |
|---|
| 159 |
ARRAY[['rendez-vous', 'repas'], ['entrainement','présentation']]); |
|---|
| 160 |
|
|---|
| 161 |
INSERT INTO sal_emp |
|---|
| 162 |
VALUES ('Carol', |
|---|
| 163 |
ARRAY[20000, 25000, 25000, 25000], |
|---|
| 164 |
ARRAY[['petit-déjeuner', 'consultation'], ['rendez-vous', 'repas']]);</programlisting> |
|---|
| 165 |
</para> |
|---|
| 166 |
<para> |
|---|
| 167 |
Les éléments du tableau sont des constantes SQL ordinaires ou |
|---|
| 168 |
des expressions ; par exemple, les chaînes de caractères littérales sont |
|---|
| 169 |
encadrées par des guillemets simples au lieu de guillemets doubles comme cela |
|---|
| 170 |
est le cas dans un tableau littéral. La syntaxe du constructeur |
|---|
| 171 |
<literal>ARRAY</literal> est discutée plus en profondeur dans la <xref |
|---|
| 172 |
linkend="sql-syntax-array-constructors"/>. |
|---|
| 173 |
</para> |
|---|
| 174 |
|
|---|
| 175 |
<para> |
|---|
| 176 |
Les tableaux multi-dimensionnels doivent avoir des échelles correspondantes |
|---|
| 177 |
pour chaque dimension. Une différence cause la levée d'une erreur. Par |
|---|
| 178 |
exemple : |
|---|
| 179 |
|
|---|
| 180 |
<programlisting> |
|---|
| 181 |
INSERT INTO sal_emp |
|---|
| 182 |
VALUES ('Bill', |
|---|
| 183 |
'{10000, 10000, 10000, 10000}', |
|---|
| 184 |
'{{"rendez-vous", "repas"}, {"rendez-vous"}}'); |
|---|
| 185 |
ERROR: multidimensional arrays must have array expressions with matching dimensions |
|---|
| 186 |
</programlisting> |
|---|
| 187 |
</para> |
|---|
| 188 |
</sect2> |
|---|
| 189 |
|
|---|
| 190 |
<sect2> |
|---|
| 191 |
<title>Accès aux tableaux</title> |
|---|
| 192 |
|
|---|
| 193 |
<para> |
|---|
| 194 |
Quelques requêtes lancées sur la table permettent d'éclairer le propos |
|---|
| 195 |
précédent. Tout d'abord, l'accès à un seul élément du tableau |
|---|
| 196 |
à la fois. Cette requête retrouve le nom des employés dont la paye a |
|---|
| 197 |
changé au cours de la deuxième semaine : |
|---|
| 198 |
|
|---|
| 199 |
<programlisting>SELECT nom FROM sal_emp WHERE paye_par_semaine[1] <> paye_par_semaine[2]; |
|---|
| 200 |
|
|---|
| 201 |
nom |
|---|
| 202 |
------- |
|---|
| 203 |
Carol |
|---|
| 204 |
(1 row)</programlisting> |
|---|
| 205 |
|
|---|
| 206 |
Les indices du tableau sont écrits entre crochets. Par défaut, |
|---|
| 207 |
<productname>PostgreSQL</productname> utilise la convention des indices |
|---|
| 208 |
commençant à 1 pour les tableaux, c'est-à-dire un tableau à |
|---|
| 209 |
<replaceable>n</replaceable> éléments commence avec <literal>array[1]</literal> et finit |
|---|
| 210 |
avec <literal>array[<replaceable>n</replaceable>]</literal>. |
|---|
| 211 |
</para> |
|---|
| 212 |
|
|---|
| 213 |
<para> |
|---|
| 214 |
Récupérer la paye de la troisième semaine de tous les |
|---|
| 215 |
employés : |
|---|
| 216 |
|
|---|
| 217 |
<programlisting>SELECT paye_par_semaine[3] FROM sal_emp; |
|---|
| 218 |
|
|---|
| 219 |
paye_par_semaine |
|---|
| 220 |
------------------ |
|---|
| 221 |
10000 |
|---|
| 222 |
25000 |
|---|
| 223 |
(2 rows)</programlisting> |
|---|
| 224 |
</para> |
|---|
| 225 |
|
|---|
| 226 |
<para> |
|---|
| 227 |
Il est également possible d'accéder à des parties rectangulaires arbitraires ou à des |
|---|
| 228 |
sous-tableaux. Une partie de tableau est indiquée par l'écriture |
|---|
| 229 |
<literal><replaceable>extrémité basse</replaceable>:<replaceable>extrémité haute</replaceable></literal> |
|---|
| 230 |
sur n'importe quelle dimension. Ainsi, La requête suivante retourne |
|---|
| 231 |
le premier élément du planning de Bill pour les deux premiers jours de la |
|---|
| 232 |
semaine : |
|---|
| 233 |
|
|---|
| 234 |
<programlisting>SELECT planning[1:2][1:1] FROM sal_emp WHERE nom = 'Bill'; |
|---|
| 235 |
|
|---|
| 236 |
planning |
|---|
| 237 |
-------------------- |
|---|
| 238 |
{{rendez-vous},{entrainement}} |
|---|
| 239 |
(1 row)</programlisting> |
|---|
| 240 |
|
|---|
| 241 |
Si l'une des dimensions est écrite comme une partie, c'est-à-dire si elle contient |
|---|
| 242 |
le caractère deux-points, alors toutes les dimensions sont traitées comme |
|---|
| 243 |
des parties. Toute dimension qui n'a qu'un numéro (pas de |
|---|
| 244 |
deux-points), est traitée comme allant de <literal>1</literal> |
|---|
| 245 |
au nombre indiqué. Par exemple, <literal>[2]</literal> est traitée comme |
|---|
| 246 |
<literal>[1:2]</literal>, comme le montre cet exemple : |
|---|
| 247 |
|
|---|
| 248 |
<programlisting>SELECT planning[1:2][2] FROM sal_emp WHERE nom = 'Bill'; |
|---|
| 249 |
|
|---|
| 250 |
planning |
|---|
| 251 |
--------------------------- |
|---|
| 252 |
{{rendez-vous,repas},{entrainement,présentation}} |
|---|
| 253 |
(1 row)</programlisting> |
|---|
| 254 |
</para> |
|---|
| 255 |
|
|---|
| 256 |
<para> |
|---|
| 257 |
Une expression indicée de tableau retourne NULL si le tableau ou une |
|---|
| 258 |
des expressions est NULL. De plus, NULL est renvoyé si un indice se trouve en |
|---|
| 259 |
dehors de la plage du tableau (ce cas n'amène pas d'erreur). |
|---|
| 260 |
Par exemple, si <literal>planning</literal> a les dimensions |
|---|
| 261 |
<literal>[1:3][1:2]</literal>, faire référence à |
|---|
| 262 |
<literal>planning[3][3]</literal> donne un |
|---|
| 263 |
résultat NULL. De la même façon, une référence sur un tableau avec une |
|---|
| 264 |
valeur d'indices incorrecte retourne une valeur NULL plutôt qu'une erreur. |
|---|
| 265 |
</para> |
|---|
| 266 |
|
|---|
| 267 |
<para> |
|---|
| 268 |
Une expression de découpage d'un tableau est aussi NULL si, soit le |
|---|
| 269 |
tableau, soit une des expressions indicées est NULL. Néanmoins, dans |
|---|
| 270 |
certains cas particuliers comme la sélection d'une partie d'un tableau |
|---|
| 271 |
complètement en dehors de la plage de ce dernier, l'expression de |
|---|
| 272 |
cette partie est un tableau vide (zéro dimension) et non pas un tableau |
|---|
| 273 |
NULL. Si la partie demandée surcharge partiellement les limites du |
|---|
| 274 |
tableau, alors elle est réduite silencieusement à la partie surchargée. |
|---|
| 275 |
</para> |
|---|
| 276 |
|
|---|
| 277 |
<para> |
|---|
| 278 |
Les dimensions actuelles de toute valeur d'un tableau sont disponibles avec la |
|---|
| 279 |
fonction <function>array_dims</function> : |
|---|
| 280 |
|
|---|
| 281 |
<programlisting>SELECT array_dims(planning) FROM sal_emp WHERE nom = 'Carol'; |
|---|
| 282 |
|
|---|
| 283 |
array_dims |
|---|
| 284 |
------------ |
|---|
| 285 |
[1:2][1:2] |
|---|
| 286 |
(1 row)</programlisting> |
|---|
| 287 |
|
|---|
| 288 |
<function>array_dims</function> donne un résultat de type <type>text</type>, |
|---|
| 289 |
ce qui est pratique à lire mais peut s'avérer plus difficile à interpréter |
|---|
| 290 |
par les |
|---|
| 291 |
programmes. Les dimensions sont aussi récupérables avec |
|---|
| 292 |
<function>array_upper</function> et <function>array_lower</function>, qui |
|---|
| 293 |
renvoient respectivement la limite haute et et la limite basse du tableau |
|---|
| 294 |
précisé : |
|---|
| 295 |
|
|---|
| 296 |
<programlisting>SELECT array_upper(planning, 1) FROM sal_emp WHERE nom = 'Carol'; |
|---|
| 297 |
|
|---|
| 298 |
array_upper |
|---|
| 299 |
------------- |
|---|
| 300 |
2 |
|---|
| 301 |
(1 row)</programlisting> |
|---|
| 302 |
</para> |
|---|
| 303 |
</sect2> |
|---|
| 304 |
|
|---|
| 305 |
<sect2> |
|---|
| 306 |
<title>Modification de tableaux</title> |
|---|
| 307 |
|
|---|
| 308 |
<para> |
|---|
| 309 |
La valeur d'un tableau peut être complètement remplacée : |
|---|
| 310 |
|
|---|
| 311 |
<programlisting>UPDATE sal_emp SET paye_par_semaine = '{25000,25000,27000,27000}' |
|---|
| 312 |
WHERE nom = 'Carol';</programlisting> |
|---|
| 313 |
|
|---|
| 314 |
ou en utilisant la syntaxe de l'expression <literal>ARRAY</literal> : |
|---|
| 315 |
|
|---|
| 316 |
<programlisting>UPDATE sal_emp SET paye_par_semaine = ARRAY[25000,25000,27000,27000] |
|---|
| 317 |
WHERE nom = 'Carol';</programlisting> |
|---|
| 318 |
|
|---|
| 319 |
On peut aussi mettre à jour un seul élément d'un tableau : |
|---|
| 320 |
|
|---|
| 321 |
<programlisting>UPDATE sal_emp SET paye_par_semaine[4] = 15000 |
|---|
| 322 |
WHERE nom = 'Bill';</programlisting> |
|---|
| 323 |
|
|---|
| 324 |
ou faire une mise à jour par tranche : |
|---|
| 325 |
|
|---|
| 326 |
<programlisting>UPDATE sal_emp SET paye_par_semaine[1:2] = '{27000,27000}' |
|---|
| 327 |
WHERE nom = 'Carol';</programlisting> |
|---|
| 328 |
|
|---|
| 329 |
</para> |
|---|
| 330 |
|
|---|
| 331 |
<para> |
|---|
| 332 |
Un tableau peut être agrandi en y stockant des éléments qui n'y sont pas |
|---|
| 333 |
déjà présents. Toute position entre ceux déjà présents et les nouveaux |
|---|
| 334 |
éléments est remplie avec la valeur NULL. Par exemple, si le tableau |
|---|
| 335 |
<literal>mon_tableau</literal> a actuellement quatre éléments, il en aura |
|---|
| 336 |
six après une mise à jour qui affecte <literal>mon_tableau[6]</literal> |
|---|
| 337 |
car <literal>mon_tableau[5]</literal> est alors rempli avec une valeur NULL. |
|---|
| 338 |
Actuellement, l'agrandissement de cette façon n'est autorisé que pour |
|---|
| 339 |
les tableaux à une dimension, pas pour les tableaux multidimensionnels. |
|---|
| 340 |
</para> |
|---|
| 341 |
|
|---|
| 342 |
<para> |
|---|
| 343 |
L'affectation par parties d'un tableau permet la création de tableaux dont |
|---|
| 344 |
l'indice de départ n'est pas 1. On peut ainsi affecter, par exemple, |
|---|
| 345 |
<literal>mon_tableau[-2:7]</literal> pour créer un tableau avec des valeurs d'indices |
|---|
| 346 |
allant de -2 à 7. |
|---|
| 347 |
</para> |
|---|
| 348 |
|
|---|
| 349 |
<para> |
|---|
| 350 |
Les valeurs de nouveaux tableaux peuvent aussi être construites en utilisant |
|---|
| 351 |
l'opérateur de concaténation, |
|---|
| 352 |
<literal>||</literal> : |
|---|
| 353 |
<programlisting>SELECT ARRAY[1,2] || ARRAY[3,4]; |
|---|
| 354 |
?column? |
|---|
| 355 |
--------------- |
|---|
| 356 |
{1,2,3,4} |
|---|
| 357 |
(1 row) |
|---|
| 358 |
|
|---|
| 359 |
SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]]; |
|---|
| 360 |
?column? |
|---|
| 361 |
--------------------- |
|---|
| 362 |
{{5,6},{1,2},{3,4}} |
|---|
| 363 |
(1 row)</programlisting> |
|---|
| 364 |
</para> |
|---|
| 365 |
|
|---|
| 366 |
<para> |
|---|
| 367 |
L'opérateur de concaténation autorise un élément à être placé au début ou à |
|---|
| 368 |
la fin d'un tableau à une dimension. Il accepte aussi deux tableaux à |
|---|
| 369 |
<replaceable>N</replaceable> dimensions, ou un tableau à <replaceable>N</replaceable> dimensions |
|---|
| 370 |
et un à <replaceable>N+1</replaceable> dimensions. |
|---|
| 371 |
</para> |
|---|
| 372 |
|
|---|
| 373 |
<para> |
|---|
| 374 |
Quand un élément seul est poussé soit au début soit à la fin d'un tableau à |
|---|
| 375 |
une dimension, le résultat est un tableau avec le même indice bas que l'opérande |
|---|
| 376 |
du tableau. Par exemple : |
|---|
| 377 |
<programlisting>SELECT array_dims(1 || '[0:1]={2,3}'::int[]); |
|---|
| 378 |
array_dims |
|---|
| 379 |
------------ |
|---|
| 380 |
[0:2] |
|---|
| 381 |
(1 row) |
|---|
| 382 |
|
|---|
| 383 |
SELECT array_dims(ARRAY[1,2] || 3); |
|---|
| 384 |
array_dims |
|---|
| 385 |
------------ |
|---|
| 386 |
[1:3] |
|---|
| 387 |
(1 row)</programlisting> |
|---|
| 388 |
</para> |
|---|
| 389 |
|
|---|
| 390 |
<para> |
|---|
| 391 |
Lorsque deux tableaux ayant un même nombre de dimensions sont concaténés, le |
|---|
| 392 |
résultat conserve la limite inférieure de l'opérande gauche. Le résultat est |
|---|
| 393 |
un tableau comprenant chaque élément de l'opérande gauche suivi de chaque |
|---|
| 394 |
élément de l'opérande droit. Par exemple : |
|---|
| 395 |
<programlisting>SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]); |
|---|
| 396 |
array_dims |
|---|
| 397 |
------------ |
|---|
| 398 |
[1:5] |
|---|
| 399 |
(1 row) |
|---|
| 400 |
|
|---|
| 401 |
SELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]); |
|---|
| 402 |
array_dims |
|---|
| 403 |
------------ |
|---|
| 404 |
[1:5][1:2] |
|---|
| 405 |
(1 row)</programlisting> |
|---|
| 406 |
</para> |
|---|
| 407 |
|
|---|
| 408 |
<para> |
|---|
| 409 |
Lorsqu'un tableau à <replaceable>N</replaceable> dimensions est placé au début ou à la |
|---|
| 410 |
fin d'un tableau à <replaceable>N+1</replaceable> dimensions, le résultat est analogue au |
|---|
| 411 |
cas ci-dessus. Chaque sous-tableau de dimension <replaceable>N</replaceable> est en |
|---|
| 412 |
quelque sorte un élément de la dimension externe d'un tableau à |
|---|
| 413 |
<replaceable>N+1</replaceable> dimensions. Par exemple : |
|---|
| 414 |
<programlisting>SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]); |
|---|
| 415 |
array_dims |
|---|
| 416 |
------------ |
|---|
| 417 |
[1:3][1:2] |
|---|
| 418 |
(1 row)</programlisting> |
|---|
| 419 |
</para> |
|---|
| 420 |
|
|---|
| 421 |
<para> |
|---|
| 422 |
Un tableau peut aussi être construit en utilisant les fonctions |
|---|
| 423 |
<function>array_prepend</function>, <function>array_append</function> |
|---|
| 424 |
ou <function>array_cat</function>. Les deux premières ne supportent que les |
|---|
| 425 |
tableaux à une dimension alors que <function>array_cat</function> supporte les |
|---|
| 426 |
tableaux multidimensionnels. |
|---|
| 427 |
|
|---|
| 428 |
L'opérateur de concaténation vu plus haut est préférable à |
|---|
| 429 |
l'utilisation directe de ces fonctions. En fait, les fonctions existent |
|---|
| 430 |
principalement pour l'implantation de l'opérateur de concaténation. |
|---|
| 431 |
Néanmoins, elles peuvent être directement utiles dans la création |
|---|
| 432 |
d'agrégats utilisateur. Quelques exemples : |
|---|
| 433 |
|
|---|
| 434 |
<programlisting>SELECT array_prepend(1, ARRAY[2,3]); |
|---|
| 435 |
array_prepend |
|---|
| 436 |
--------------- |
|---|
| 437 |
{1,2,3} |
|---|
| 438 |
(1 row) |
|---|
| 439 |
|
|---|
| 440 |
SELECT array_append(ARRAY[1,2], 3); |
|---|
| 441 |
array_append |
|---|
| 442 |
-------------- |
|---|
| 443 |
{1,2,3} |
|---|
| 444 |
(1 row) |
|---|
| 445 |
|
|---|
| 446 |
SELECT array_cat(ARRAY[1,2], ARRAY[3,4]); |
|---|
| 447 |
array_cat |
|---|
| 448 |
--------------- |
|---|
| 449 |
{1,2,3,4} |
|---|
| 450 |
(1 row) |
|---|
| 451 |
|
|---|
| 452 |
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]); |
|---|
| 453 |
array_cat |
|---|
| 454 |
--------------------- |
|---|
| 455 |
{{1,2},{3,4},{5,6}} |
|---|
| 456 |
(1 row) |
|---|
| 457 |
|
|---|
| 458 |
SELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]); |
|---|
| 459 |
array_cat |
|---|
| 460 |
--------------------- |
|---|
| 461 |
{{5,6},{1,2},{3,4}}</programlisting> |
|---|
| 462 |
</para> |
|---|
| 463 |
</sect2> |
|---|
| 464 |
|
|---|
| 465 |
<sect2> |
|---|
| 466 |
<title>Recherche dans les tableaux</title> |
|---|
| 467 |
|
|---|
| 468 |
<para> |
|---|
| 469 |
Pour rechercher une valeur dans un tableau, il faut vérifier chaque valeur |
|---|
| 470 |
dans le tableau. Ceci peut se faire à la main lorque la taille du |
|---|
| 471 |
tableau est connue. Par exemple : |
|---|
| 472 |
|
|---|
| 473 |
<programlisting>SELECT * FROM sal_emp WHERE paye_par_semaine[1] = 10000 OR |
|---|
| 474 |
paye_par_semaine[2] = 10000 OR |
|---|
| 475 |
paye_par_semaine[3] = 10000 OR |
|---|
| 476 |
paye_par_semaine[4] = 10000;</programlisting> |
|---|
| 477 |
|
|---|
| 478 |
Ceci devient toutefois rapidement fastidieux pour les gros tableaux et n'est |
|---|
| 479 |
pas très utile si la taille du tableau n'est pas connue. Une autre méthode |
|---|
| 480 |
est décrite dans la <xref linkend="functions-comparisons"/>. La requête ci-dessus |
|---|
| 481 |
est remplaçable par : |
|---|
| 482 |
|
|---|
| 483 |
<programlisting>SELECT * FROM sal_emp WHERE 10000 = ANY (paye_par_semaine);</programlisting> |
|---|
| 484 |
|
|---|
| 485 |
De la même façon, on trouve les lignes où le tableau n'a que des valeurs |
|---|
| 486 |
égales à 10000 avec : |
|---|
| 487 |
|
|---|
| 488 |
<programlisting>SELECT * FROM sal_emp WHERE 10000 = ALL (paye_par_semaine);</programlisting> |
|---|
| 489 |
|
|---|
| 490 |
</para> |
|---|
| 491 |
|
|---|
| 492 |
<tip> |
|---|
| 493 |
<para> |
|---|
| 494 |
Les tableaux ne sont pas toujours initialisés ; rechercher des éléments |
|---|
| 495 |
spécifiques dans un tableau peut être un signe d'une mauvaise conception de |
|---|
| 496 |
la base de données. On utilise plutôt une table séparée avec une |
|---|
| 497 |
ligne pour chaque élément faisant parti du tableau. Cela simplifie |
|---|
| 498 |
la recherche et fonctionne mieux dans le cas d'un grand nombre |
|---|
| 499 |
d'éléments. |
|---|
| 500 |
</para> |
|---|
| 501 |
</tip> |
|---|
| 502 |
</sect2> |
|---|
| 503 |
|
|---|
| 504 |
<sect2> |
|---|
| 505 |
<title>Syntaxe d'entrée et de sortie des tableaux</title> |
|---|
| 506 |
|
|---|
| 507 |
<para> |
|---|
| 508 |
La représentation externe du type texte d'une valeur de tableau consiste en |
|---|
| 509 |
des éléments interprétés suivant les règles de conversion d'entrées/sorties |
|---|
| 510 |
pour le type de l'élément du tableau, plus des décorations indiquant la |
|---|
| 511 |
structure du tableau. L'affichage est constitué d'accolades (<literal>{</literal> |
|---|
| 512 |
et <literal>}</literal>) autour des valeurs du tableau et de caractères de |
|---|
| 513 |
délimitation entre éléments adjacents. Le caractère délimiteur est |
|---|
| 514 |
habituellement une virgule (<literal>,</literal>) mais peut différer : |
|---|
| 515 |
il est déterminé par le paramètre <literal>typdelim</literal> du type de l'élément |
|---|
| 516 |
tableau (parmi les types de données standards supportés par l'implantation |
|---|
| 517 |
de <productname>PostgreSQL</productname>, le type <literal>box</literal> utilise un |
|---|
| 518 |
point-virgule (<literal>;</literal>) mais tous les autres utilisent la virgule). |
|---|
| 519 |
Dans un tableau multidimensionnel, chaque dimension (row, plane, cube, etc.) |
|---|
| 520 |
utilise son propre niveau d'accolades et les délimiteurs doivent être |
|---|
| 521 |
utilisés entre des entités adjacentes au sein d'accolades de même niveau. |
|---|
| 522 |
</para> |
|---|
| 523 |
|
|---|
| 524 |
<para> |
|---|
| 525 |
La routine de sortie du tableau place des guillemets doubles autour des |
|---|
| 526 |
valeurs des éléments si ce sont des chaînes vides, si elles contiennent des |
|---|
| 527 |
accolades, des caractères délimiteurs, des guillemets doubles, des antislashs |
|---|
| 528 |
ou des espaces ou si elles correspondent à <literal>NULL</literal>. Les guillemets |
|---|
| 529 |
doubles et les antislashs intégrés aux valeurs |
|---|
| 530 |
des éléments sont échappés à l'aide d'un antislash. Pour les types de données |
|---|
| 531 |
numériques, on peut supposer sans risque que les doubles guillemets |
|---|
| 532 |
n'apparaissent jamais, mais pour les types de données texte, il faut être |
|---|
| 533 |
préparé à gérer la présence et l'absence de guillemets. |
|---|
| 534 |
</para> |
|---|
| 535 |
|
|---|
| 536 |
<para> |
|---|
| 537 |
Par défaut, la valeur de la limite basse d'un tableau est initialisée à 1. |
|---|
| 538 |
Pour représenter des tableaux avec des limites basses différentes, les |
|---|
| 539 |
indices du tableau doivent être indiqués explicitement avant d'écrire le |
|---|
| 540 |
contenu du tableau. |
|---|
| 541 |
Cet affichage est consititué de crochets (<literal>[]</literal>) autour |
|---|
| 542 |
de chaque limite basse et haute d'une |
|---|
| 543 |
dimension avec un délimiteur deux-points (<literal>:</literal>) entre |
|---|
| 544 |
les deux. |
|---|
| 545 |
L'affichage des dimensions du tableau est suivie par un signe d'égalité |
|---|
| 546 |
(<literal>=</literal>). Par exemple : |
|---|
| 547 |
<programlisting> |
|---|
| 548 |
SELECT f1[1][-2][3] AS e1, f1[1][-1][5] AS e2 |
|---|
| 549 |
FROM (SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[] AS f1) AS ss; |
|---|
| 550 |
|
|---|
| 551 |
e1 | e2 |
|---|
| 552 |
----+---- |
|---|
| 553 |
1 | 6 |
|---|
| 554 |
(1 row) |
|---|
| 555 |
</programlisting> |
|---|
| 556 |
La routine de sortie du tableau inclut les dimensions explicites dans |
|---|
| 557 |
le resultat uniquement lorsqu'au moins une limite basse est différente |
|---|
| 558 |
de 1. |
|---|
| 559 |
</para> |
|---|
| 560 |
|
|---|
| 561 |
<para> |
|---|
| 562 |
Si la valeur écrite pour un élément est <literal>NULL</literal> (toute |
|---|
| 563 |
variante), l'élément est considéré NULL. La présence de guillemets ou |
|---|
| 564 |
d'antislashs désactive ce fonctionnement et autorise la saisie de la valeur litérale de |
|---|
| 565 |
la chaîne <quote>NULL</quote>. De plus, pour une compatibilité ascendante |
|---|
| 566 |
avec les versions antérieures à la version 8.2 de |
|---|
| 567 |
<productname>PostgreSQL</productname>, |
|---|
| 568 |
le paramètre de configuration <xref linkend="guc-array-nulls"/> doit être |
|---|
| 569 |
désactivé (<literal>off</literal>) pour supprimer la reconnaissance de |
|---|
| 570 |
<literal>NULL</literal> comme un NULL. |
|---|
| 571 |
</para> |
|---|
| 572 |
|
|---|
| 573 |
<para> |
|---|
| 574 |
Comme indiqué précédemment, lors de l'écriture d'une valeur de tableau, |
|---|
| 575 |
des guillemets doubles peuvent être positionnés autour de chaque élément |
|---|
| 576 |
individuel du |
|---|
| 577 |
tableau. Il <emphasis>faut</emphasis> le faire si leur absence autour d'un élément |
|---|
| 578 |
induit en erreur l'analyseur de la valeur du tableau. Par exemple, les |
|---|
| 579 |
éléments contenant des crochets, virgules (ou tout caractère délimiteur), |
|---|
| 580 |
guillemets doubles, antislashs ou espace (en début comme en fin) doivent |
|---|
| 581 |
avoir des guillemets doubles. Les chaînes vides et les chaînes <literal>NULL</literal> |
|---|
| 582 |
doivent aussi être entre guillemets. Pour placer un guillemet double ou un antislash |
|---|
| 583 |
dans une valeur d'élément d'un tableau, on utilise la syntaxe d'échappement des |
|---|
| 584 |
chaînes et on le précède d'un antislash. |
|---|
| 585 |
Au-delà, tous les caractères de données qui sont utilisés dans la syntaxe |
|---|
| 586 |
du tableau peuvent être échappés. |
|---|
| 587 |
</para> |
|---|
| 588 |
|
|---|
| 589 |
<para> |
|---|
| 590 |
Des espaces peuvent être ajoutées avant un crochet gauche ou après un crochet |
|---|
| 591 |
droit. Comme avant tout élément individuel. |
|---|
| 592 |
Dans tous les cas, les espaces sont ignorées. En revanche, les espaces à |
|---|
| 593 |
l'intérieur des éléments entre guillemets doubles ou entourées de |
|---|
| 594 |
caractères autres que des espaces ne sont pas ignorées. |
|---|
| 595 |
</para> |
|---|
| 596 |
|
|---|
| 597 |
<note> |
|---|
| 598 |
<para> |
|---|
| 599 |
Toute ce qui est écrit dans une commande SQL est d'abord |
|---|
| 600 |
interprété en tant que chaîne littérale puis en tant que tableau. Ceci |
|---|
| 601 |
double le nombre d'antislash nécessaire. Par exemple, pour |
|---|
| 602 |
insérer une valeur de tableau de type <type>text</type> contenant un antislash |
|---|
| 603 |
et un guillemet double, il faut écrire : |
|---|
| 604 |
<programlisting>INSERT ... VALUES (E'{"\\\\","\\""}');</programlisting> |
|---|
| 605 |
Le processeur de la chaîne d'échappement supprime un niveau d'antislash, donc |
|---|
| 606 |
l'analyseur de tableau reçoit <literal>{"\\","\""}</literal>. |
|---|
| 607 |
En conséquence, les chaînes remplissant l'entrée du type de données |
|---|
| 608 |
<type>text</type> deviennent respectivement <literal>\</literal> et <literal>"</literal>. |
|---|
| 609 |
(Si la routine d'entrée du type de données utilisé |
|---|
| 610 |
traite aussi les antislash de manière spéciale, <type>bytea</type> par |
|---|
| 611 |
exemple, il peut être nécessaire d'avoir jusqu'à huit antislash dans la |
|---|
| 612 |
commande pour en obtenir un dans l'élément stocké.) |
|---|
| 613 |
Les guillemets dollar (voir <xref linkend="sql-syntax-dollar-quoting"/>) |
|---|
| 614 |
peuvent être utilisés pour éviter de doubler les antislash. |
|---|
| 615 |
</para> |
|---|
| 616 |
</note> |
|---|
| 617 |
|
|---|
| 618 |
<tip> |
|---|
| 619 |
<para> |
|---|
| 620 |
La syntaxe du constructeur <literal>ARRAY</literal> (voir <xref |
|---|
| 621 |
linkend="sql-syntax-array-constructors"/>) est souvent plus facile à utiliser |
|---|
| 622 |
que la syntaxe de tableau littéral lors de l'écriture des valeurs du tableau |
|---|
| 623 |
en commandes SQL. Avec <literal>ARRAY</literal>, les valeurs de l'élément individuel |
|---|
| 624 |
sont écrites comme elles le seraient si elles ne faisaient pas partie d'un tableau. |
|---|
| 625 |
</para> |
|---|
| 626 |
</tip> |
|---|
| 627 |
</sect2> |
|---|
| 628 |
|
|---|
| 629 |
</sect1> |
|---|