Tableaux

Postgres fournit des colonnes de table définies comme tables multidimensionnelles de longeur variables. Des tableaux de chaque type natif ou utilisateur peuvent être créés. Pour illustrer leur utilisation, créons cette table :

CREATE TABLE sal_emp (
    name            text,
    pay_by_quarter  integer[],
    schedule        text[][]
);
Comme indiqué, un type tableau est nommé par l'ajout de crochets ([]) au nom de type des éléments du tableau. La requête ci-dessous créera une table nommée sal_emp avec une chaîne text (name), une table unidimensionnelle de type integer (pay_by_quarter), qui représente le salaire des employés par trimestre, et un tableau bidimensionnel de type text (schedule), qui représente les horaires hebdomadaires des employés.

Maintenant faisons quelques INSERT. Nous observons que pour écrire une valeur tableau, nous insérons les valeurs des éléments dans des crochets arrondis séparés par des virgules. Si vous connaissez le langage C, ce n'est pas différent de la syntaxe d'initialisation des structures.

INSERT INTO sal_emp
    VALUES ('Bill',
    '{10000, 10000, 10000, 10000}',
    '{{"meeting", "lunch"}, {}}');

INSERT INTO sal_emp
    VALUES ('Carol',
    '{20000, 25000, 25000, 25000}',
    '{{"talk", "consult"}, {"meeting"}}');

Maintenant, nous pouvons lancer certaines requêtes sur sal_emp. En premier, nous voyons comment accéder à un élément unique d'un tableau à un moment donné. Cette requête retrouve les noms des employés dont la paie a changé au cours du second trimestre :

SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2];

 name
-------
 Carol
(1 row)
Les nombres du tableau sont écrits dans des crochets carrés. Postgres utilise la convention de numérotage "à partir de 1" pour les tableaux, qui donne, un tableau de n éléments démarre avec array[1] et fini avec array[n].

Cette requête retrouve le troisième trimestre de paie de tous les employés :

SELECT pay_by_quarter[3] FROM sal_emp;

 pay_by_quarter
----------------
          10000
          25000
(2 rows)

Nous pouvons aussi accéder à des coupes rectangulaires arbitraires d'un tableau, ou sous-tableaux. Une coupe de tableau est signifiée en écrivant des indexage bas : indexage haut pour une ou plusieurs dimensions de tableau. Cette requête retrouve la première rubrique de l'emploi du temps de Bill pour les deux premiers jours de la semaine :

SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';

      schedule
--------------------
 {{"meeting"},{""}}
(1 row)
Nous pourrions aussi avoir écrit
SELECT schedule[1:2][1] FROM sal_emp WHERE name = 'Bill';
avec le même résultat. Une opération de sous-script de tableau représente une coupe de tableau si certains des sous-scripts sont écrits dans la forme lower : upper. Une limite basse de 1 est supposée pour n'importe quel sous-script où seulement une valeur est spécifiée.

Une valeur de tableau peut être replacée complètement :

UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'
    WHERE name = 'Carol';
ou mise à jour pour un seul élément :
UPDATE sal_emp SET pay_by_quarter[4] = 15000
    WHERE name = 'Bill';
ou mise à jour dans une coupe :
UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'
    WHERE name = 'Carol';

Un tableau peut être élargi en lui assignant un élément adjacent à ceux déja présents, ou en lui assignant une coupe adjacente ou chevauchant des données déjà présentes. Par exemple, si une valeur de tableau possède 4 éléments, elle aura 5 éléments après une mise à jour qui lui assigne array[5]. L'élargissement de cette manière est admis seulement pour les tableaux unidimensionnels, pas multidimensionnels.

La syntaxe de CREATE TABLE permet de définir des tableaux de longueur fixe.

CREATE TABLE tictactoe (
    squares   integer[3][3]
);
Cependant, la version courante ne précise pas les limites de taille des tableaux --- le comportement est le même que pour les tableaux de longueur non spécifiée.

Actuellement, cette version ne précise pas le nombre de dimensions déclarées. Les tableaux d'un type particulier sont sont tous considérés comme du même type, en regard de la taille ou du nombre des dimensions.

Les dimensions d'une valeur tableau peuvent être retrouvées par la fonction array_dims :

SELECT array_dims(schedule) FROM sal_emp WHERE name = 'Carol';

 array_dims
------------
 [1:2][1:1]
(1 row)
array_dims produit un résultat text, qui est pratique à lire mais peut être pas pratique pour les programmes.

Pour chercher une valeur dans un tableau, vous devez vérifier chaque valeur du tableau. Ceci peut être fait à la main (si vous connaissez la taille du tableau) :

SELECT * FROM sal_emp WHERE pay_by_quarter[1] = 10000 OR
                            pay_by_quarter[2] = 10000 OR
                            pay_by_quarter[3] = 10000 OR
                            pay_by_quarter[4] = 10000;
Cependant celà devient rapidement pénible pour les gros tableaux, et ce n'est pas pratique si la taille du tableau n'est pas connue. Bien qu'elle ne fasse pas partie de la distribution normale de Postgres, il existe une extension disponible qui définit de nouveaux opérateurs et fonctions pour l'itération des valeurs de tableaux. En les utilisant, la requête ci-dessous serait :
SELECT * FROM sal_emp WHERE pay_by_quarter[1:4] *= 10000;
Pour rechercher sur le tableau entier (pas seulement les colonnes spécifiées), vous pouvez utiliser :
SELECT * FROM sal_emp WHERE pay_by_quarter *= 10000;
De plus, vous pouvez retrouver les lignes où le tableau a toutes les valeurs égales à 10 000 avec :
SELECT * FROM sal_emp WHERE pay_by_quarter **= 10000;
Pour installer ce module optionnel, regardez dans le répertoire contrib/array du source de Postgres.

Tip

Les tableaux ne sont pas placés; utiliser les tableaux de la manière décrite précédemment est souvent un signe de mauvaise conceptualisation de la base. Le champ tableau serait généralement disposé dans une table séparée. Évidemment les tables peuvent être questionnées facilement.

Note

Une limitation à l'implémentation actuelle des tableaux est que les éléments individuels d'un tableau ne peuvent ne peuvent être NULL en SQL. Le tableau entier peut être placé à NULL, mais vous ne pouvez avoir un tableau avec certains éléments NULL et certains non. La correction de ceci est dans la liste des choses "à faire".

Quotage des éléments tableau. Comme indiqué ci-dessus, quand on écrit une valeur de tableau on peut écrire des guillemets autour d'un élément tableau individuel. Vous devez le faire sinon les valeurs d'élément induiront en erreur le parser de valeur tableau. Par exemple, les éléments contenant des crochets arrondis, virgules, guillemets, backslashes, ou espaces blancs doivent être entre guillemets. Pour placer un guillemet ou un backslash dans une valeur d'élément tableau, faites le précéder d'un backslash.

Tip

Souvenez vous que quoi que vous écriviez dans une requête SQL elle sera d'abord interprétée comme une chaîne littérale, et ensuite comme un tableau. Ceci double le nombre de backslashes dont vous avez besoin. Par exemple, pour insérer une valeur tableau text contenant un backslash et un guillemet, vous devez écrire :

INSERT ... VALUES ('{"\\\\","\\""}');
Le processeur de chaîne efface un niveau de backslashes, ce qui se produit pour le parser de la valeur tableau comme {"\\","\""}. Les chaînes fédèrent les routines d'entrée de type text devenant \ et " respectivement. (Si vous travaillez avec un type dont la routine d'entrée traite aussi les backslashes de façon spéciale, bytea par exemple, vous aurez besoin de plus de 8 backslashes dans la requête pour obtenir qu'un backslash soit ainsi stocké dans l'élément tableau).