PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 17.6 » Langage SQL » Définition des données » Colonnes générées

5.4. Colonnes gĂ©nĂ©rĂ©es #

Une colonne gĂ©nĂ©rĂ©e est une colonne spĂ©ciale, toujours calculĂ©e Ă  partir d'autres colonnes. Elle est donc aux colonnes ce qu'une vue est aux tables. Il y a deux types de colonnes gĂ©nĂ©rĂ©es : stockĂ©e et virtuelle. Une colonne gĂ©nĂ©rĂ©e stockĂ©e est calculĂ©e quand elle est Ă©crite (insĂ©rĂ©e ou mise Ă  jour) et occupe de l'espace de stockage comme si elle Ă©tait une colonne normale. Une colonne virtuelle gĂ©nĂ©rĂ©e n'occupe pas d'espace et est calculĂ©e Ă  la lecture. Une colonne gĂ©nĂ©rĂ©e virtuelle est donc Ă©quivalente Ă  une vue, et une colonne gĂ©nĂ©rĂ©e stockĂ©e est Ă©quivalente Ă  une vue matĂ©rialisĂ©e (sauf qu'elle sera toujours mise Ă  jour automatiquement). PostgreSQL n'implĂ©mente actuellement que les colonnes gĂ©nĂ©rĂ©es stockĂ©es.

Pour crĂ©er une colonne gĂ©nĂ©rĂ©e, utilisez la clause GENERATED ALWAYS AS de la commande CREATE TABLE, par exemple :

CREATE TABLE people (
    ...,
    height_cm numeric,
    height_in numeric GENERATED ALWAYS AS (height_cm / 2.54) STORED
);

Le mot-clĂ© STORED doit ĂȘtre spĂ©cifiĂ© pour choisir le type de colonne gĂ©nĂ©rĂ©e. Voir CREATE TABLE pour plus de dĂ©tails.

On ne peut Ă©crire directement dans une colonne gĂ©nĂ©rĂ©e. Une valeur ne peut pas y ĂȘtre affectĂ©e dans les commandes INSERT ou UPDATE, mais le mot-clĂ© DEFAULT peut l'ĂȘtre.

Voyons les diffĂ©rences entre une colonne avec une valeur par dĂ©faut et une colonne gĂ©nĂ©rĂ©e. La colonne par dĂ©faut est calculĂ©e une seule fois Ă  la premiĂšre insertion de la ligne si aucune autre valeur n'est fournie ; une colonne gĂ©nĂ©rĂ©e est mise Ă  jour Ă  chaque fois que la ligne change et on ne peut y dĂ©roger. Une valeur par dĂ©faut d'une colonne ne peut se rĂ©fĂ©rer Ă  d'autres colonnes de la table ; mais c'est ce que fait normalement une expression gĂ©nĂ©rĂ©e. Une valeur par dĂ©faut d'une colonne peut utiliser des fonctions volatiles, par exemple random() ou des fonctions se rĂ©fĂ©rant au temps actuel ; ce n'est pas permis pour les colonnes gĂ©nĂ©rĂ©es.

Il existe plusieurs restrictions dans la dĂ©finition des colonnes gĂ©nĂ©rĂ©es et des tables qui les utilisent :

  • L'expression pour gĂ©nĂ©rer les valeurs ne peut utiliser que des fonctions immutables, ne peut pas utiliser de sous-requĂȘtes, ni rĂ©fĂ©rencer d'aucune maniĂšre quoi que ce soit hors de la ligne en cours.

  • Une expression ne peut rĂ©fĂ©rencer une autre colonne gĂ©nĂ©rĂ©e.

  • Une expression ne peut rĂ©fĂ©rencer une colonne systĂšme, sauf tableoid.

  • Une colonne gĂ©nĂ©rĂ©e ne peut avoir une valeur par dĂ©faut ou ĂȘtre dĂ©finie comme colonne identitĂ©.

  • Une colonne gĂ©nĂ©rĂ©e ne peut faire partie d'une clĂ© de partitionnement.

  • Les tables distantes peuvent porter des colonnes gĂ©nĂ©rĂ©es. Voir CREATE FOREIGN TABLE pour les dĂ©tails.

  • Pour l'hĂ©ritage et le partitionnement :

    • Si une colonne parent est une colonne gĂ©nĂ©rĂ©e, la colonne enfant doit aussi ĂȘtre une colonne gĂ©nĂ©rĂ©e ; nĂ©anmoins, la colonne enfant peut avoir une expression de gĂ©nĂ©ration diffĂ©rente. L'expression de gĂ©nĂ©ration qui est rĂ©ellement appliquĂ©e lors de l'insertion ou de la mise Ă  jour d'une ligne est celle qui est associĂ©e avec la table qui contiendra physiquement la ligne. (Ceci est contraire au comportement pour la valeur par dĂ©faut d'une colonne : pour ces derniĂšres, la valeur par dĂ©faut appliquĂ©e est celle associĂ©e avec la table nommĂ©e dans la requĂȘte.)

    • Si une colonne parent n'est pas une colonne gĂ©nĂ©rĂ©e, sa colonne enfant ne doit pas non plus ĂȘtre une colonne gĂ©nĂ©rĂ©e.

    • Pour les tables hĂ©ritĂ©es, si vous Ă©crivez une dĂ©finition de colonne de la table enfant sans clause GENERATED dans CREATE TABLE ... INHERITS, alors sa clause GENERATED sera automatiquement copiĂ©e du parent. ALTER TABLE ... INHERIT insistera que les colonnes parents et enfants correspondant dĂ©jĂ  au statut de gĂ©nĂ©ration, mais il n'obligera pas Ă  ce que les expressions de gĂ©nĂ©ration correspondent.

    • De façon similaire pour les tables partitionnĂ©es, si vous Ă©crivez la dĂ©finition d'une colonne enfant sans la clause GENERATED clause dans CREATE TABLE ... PARTITION OF, alors la clause GENERATED sera automatiquement copiĂ©e du parent. ALTER TABLE ... ATTACH PARTITION insistera pour que les colonnes parents et enfants correspondent dĂ©jĂ  au niveau du statut de gĂ©nĂ©ration, mais il ne reclamera pas que les expressions de gĂ©nĂ©ration correspondent.

    • Dans le cas de plusieurs hĂ©ritages, si une des colonnes parents est une colonne gĂ©nĂ©rĂ©e, alors toutes les colonnes parents doivent ĂȘtre des colonnes gĂ©nĂ©rĂ©es. Si elles n'ont pas toutes la mĂȘme expression de gĂ©nĂ©ration, alors l'expression dĂ©sirĂ©e pour l'enfant doit ĂȘtre indiquĂ©e explicitement.

D'autres considérations s'appliquent à l'utilisation des colonnes générées.

  • Les colonnes gĂ©nĂ©rĂ©es maintiennent les droits d'accĂšs sĂ©parĂ©ment des colonnes sur lesquelles elles sont basĂ©es. On peut donc s'arranger pour qu'un rĂŽle dĂ©fini puisse lire une colonne gĂ©nĂ©rĂ©e mais pas la colonne de base sous-jacente.

  • Conceptuellement, les colonnes gĂ©nĂ©rĂ©es sont mises Ă  jour aprĂšs le dĂ©clenchement des triggers BEFORE. Les changements dans les colonnes de base au sein d'un trigger BEFORE seront donc rĂ©percutĂ©s dans les colonnes gĂ©nĂ©rĂ©es. Mais Ă  l'inverse, il n'est pas permis d'accĂ©der aux colonnes gĂ©nĂ©rĂ©es dans les triggers BEFORE.

  • Les colonnes gĂ©nĂ©rĂ©es sont ignorĂ©es pour la rĂ©plication logique et ne peuvent pas ĂȘtre indiquĂ©es dans une liste de colonnes d'une commande CREATE PUBLICATION.