ฉันจะอัปเดตการประทับเวลาโดยอัตโนมัติใน PostgreSQL ได้อย่างไร


133

ฉันต้องการให้รหัสสามารถอัปเดตการประทับเวลาโดยอัตโนมัติเมื่อมีการแทรกแถวใหม่ตามที่ฉันสามารถทำได้ใน 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
)

6
อย่างไรก็ตามประเภทข้อมูลของคุณtimestampถูกกำหนดโดยข้อมูลจำเพาะ SQL เป็นตัวย่อของTIMESTAMP WITHOUT TIME ZONE. ที่เกือบจะไม่แน่นอนสิ่งที่คุณต้องการเป็นอธิบายโดยผู้เชี่ยวชาญ Postgres เดวิดอีวีลเลอร์ อีกประเภทหนึ่งTIMESTAMP WITH TIME ZONEอาจเป็นสิ่งที่คุณต้องการโดยใช้ข้อมูลออฟเซ็ตโซนเวลาที่ผ่านใด ๆ เพื่อปรับวันที่ - เวลาเป็นUTC (แต่ไม่ได้จัดเก็บข้อมูลโซนเวลานั้นแม้จะมีชื่อประเภทก็ตาม)
Basil Bourque

3
หลังจากได้เรียนรู้สิ่งนี้อีกครั้งฉันได้เขียนบล็อกโพสต์โดยละเอียดเกี่ยวกับการบันทึกวันที่ - เวลาของทั้งการสร้างและแก้ไขแถวโดยใช้ค่าเริ่มต้นฟังก์ชันและทริกเกอร์ รวมตัวอย่างที่สมบูรณ์โค้ด SQL และ PL / pgSQL สำหรับใช้ใน Postgres
Basil Bourque

คำตอบ:


197

ในการเติมคอลัมน์ระหว่างการแทรกให้ใช้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คำสั่ง หากคุณต้องการที่จะป้องกันไม่ให้คุณทำต้องมีทริกเกอร์

คุณต้องมีทริกเกอร์หากคุณต้องการอัปเดตคอลัมน์นั้นเมื่อใดก็ตามที่มีการอัปเดตแถว ( ตามที่ EJ Brennan กล่าวไว้ )

โปรดทราบว่าการใช้คำสงวนสำหรับชื่อคอลัมน์มักไม่ใช่ความคิดที่ดี คุณควรหาชื่ออื่นที่ไม่ใช่timestamp


14
โปรดทราบว่า Postgres มีฟังก์ชันที่จะบอกคุณ (1) เวลาของช่วงเวลาปัจจุบันจริง (2) เวลาที่คำสั่งเริ่มต้นและ (3) เวลาที่ธุรกรรมเริ่มต้น ตัวอย่างที่แสดงที่นี่คือจุดเริ่มต้นของธุรกรรมปัจจุบัน คุณอาจต้องการหรือไม่ต้องการสิ่งนั้นเมื่อเทียบกับความเป็นไปได้อีกสองข้อ
Basil Bourque

6
คะแนนโบนัสที่ดีเกี่ยวกับการหลีกเลี่ยงชื่อที่ชนกับคำสงวน โปรดทราบว่าข้อมูลจำเพาะของ SQL สัญญาอย่างชัดเจนว่าจะไม่ใช้ขีดล่างเป็นคำสงวน เพื่อให้คุณสามารถเข้าสู่timestamp ยิ่งไปกว่านั้นจะเป็นชื่อสุชาอธิบายเพิ่มเติมเป็นtimestamp_ row_created_
Basil Bourque

ครึ่งแรกไม่ใช่สิ่งที่ OP ถามเลยแม้ว่าครึ่งหลังจะอ้างถึงคำตอบอื่น ๆ (ซึ่งถูกต้อง) แต่ก็ยังทำให้เข้าใจผิด ไม่ควรยอมรับว่าเป็นคำตอบ
Eric Wang

1
กล่าวเช่นนั้นในเอกสาร Postgres ของประเภท Varchar มีรอบ CPU พิเศษเพื่อตรวจสอบข้อ จำกัด ซึ่งไม่เกิดขึ้นใน TEXT
Rahly

3
ไม่ใช่กับเขตข้อมูลเดียว แต่ฉันไม่เคยเห็นตารางที่มีประโยชน์กับเขตข้อมูลเดียว ข้อ จำกัด นี้ประกอบด้วยจำนวนฟิลด์ ฉันจำได้ว่าเปลี่ยน varchar ทั้งหมดในตารางเป็นข้อความและได้รับการปรับปรุงการเขียน 15% นอกจากนี้การลงโทษจากการปฏิบัติงานเพียงเล็กน้อยก็ไม่ใช่โทษจากการปฏิบัติงาน "ไม่"
Rahly

104

คุณจะต้องเขียนทริกเกอร์แทรกและอาจเป็นทริกเกอร์การอัปเดตหากคุณต้องการให้เปลี่ยนแปลงเมื่อมีการเปลี่ยนแปลงระเบียน บทความนี้อธิบายได้ค่อนข้างดี:

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

2
นี่คือคำตอบที่ดีที่สุด IMO (แม้ว่าค่าเริ่มต้นจะเพียงพอสำหรับการแทรกก็ตาม)
kik

2
มีอะไรใหม่ที่นี่?
Naveen


นี่เป็นโซลูชันที่สมบูรณ์ยิ่งขึ้นซึ่งจะทำงานร่วมกับ INSERTs เริ่มต้นและการอัปเดตที่ตามมา (เหมาะสำหรับการตรวจสอบข้อมูล) จริงอยู่ที่ OP ขอเฉพาะอดีต
Pavel Lechev

5
@Naveen ไม่มากมีอะไรใหม่กับคุณ?
Underyx

57

การอัปเดตการประทับเวลาเฉพาะเมื่อค่าเปลี่ยนไป

ตามลิงค์ของ EJ และเพิ่มคำสั่ง 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';

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.