【问题标题】:How do I automatically update a timestamp in PostgreSQL如何在 PostgreSQL 中自动更新时间戳
【发布时间】:2012-03-22 07:47:05
【问题描述】:

我希望代码能够在插入新行时自动更新时间戳,就像我在 MySQL 中使用 CURRENT_TIMESTAMP 所做的那样。

如何在 PostgreSQL 中实现这一点?

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

【问题讨论】:

  • 顺便说一下,你的timestamp数据类型是由SQL规范定义为TIMESTAMP WITHOUT TIME ZONE的缩写。这几乎肯定不是你想要的,就像explained by Postgres expert David E. Wheeler。另一种类型,TIMESTAMP WITH TIME ZONE 可能是您想要的,使用任何传递的时区偏移信息将日期时间调整为 UTC(但实际上并没有存储该时区信息,尽管类型名称)。
  • 在重新学习了这一点之后,我写了一个detailed blog post,关于使用默认值、函数和触发器记录行的创建和修改的日期时间。包括用于 Postgres 的完整示例 SQL 和 PL/pgSQL 代码。

标签: database postgresql timestamp


【解决方案1】:

要在插入期间填充列,请使用 DEFAULT 值:

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

请注意,该列的值可以通过在INSERT 语句中提供值来显式覆盖。如果您想防止这种情况发生,您确实需要trigger

如果您需要在更新行时更新该列(如mentioned by E.J. Brennan),则还需要一个触发器

请注意,对列名使用保留字通常不是一个好主意。您应该找到与 timestamp 不同的名称

【讨论】:

  • 请注意 Postgres 有 functions 告诉您 (1) 实际当前时刻的时间,(2) 语句开始的时间,以及 (3) 事务开始的时间。此处显示的示例是当前事务的开始。与其他两种可能性相反,您可能想要也可能不想要。
  • 避免名称与保留字冲突的好处。请注意,SQL 规范明确承诺永远不会使用结尾的下划线作为保留字。所以你可以把timestamp变成timestamp_。更好的是一个更具描述性的名称,例如row_created_
  • 前半部分根本不是OP所要求的,尽管后半部分提到了其他答案(这是正确的),但它仍然具有误导性。这不应该被接受为答案。
  • 在类型的 Postgres 文档中这样说。 Varchar 有额外的 CPU 周期来检查约束,这在 TEXT 上不会发生。
  • 没有单个字段,但我从未见过有单个字段的有用表格。该约束因字段数量而更加复杂。我记得将表格中的所有 varchar 更改为文本并获得了 15% 的写作改进。此外,小的性能损失不是“否”性能损失。
【解决方案2】:

您需要编写一个插入触发器,如果​​您希望在更改记录时更改它,还可能编写一个更新触发器。这篇文章解释得很好:

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';

像这样应用触发器:

CREATE TRIGGER update_customer_modtime BEFORE UPDATE ON customer FOR EACH ROW EXECUTE PROCEDURE  update_modified_column();

【讨论】:

  • 这是一个更完整的解决方案,适用于初始 INSERT 以及任何后续 UPDATE(有利于数据审计)。当然,OP 只要求前者。
【解决方案3】:

更新时间戳,仅当值发生变化时

基于 E.J 的链接并从此链接添加 if 语句 (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';

【讨论】:

    【解决方案4】:

    使用 'now()' 作为默认值会自动生成时间戳。

    【讨论】:

    • 仅用于添加值,更新记录时似乎不使用默认值。
    【解决方案5】:

    要在插入新行时自动更新 PostgresSQL 中的时间戳字段,您可以将 current_timestamp 设置为其 default 值:

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

    除此之外,您可能希望阻止任何人在将来更新此字段,这可以通过创建更新触发器并应用它来完成:

    CREATE OR REPLACE FUNCTION stop_change_on_timestamp()
      RETURNS trigger AS
    $BODY$
    BEGIN
      -- always reset the timestamp to the old value ("actual creation time")
      NEW.timestamp := OLD.timestamp;
      RETURN NEW;
    END;
    $BODY$
    
    CREATE TRIGGER prevent_timestamp_changes
      BEFORE UPDATE
      ON users
      FOR EACH ROW
      EXECUTE PROCEDURE stop_change_on_timestamp();
    

    【讨论】:

      【解决方案6】:

      对于更新和 Liquibase YAML:

      databaseChangeLog:
        - changeSet:
            id: CREATE FUNCTION set_now_to_timestamp
            author: Konstantin Chvilyov
            changes:
              - sql:
                  sql: CREATE OR REPLACE FUNCTION set_now_to_timestamp() RETURNS TRIGGER LANGUAGE plpgsql AS 'BEGIN NEW.timestamp = NOW(); RETURN NEW; END;'
      
        - changeSet:
            id: CREATE TRIGGER update_users_set_now_to_timestamp
            author: Konstantin Chvilyov
            changes:
              - sql:
                  sql: CREATE TRIGGER update_users_set_now_to_timestamp BEFORE UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE set_now_to_timestamp();
      

      【讨论】:

        猜你喜欢
        • 2010-11-05
        • 2013-09-28
        • 1970-01-01
        • 2012-11-14
        • 1970-01-01
        • 1970-01-01
        • 2020-07-08
        • 2020-09-18
        相关资源
        最近更新 更多