提问人:Aaron 提问时间:3/5/2012 最后编辑:mickmackusaAaron 更新时间:10/30/2023 访问量:266077
插入新行时在 PostgreSQL 中自动填充时间戳字段
Automatically populate a timestamp field in PostgreSQL when a new row is inserted
问:
我希望代码能够在插入新行时自动填充时间戳值,就像我在 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
)
答:
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 规范明确承诺永远不会使用尾随下划线作为保留字。所以你可以做成.更好的是更具描述性的名称,例如.timestamp
timestamp_
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_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();
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();
评论
timestamp
TIMESTAMP WITHOUT TIME ZONE
TIMESTAMP WITH TIME ZONE