插入新行时在 PostgreSQL 中自动填充时间戳字段

Automatically populate a timestamp field in PostgreSQL when a new row is inserted

提问人:Aaron 提问时间:3/5/2012 最后编辑:mickmackusaAaron 更新时间:10/30/2023 访问量:266077

问:

我希望代码能够在插入新行时自动填充时间戳值,就像我在 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
)
数据库 postgresql 时间戳 sql-insert 默认值

评论

12赞 Basil Bourque 10/2/2014
顺便说一句,您的 数据类型 由 SQL 规范定义为 的缩写。这几乎可以肯定不是你想要的,正如Postgres专家David E. Wheeler所解释的那样。另一种类型可能是您想要的,它使用任何传递的时区偏移量信息将日期时间调整为 UTC(但实际上不存储该时区信息,尽管有类型名称)。timestampTIMESTAMP WITHOUT TIME ZONETIMESTAMP WITH TIME ZONE
5赞 Basil Bourque 10/3/2014
在再次学习了这一点之后,我写了一篇详细的博客文章,介绍了如何使用默认值、函数和触发器记录行创建和修改的日期时间。包括用于 Postgres 的完整示例 SQL 和 PL/pgSQL 代码。

答:

191赞 E.J. Brennan 3/5/2012 #1

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

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();

评论

1赞 Pavel Lechev 6/4/2018
这是一个更完整的解决方案,适用于初始 INSERT 以及任何后续更新(适用于数据审计)。当然,OP 只要求前者。
1赞 Aldo aldo 6/27/2022
为每次插入创建一个触发器是否会使插入过程变得昂贵?这可以在生产环境中执行吗?
303赞 user330315 3/5/2012 #2

若要在插入期间填充列,请使用 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 语句中提供值来显式覆盖该列的值。如果你想防止这种情况发生,你确实需要一个触发器

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

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

评论

27赞 Basil Bourque 10/2/2014
请注意,Postgres 具有告诉您 (1) 实际当前时刻的时间、(2) 语句开始的时间和 (3) 事务开始时间的功能。此处显示的示例是当前事务的开始。您可能希望也可能不希望这样做,而不是其他两种可能性。
10赞 Basil Bourque 10/2/2014
关于避免与保留字发生冲突的名称的好奖励点。请注意,SQL 规范明确承诺永远不会使用尾随下划线作为保留字。所以你可以做成.更好的是更具描述性的名称,例如.timestamptimestamp_row_created_
2赞 Rahly 6/21/2017
在类型的 Postgres 文档中是这样说的。Varchar 有额外的 CPU 周期来检查约束,这在 TEXT 上不会发生。
1赞 6/21/2017
我非常怀疑你是否能注意到“几个额外的 CPU 周期”的区别。出于所有实际目的,性能(或存储)没有任何差异。
5赞 Rahly 6/22/2017
不是单个字段,但我从未见过具有单个字段的有用表。字段数使此约束更加复杂。我记得将表格中的所有 varchar 更改为文本,并获得了 15% 的写作改进。此外,小的绩效惩罚不是“否”的性能惩罚。
94赞 Jim Yu 10/10/2014 #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';

评论

0赞 mickmackusa 10/30/2023
这个问题不是在问覆盖 UPDATE 上的时间戳。这个问题询问如何在执行 INSERT 查询时将字段值设置为当前时间戳。
19赞 Parichay Mo 6/7/2015 #4

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

评论

16赞 Alex Hope O'Connor 9/15/2020
仅用于添加值,在更新记录时似乎不使用默认值。
0赞 comte 2/10/2023
除此之外,它是一个“默认”值,因此可以被覆盖,这可能是审计目的的问题。
7赞 Ashish Kumar 10/12/2021 #5

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

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();
1赞 RoutesMaps.com 10/28/2021 #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();