Memiliki kolom cap waktu Dibuat dan Terakhir Diperbarui di MySQL 4.0

127

Saya memiliki skema tabel berikut;

CREATE TABLE `db1`.`sms_queue` (
  `Id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
  `Message` VARCHAR(160) NOT NULL DEFAULT 'Unknown Message Error',
  `CurrentState` VARCHAR(10) NOT NULL DEFAULT 'None',
  `Phone` VARCHAR(14) DEFAULT NULL,
  `Created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `LastUpdated` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  `TriesLeft` tinyint NOT NULL DEFAULT 3,
  PRIMARY KEY (`Id`)
)
ENGINE = InnoDB;

Gagal dengan kesalahan berikut:

ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause.

Pertanyaan saya adalah, bisakah saya memiliki kedua bidang tersebut? atau apakah saya harus secara manual mengatur bidang LastUpdated selama setiap transaksi?

Xenph Yan
sumber
Hei, @Xenph Yan, maukah Anda mengubah jawaban "Diterima" dari yang salah saat ini menjadi yang benar? Jawaban yang salah dan diterima ini membuat saya kehilangan sekitar 15 menit mencoba untuk mencari tahu apa yang terjadi ...
Bruno Reis
1
@BrunoReis Selesai, terima kasih atas penjemputannya.
Xenph Yan

Jawaban:

128

Dari dokumentasi MySQL 5.5 :

Satu kolom TIMESTAMP dalam tabel dapat memiliki cap waktu saat ini sebagai nilai default untuk menginisialisasi kolom, sebagai nilai pembaruan otomatis, atau keduanya. Tidak mungkin memiliki stempel waktu saat ini menjadi nilai default untuk satu kolom dan nilai pembaruan otomatis untuk kolom lainnya.

Perubahan pada MySQL 5.6.5 :

Sebelumnya, paling banyak satu kolom TIMESTAMP per tabel dapat secara otomatis diinisialisasi atau diperbarui ke tanggal dan waktu saat ini. Pembatasan ini telah dicabut. Definisi kolom TIMESTAMP dapat memiliki kombinasi dari DEFAULT CURRENT_TIMESTAMP dan ON UPDATE CURRENT_TIMESTAMP klausa. Selain itu, klausa ini sekarang dapat digunakan dengan definisi kolom DATETIME. Untuk informasi lebih lanjut, lihat Inisialisasi Otomatis dan Pembaruan untuk TIMESTAMP dan DATETIME.

Robert Gamble
sumber
Itu telah berubah (setidaknya di MySQL 5.0). Lihat dokumentasi: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
Melawan @SimonSimCity: Dokumen untuk 5.0 mengatakan hal yang sama persis seperti di atas.
davemyron
5
@RobertGamble Saya pikir pertanyaan yang lebih menarik adalah MENGAPA THE HECK THE DON'T mereka belum menyediakan cara melakukan ini fungsi yang sangat umum diminta / dibutuhkan.
Ray
22
Ini tampaknya agak sewenang-wenang pada bagian MySQL. Adakah yang bisa menjelaskan mengapa ini masalahnya?
humble_coder
12
Komentar yang benar-benar sangat tua, TETAPI, akhirnya diubah: Changes in MySQL 5.6.5 (2012-04-10, Milestone 8) Previously, at most one TIMESTAMP column per table could be automatically initialized or updated to the current date and time. This restriction has been lifted. Any TIMESTAMP column definition can have any combination of DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses. In addition, these clauses now can be used with DATETIME column definitions. For more information, see Automatic Initialization and Updating for TIMESTAMP and DATETIME.
Mauricio Vargas
83

Ada trik untuk memiliki kedua cap waktu, tetapi dengan sedikit batasan.

Anda hanya dapat menggunakan salah satu definisi dalam satu tabel. Buat kedua kolom stempel waktu seperti ini:

create table test_table( 
  id integer not null auto_increment primary key, 
  stamp_created timestamp default '0000-00-00 00:00:00', 
  stamp_updated timestamp default now() on update now() 
); 

Perhatikan bahwa perlu masuk nullke dalam kedua kolom selama insert:

mysql> insert into test_table(stamp_created, stamp_updated) values(null, null); 
Query OK, 1 row affected (0.06 sec)

mysql> select * from test_table; 
+----+---------------------+---------------------+ 
| id | stamp_created       | stamp_updated       |
+----+---------------------+---------------------+
|  2 | 2009-04-30 09:44:35 | 2009-04-30 09:44:35 |
+----+---------------------+---------------------+
2 rows in set (0.00 sec)  

mysql> update test_table set id = 3 where id = 2; 
Query OK, 1 row affected (0.05 sec) Rows matched: 1  Changed: 1  Warnings: 0  

mysql> select * from test_table;
+----+---------------------+---------------------+
| id | stamp_created       | stamp_updated       | 
+----+---------------------+---------------------+ 
|  3 | 2009-04-30 09:44:35 | 2009-04-30 09:46:59 | 
+----+---------------------+---------------------+ 
2 rows in set (0.00 sec)  
Bogdan Gusiev
sumber
Berikut tautan dari MySQL-Documentation yang menjelaskan fungsi itu: dev.mysql.com/doc/refman/5.0/en/timestamp.html
SimonSimCity
6
kotak kode pertama, ketika dimasukkan secara manual bekerja dengan sempurna untuk saya. Terima kasih! Saya berharap saya memiliki cukup 'karma' untuk menghapuskan jawaban ini karena menghemat bacon saya. mmmmm menyimpan bacon.
amatusko
Anda perlu memastikan bahwa stamp_created itu juga diatur sebagai TIDAK NULL. MySQL akan secara otomatis mengganti NULL dengan cap waktu saat ini.
Valentin Despa
Mengapa Anda tidak menjadikan stamp_createdbidang sebagai: stamp_created timestamp default now()alih-alih menggunakan nilai 'NOL'?
Sebastian Scholle
28

Anda dapat memiliki keduanya, lepas saja bendera "CURRENT_TIMESTAMP" di bidang yang dibuat. Setiap kali Anda membuat catatan baru di tabel, cukup gunakan "SEKARANG ()" untuk nilai.

Atau.

Sebaliknya, hapus bendera 'ON UPDATE CURRENT_TIMESTAMP' dan kirim SEKARANG () untuk bidang itu. Cara itu sebenarnya lebih masuk akal.

Stephen Walcher
sumber
2
Apakah ini satu-satunya jalan? Saya tidak bisa melihat database setelah semua detail itu?
Xenph Yan
2
Menurut manual MySql, CURRENT_TIMESTAMP adalah sinonim untuk SEKARANG () jadi saya tidak berpikir ini akan berhasil.
tvanfosson
Saya yakin Anda bisa, hanya saja CURRENT_TIMESTAMP adalah bendera yang dicadangkan hanya untuk satu bidang. Either way, jika Anda memiliki bendera itu di sana, terlepas dari nilai apa yang Anda miliki untuk bidang itu ketika Anda menambahkan catatan, itu akan selalu menjadi timestamp saat ini, maka namanya.
Stephen Walcher
1
@tvanfosson: Menggunakan 'SEKARANG ()' dalam permintaan melewati waktu saat ini ke database. Nilai apa sebenarnya tergantung pada bahasa, mesin, dan mungkin seratus hal lain yang saya tidak tahu. Bendera yang saya maksudkan untuk menyetelnya sehingga ketika catatan dibuat, waktu ditambahkan ke bidang itu.
Stephen Walcher
2
Saya menggunakan cara insert NOW (), sebagian besar karena kode lain mungkin menyentuh tabel ini dan saya tidak percaya orang memperbaruinya dengan benar. :)
Xenph Yan
26

Jika Anda memutuskan untuk membuat MySQL menangani pembaruan cap waktu, Anda dapat mengatur pemicu untuk memperbarui bidang saat disisipkan.

CREATE TRIGGER <trigger_name> BEFORE INSERT ON <table_name> FOR EACH ROW SET NEW.<timestamp_field> = CURRENT_TIMESTAMP;

Referensi MySQL: http://dev.mysql.com/doc/refman/5.0/id/triggers.html

webkraller
sumber
Bagus inilah yang saya cari. Saya tidak mau harus bergantung pada orang yang ditambahkan SEKARANG () ke dalam kueri!
Bot
sebenarnya akan lebih baik untuk dilakukan setelah memasukkan, dan mengatur BARU. <timestamp_field> = baru. <timestamp_field yang benar-benar harus memiliki current_timestamp default> dengan cara ini kedua bidang tersebut konsisten
KacieHouser
@KacieHouser Memperbarui baris BARU tidak diizinkan setelah pemicu
Thomas
23

Ini adalah bagaimana Anda dapat memiliki bidang createDate / lastModified otomatis & fleksibel menggunakan pemicu:

Pertama mendefinisikannya seperti ini:

CREATE TABLE `entity` (
  `entityid` int(11) NOT NULL AUTO_INCREMENT,
  `createDate` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `lastModified` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `name` varchar(255) DEFAULT NULL,
  `comment` text,
  PRIMARY KEY (`entityid`),
)

Kemudian tambahkan pemicu ini:

DELIMITER ;;
CREATE trigger entityinsert BEFORE INSERT ON entity FOR EACH ROW BEGIN SET NEW.createDate=IF(ISNULL(NEW.createDate) OR NEW.createDate='0000-00-00 00:00:00', CURRENT_TIMESTAMP, IF(NEW.createDate<CURRENT_TIMESTAMP, NEW.createDate, CURRENT_TIMESTAMP));SET NEW.lastModified=NEW.createDate; END;;
DELIMITER ;
CREATE trigger entityupdate BEFORE UPDATE ON entity FOR EACH ROW SET NEW.lastModified=IF(NEW.lastModified<OLD.lastModified, OLD.lastModified, CURRENT_TIMESTAMP);
  • Jika Anda menyisipkan tanpa menentukan createDate atau LastModified, mereka akan sama dan diatur ke stempel waktu saat ini.
  • Jika Anda memutakhirkannya tanpa menentukan createDate atau lastModified, lastModified akan disetel ke stempel waktu saat ini.

Tapi inilah bagian yang bagus:

  • Jika Anda menyisipkan , Anda dapat menentukan tanggal membuat lebih lama dari cap waktu saat ini , memungkinkan impor dari waktu yang lebih lama untuk bekerja dengan baik (lastModified akan sama dengan createDate).
  • Jika Anda memperbarui , Anda dapat menentukan yang terakhir dimodifikasi lebih lama dari nilai sebelumnya ('0000-00-00 00:00:00' berfungsi dengan baik), memungkinkan untuk memperbarui entri jika Anda melakukan perubahan kosmetik (memperbaiki kesalahan ketik dalam komentar ) dan Anda ingin menyimpan tanggal Modifikasi terakhir yang lama . Ini tidak akan mengubah tanggal modifikasi terakhir.
asing
sumber
21

Pada MySQL 5.6 yang mudah-peasy ... coba saja:

create table tweet ( 
    id integer not null auto_increment primary key, 
    stamp_created timestamp default now(), 
    stamp_updated timestamp default now() on update now(),
    message varchar(163)
)
Shaheen Ghiassy
sumber
Mungkin solusi hebat Apa yang saya cari buat & perbarui masalah waktu tanpa pemicu
matinict
Aku tidak percaya butuh waktu selama ini untuk gangguan kecil ini diselesaikan. Saya bahkan tidak menyadari bahwa mereka telah memperbaiki ini dan ini tahun 2018 ... Terima kasih.
hsanders
4

Masalah ini sepertinya telah diselesaikan di MySQL 5.6. Saya perhatikan ini sampai MySQL 5.5; di sini adalah contoh kode:

DROP TABLE IF EXISTS `provider_org_group` ;
CREATE TABLE IF NOT EXISTS `provider_org_group` (
  `id` INT NOT NULL,
  `name` VARCHAR(100) NOT NULL,
  `type` VARCHAR(100) NULL,
  `inserted` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `insert_src_ver_id` INT NULL,
  `updated` TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP,
  `update_src_ver_id` INT NULL,
  `version` INT NULL,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `id_UNIQUE` (`id` ASC),
  UNIQUE INDEX `name_UNIQUE` (`name` ASC))
ENGINE = InnoDB;

Menjalankan ini di MySQL 5.5 memberi:

ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause

Menjalankan ini di MySQL 5.6

0 row(s) affected   0.093 sec
Kingz
sumber
2

Untuk mysql 5.7.21 Saya menggunakan yang berikut ini dan berfungsi dengan baik:

CREATE TABLE Posts( modified_attimestamp TIDAK NULL DEFAULT CURRENT_TIMESTAMP PADA PEMBARUAN CURRENT_TIMESTAMP, created_attimestamp TIDAK NULL DEFAULT CURRENT_TIMESTAMP)

Ioannis Chrysochos
sumber
1

saya pikir ini adalah permintaan yang lebih baik untuk stamp_created dan stamp_updated

CREATE TABLE test_table( 
    id integer not null auto_increment primary key, 
    stamp_created TIMESTAMP DEFAULT now(), 
    stamp_updated TIMESTAMP DEFAULT '0000-00-00 00:00:00' ON UPDATE now() 
); 

karena ketika catatan dibuat, stamp_createdharus diisi oleh now()dan stamp_updatedharus diisi oleh'0000-00-00 00:00:00'

Anonim-
sumber