Comment mettre à jour automatiquement un horodatage dans PostgreSQL

132

Je veux que le code puisse mettre à jour automatiquement l'horodatage lorsqu'une nouvelle ligne est insérée, comme je peux le faire dans MySQL en utilisant CURRENT_TIMESTAMP.

Comment pourrais-je y parvenir dans PostgreSQL?

CREATE TABLE users (
    id serial not null,
    firstname varchar(100),
    middlename varchar(100),
    lastname varchar(100),
    email varchar(200),
    timestamp timestamp
)
Aaron
la source
6
À propos, votre type de données timestampest défini par la spécification SQL comme une abréviation de TIMESTAMP WITHOUT TIME ZONE. Ce n'est certainement pas ce que vous voulez, comme l'a expliqué l'expert Postgres David E. Wheeler . L'autre type, TIMESTAMP WITH TIME ZONEest probablement ce que vous voulez, en utilisant toutes les informations de décalage de fuseau horaire passées pour ajuster la date-heure à UTC (mais pas réellement en stockant ces informations de fuseau horaire malgré le nom du type).
Basil Bourque
3
Après avoir réappris cela encore une fois, j'ai écrit un article de blog détaillé sur la journalisation de la date et de l'heure de la création et de la modification d'une ligne à l'aide de la valeur par défaut, de la fonction et du déclencheur. Inclut un exemple complet de code SQL et PL / pgSQL à utiliser dans Postgres.
Basil Bourque

Réponses:

197

Pour remplir la colonne lors de l'insertion, utilisez une DEFAULTvaleur:

CREATE TABLE users (
  id serial not null,
  firstname varchar(100),
  middlename varchar(100),
  lastname varchar(100),
  email varchar(200),
  timestamp timestamp default current_timestamp
)

Notez que la valeur de cette colonne peut être explicitement écrasée en fournissant une valeur dans l' INSERTinstruction. Si vous voulez éviter cela, vous avez besoin d'un déclencheur .

Vous avez également besoin d'un déclencheur si vous devez mettre à jour cette colonne chaque fois que la ligne est mise à jour (comme mentionné par EJ Brennan )

Notez que l'utilisation de mots réservés pour les noms de colonnes n'est généralement pas une bonne idée. Vous devriez trouver un nom différent detimestamp

un cheval sans nom
la source
14
Sachez que Postgres a des fonctions pour vous indiquer (1) l'heure du moment actuel, (2) l'heure à laquelle l'instruction a commencé et (3) l'heure à laquelle la transaction a commencé. L'exemple présenté ici est le début de la transaction en cours. Vous pouvez ou non vouloir cela par opposition aux deux autres possibilités.
Basil Bourque
6
Bon bonus pour éviter les noms qui entrent en collision avec des mots réservés. Notez que la spécification SQL promet explicitement de ne jamais utiliser de trait de soulignement de fin comme mot réservé. Ainsi , vous pouvez faire timestampen timestamp_. Encore mieux serait un nom plus descriptif tel que row_created_.
Basil Bourque
La première moitié n'est pas du tout ce que le PO a demandé, même si la seconde moitié faisait référence à une autre réponse (ce qui est correcte), mais elle est toujours trompeuse. Cela ne devrait pas être accepté comme réponse.
Eric Wang
1
Dit ainsi dans la documentation Postgres des types. Varchar a des cycles CPU supplémentaires pour vérifier la contrainte, ce qui ne se produit pas sur TEXT.
Rahly
3
pas avec un seul champ, mais je n'ai jamais vu une table utile avec un seul champ. Cette contrainte est aggravée par le nombre de champs. Je me souviens avoir changé tous les varchar d'un tableau en texte et j'ai obtenu une amélioration de l'écriture de 15%. En outre, une petite pénalité de performance n'est pas une pénalité de performance "NON".
Rahly
104

Vous devrez écrire un déclencheur d'insertion, et éventuellement un déclencheur de mise à jour si vous voulez qu'il change lorsque l'enregistrement est modifié. Cet article l'explique assez bien:

http://www.revsys.com/blog/2006/aug/04/automatically-updating-a-timestamp-column-in-postgresql/

CREATE OR REPLACE FUNCTION update_modified_column()   
RETURNS TRIGGER AS $$
BEGIN
    NEW.modified = now();
    RETURN NEW;   
END;
$$ language 'plpgsql';

Appliquez le déclencheur comme ceci:

CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON customer FOR EACH ROW EXECUTE PROCEDURE  update_modified_column();
EJ Brennan
la source
2
C'est la meilleure réponse, IMO (bien qu'une valeur par défaut soit suffisante pour l'insertion).
kik
2
Quoi de neuf ici?
Naveen
Il s'agit d'une solution plus complète qui fonctionnerait avec les INSERT initiaux ainsi qu'avec les MISES À JOUR ultérieures (bon pour l'audit des données). Certes, l'OP ne demande que le premier.
Pavel Lechev le
5
@Naveen pas beaucoup, quoi de neuf avec vous?
Underyx
57

Mise à jour de l'horodatage, uniquement si les valeurs ont changé

Sur la base du lien d'EJ et ajoutez une instruction if à partir de ce lien ( https://stackoverflow.com/a/3084254/1526023 )

CREATE OR REPLACE FUNCTION update_modified_column()
RETURNS TRIGGER AS $$
BEGIN
   IF row(NEW.*) IS DISTINCT FROM row(OLD.*) THEN
      NEW.modified = now(); 
      RETURN NEW;
   ELSE
      RETURN OLD;
   END IF;
END;
$$ language 'plpgsql';
Jim Yu
la source
9

L'utilisation de «now ()» comme valeur par défaut génère automatiquement un horodatage.

Parichay Mo
la source