¿Cómo actualizo automáticamente una marca de tiempo en PostgreSQL?

132

Quiero que el código pueda actualizar automáticamente la marca de tiempo cuando se inserta una nueva fila, como puedo hacer en MySQL usando CURRENT_TIMESTAMP.

¿Cómo podré lograr esto en PostgreSQL?

CREATE TABLE users (
    id serial not null,
    firstname varchar(100),
    middlename varchar(100),
    lastname varchar(100),
    email varchar(200),
    timestamp timestamp
)
Aaron
fuente
66
Por cierto, su tipo de datos timestampestá definido por la especificación SQL como una abreviatura de TIMESTAMP WITHOUT TIME ZONE. Es casi seguro que no es lo que quieres, como lo explicó el experto de Postgres David E. Wheeler . El otro tipo, TIMESTAMP WITH TIME ZONEes probablemente lo que desea, utilizando cualquier información de compensación de zona horaria pasada para ajustar la fecha y hora a UTC (pero en realidad no almacena esa información de zona horaria a pesar del nombre del tipo).
Basil Bourque
3
Después de volver a aprender esto una vez más, escribí una publicación de blog detallada sobre el registro de la fecha y hora de la creación y modificación de una fila utilizando el valor predeterminado, la función y el disparador. Incluye un ejemplo completo de código SQL y PL / pgSQL para usar en Postgres.
Basil Bourque

Respuestas:

197

Para llenar la columna durante la inserción, use un DEFAULTvalor:

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

Tenga en cuenta que el valor de esa columna se puede sobrescribir explícitamente proporcionando un valor en la INSERTdeclaración. Si desea evitar eso, necesita un disparador .

También necesita un activador si necesita actualizar esa columna cada vez que se actualiza la fila (como lo menciona EJ Brennan )

Tenga en cuenta que el uso de palabras reservadas para los nombres de columna generalmente no es una buena idea. Deberías encontrar un nombre diferente atimestamp

un caballo sin nombre
fuente
14
Tenga en cuenta que Postgres tiene funciones para indicarle (1) la hora del momento actual real, (2) la hora en que comenzó la declaración y (3) la hora en que comenzó la transacción. El ejemplo que se muestra aquí es el inicio de la transacción actual. Puede o no querer eso en oposición a las otras dos posibilidades.
Basil Bourque
66
Buen punto adicional sobre evitar nombres que chocan con palabras reservadas. Tenga en cuenta que la especificación SQL promete explícitamente nunca usar un guión bajo como palabra reservada. Así que usted puede hacer timestampen timestamp_. Aún mejor sería un nombre más descriptivo como row_created_.
Basil Bourque
La primera mitad no es lo que el OP preguntó en absoluto, aunque la segunda mitad se refirió a otra respuesta (que es correcta), pero sigue siendo engañosa. Esto no debe aceptarse como respuesta.
Eric Wang
1
Lo dice en la documentación de Postgres de los tipos. Varchar tiene ciclos de CPU adicionales para verificar la restricción, lo que no sucede en TEXT.
Rahly
3
no con un solo campo, pero nunca he visto una tabla útil con un solo campo. Esta restricción se agrava por el número de campos. Recuerdo que cambié todos los varchar de una tabla en texto y obtuve una mejora de escritura del 15%. Además, una pequeña penalización de rendimiento no es una penalización de rendimiento "NO".
Rahly
104

Tendrá que escribir un activador de inserción y, posiblemente, un activador de actualización si desea que cambie cuando se cambia el registro. Este artículo lo explica muy 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';

Aplica el gatillo de esta manera:

CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON customer FOR EACH ROW EXECUTE PROCEDURE  update_modified_column();
EJ Brennan
fuente
2
Esta es la mejor respuesta, IMO (aunque, un valor predeterminado es suficiente para insertar).
kik
2
¿Qué hay de nuevo aquí?
Naveen
Esta es una solución más completa que funcionaría con los INSERTOS iniciales, así como con las ACTUALIZACIONES posteriores (bueno para la auditoría de datos). Por supuesto, el OP solo pregunta por el primero.
Pavel Lechev
55
@Naveen no mucho, ¿qué hay de nuevo contigo?
Underyx
57

Actualización de marca de tiempo, solo si los valores cambiaron

Basado en el enlace de EJ y agregue una declaración if desde este enlace ( 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
fuente
9

El uso de 'now ()' como valor predeterminado genera automáticamente la marca de tiempo.

Parichay Mo
fuente