I am using MySQL 5.6.1 on a Win 7 64Bit.
I have a standard audit column I add to all my tables called CRT_TS (create timestamp), along with a UPD_TS (update timestamp) column. I had planned on populating these via a before insert trigger and a before update trigger using utc_timestamp().
The UPD_TS column behaves as I expect it to. However, the CRT_TS column seems to be getting automatically populated without my defining a default or trigger for that column.
I was able to reproduce this behavior by running the following script.
create schema `test` default character set utf8 collate utf8_general_ci;
drop table test.TEST_TABLE;
create table test.TEST_TABLE(
TEST_ID int not null auto_increment ,
CRT_TS timestamp not null ,
UPD_TS timestamp not null ,
TEST_ALIAS varchar(64) not null ,
primary key PK_PERM (TEST_ID) ,
unique index UI_PERM_01 (TEST_ALIAS) )
auto_increment = 1001;
insert into test.TEST_TABLE
(TEST_ID
,TEST_ALIAS)
values
(1
,'testing');
select *
from test.TEST_TABLE;
In the above example, the CRT_TS column isn't being supplied a value, and yet it is being populated with the same value what would have been provided by the now() function. The UPD_TS column is populated with all zeros, yet both columns have been defined identically.
My questions is, what is populating the CRT_TS column? I am attempting to set both the UPD_TS and CRT_TS columns to utc_timestamp() value. Even setting the value in a trigger for CRT_TS, the value is overridden.
Thanks for any clarity you can provide.
Related
so, I have a table named companies and I want to add 2 columns for insert and update times.
how do I do this? I dont want to add insert and update dates into my query.
this is my create statement
create table companies(
name varchar(20),
city char(10),
numberofemployees int(10),
averagesalary double
);
alter table companies add inserttime datetime, add updatedtime datetime, add id serial;
I need the insert query to look like this:
insert into companies values ("company","bglr",30,400.00)
and need output as
name,city,numberofemployees,averagesalary,inserttime,updatetime
company blr 30 400.00 23:00:11 23:00:11
First of all, you'll have to change your INSERT statement since the number of values doesn't match the number of columns. Luckily, you can specify the subset of columns that correspond to the given values:
INSERT INTO companies(name, city, numberofemployees, averagesalary)
VALUES ('company', 'blgr', 30, 400.00);
As you don't provide values for inserttime and updatetime, default values will be used for new records. Another way to insert records using default values is to put in the DEFAULT keyword instead of a concrete value (please refer to the documentation of INSERT for more details).
In your case the default values should be NULL because you didn't define anything else. To change the DEFAULT value for your columns, you can modify their definitions:
ALTER TABLE companies MODIFY COLUMN inserttime datetime DEFAULT CURRENT_TIMESTAMP;
Having this, inserttime is set to the current time for newly inserted records. Of course, you can also use the DEFAULT clause in CREATE TABLE statements, or while adding the columns.
Next, let's have a look at the updatetime. Usually, you want this to be updated automatically to the current time. This can be achieved in MySQL by specifying an ON UPDATE clause for the default value (details in Automatic Initialization and Updating for TIMESTAMP and DATETIME:
ALTER TABLE companies MODIFY COLUMN
updatetime datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
From now on, updatetime will be set to the current time automatically when a new record is inserted or an existing record is updated.
More information about default values in MySQL can be found in the documentation.
I have not used MySQL in a few years and when I created a new table it did something I was not expecting. I am using MariaDB v5.5.60-MariaDB
I need to create a table that has both a created column and an updated column.
I need the created column to only be set to CURRENT_TIMESTAMP when the row is created and then never change unless I change it explicitly.
I need the updated column to be set to CURRENT_TIMESTAMP both when the row is created and when the row is changed.
If I do the following:
CREATE TABLE user_prefs (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
user VARCHAR(255) NOT NULL,
provider VARCHAR(255) NOT NULL,
pref VARCHAR(128) NOT NULL,
jsondata LONGTEXT,
created timestamp NOT NULL,
modified timestamp NOT NULL,
PRIMARY KEY (id),
UNIQUE INDEX id_UNIQUE (id ASC));
Then the created column is set to:
DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
and the modified column is set to:
DEFAULT '0000-00-00 00:00:00'
If I try this:
CREATE TABLE user_prefs (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
user VARCHAR(255) NOT NULL,
provider VARCHAR(255) NOT NULL,
pref VARCHAR(128) NOT NULL,
jsondata LONGTEXT,
created timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
modified timestamp NOT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE INDEX id_UNIQUE (id ASC));
Then I get the error **Error Code: 1293. Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause
**
So is there a way to automate setting both created and modified on creation of a row and then to change modified every time the row is change?
Thanks in advance.
A table might have automatic initialization of date in only one column in old versions of MySQL. But its behavior fixed in version 5.6.5.
It means you have several ways to avoid this error:
1.You can upgrade your MySQL to the latest version;
Advantages:
native clear implementation of modification dates management in a database side
there aren't excess triggers
Вrawback:
if the current version of MySQL is used in exists projects then upgrading might make some problems.
2.You can create triggers for updating and the creation of a record, as #Simonare said
Advantages:
implementation of modification dates management in a database side
Вrawback:
there are many excess triggers. You'll create two triggers for each table. It means you'll create N*2 triggers for N tables.
3.You can set default value of created column to 0000-00-00 00:00:00 and set default value of updated column to CURRENT_TIMESTAMP(). In this case date of updating will be generated automatically. Also if you write null to created column MySQL will generate current date automatically and set it to the column. For example:
CREATE TABLE example_table (
created TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
updated_at TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP
);
If you execute the following query:
INSERT INTO example_table (created) VALUES (null);
created column will have current date value. MySQL will fill it automatically.
Advantages:
there aren't excess triggers
Вrawback:
implementation of modification dates management in a database side and client application side
4.You can use automatic initialization of date in updated column and use trigger to fill created column. For example:
CREATE TABLE example_table (
created TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00',
updated_at TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP
);
DELIMITER //
CREATE TRIGGER example_table_set_created_date
BEFORE INSERT
ON example_table FOR EACH ROW
BEGIN
SET NEW.created = CURRENT_TIMESTAMP();
END; //
DELIMITER;
Advantages:
implementation of modification dates management in a database side
Вrawback:
there are many excess triggers. You'll create N triggers for N tables.
you can create trigger for this
DELIMITER //
CREATE TRIGGER user_prefs_before_insert
BEFORE INSERT
ON user_prefs FOR EACH ROW
BEGIN
SET NEW.updated = new.created;
END; //
DELIMITER ;
then another trigger for update
DELIMITER //
CREATE TRIGGER user_prefs_before_update
BEFORE UPDATE
ON user_prefs FOR EACH ROW
BEGIN
SET NEW.updated = CURRENT_TIMESTAMP();
END; //
DELIMITER ;
I have an InnoDB table with a timestamp in it, and I wish to have another field which carries only the date part of the timestamp, so that I can create an index on it. (My temporal queries will always be bound by date, so having an index with high cardinality on the timestamp is not really needed.)
Is it possible to have the date field update automatically ON UPDATE from the timestamp field (similar to how CURRENT_TIMESTAMP works)?
I tried the following but it MySQL says I have an error in my SQL syntax.
CREATE TABLE test_table (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`full_ts` timestamp NULL DEFAULT NULL COMMENT 'The full timestamp',
`only_date` date NULL DEFAULT NULL ON UPDATE date(full_ts) COMMENT 'This field carries only the date part of the full timestamp for better indexing.',
PRIMARY KEY (`id`),
KEY `ONLY_DATE_IDX` (`only_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I could of course update both fields everywhere in the code, but it would be cleaner if the only_date field was a slave of the full_ts field, updated and kept consistent by the database.
I know that in MySQL 5.7.5 there was a new feature added for stored generated columns, which seem to do exactly this. Unfortunately it is not possible to upgrade the database version at the moment.
Is there a way to achieve this in MySQL 5.5?
This will update the "only_date" column when you update the "full_ts" column
CREATE TRIGGER `autoDate` BEFORE UPDATE ON `test_table` FOR EACH ROW BEGIN
SET NEW.only_date=DATE(NEW.full_ts);
END
EDIT:
For further reading on triggers, please refer to https://dev.mysql.com/doc/refman/5.5/en/create-trigger.html
Also worth reading about triggers https://dev.mysql.com/doc/refman/5.5/en/faqs-triggers.html
What does AUTO_INCREMENT=535 actually mean or do? I have seen this used when creating tables as shown below, but never knew what it does or is used for.
Create Table:
CREATE TABLE `my_table` (
`entry_id` int(11) NOT NULL auto_increment,
`address` varchar(512) NOT NULL,
PRIMARY KEY(entry_id)
) ENGINE=InnoDB AUTO_INCREMENT=535 DEFAULT CHARSET=utf8
Auto increment field allow automatic indexing of the records in a table. Usually serving as a Unique Key
Any table with definition like AUTO_INCREMENT=535 would mean that next auto-generated key will start from the 535.
This usually happen when you take backup from existing database. But also can be used in some special cases to have higher value of starting index.
Tells when to start with auto_increment counting. For example if you want to reserve some number of ID for some dedicated purposes.
The AUTO_INCREMENT attribute can be used to generate a unique identity
You can use a pair of statements: DROP TABLE and CREATE TABLE to reset the auto-increment column. Like the TRUNCATE TABLE statement, those statements removes all the data and reset the auto-increment value to zero.
No value was specified for the AUTO_INCREMENT column, so MySQL assigned sequence numbers automatically.
You can also ** explicitly assign 0 ** to the column to generate sequence numbers. If the column is declared NOT NULL, it is also ** possible to assign NULL ** to the column to generate sequence numbers.
You can retrieve the most recent AUTO_INCREMENT value with the LAST_INSERT_ID()
To start with an AUTO_INCREMENT value other than 1, you can set that value with CREATE TABLE or ALTER TABLE, like this:
mysql> ALTER TABLE tbl AUTO_INCREMENT = 100;
The AUTO INCREMENT interval value is controlled by the MySQL Server variable auto_increment_increment and applies globally. To change this to a number different from the default of 1, use the following command in MySQL:
mysql> SET ##auto_increment_increment = [interval number];
where [interval number] is the interval value you want to use. So, if we want to set the interval to be 5, we would issue the following command:
mysql> SET ##auto_increment_increment = 5;
refrence:-
http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
In my MySQL table I've created an ID column which I'm hoping to auto-increment in order for it to be the primary key.
I've created my table:
CREATE TABLE `test` (
`id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 50 ) NOT NULL ,
`date_modified` DATETIME NOT NULL ,
UNIQUE (
`name`
)
) TYPE = INNODB;
then Inserted my records:
INSERT INTO `test` ( `id` , `name` , `date_modified` )
VALUES (
NULL , 'TIM', '2011-11-16 12:36:30'
), (
NULL , 'FRED', '2011-11-16 12:36:30'
);
I'm expecting that my ID's for the above are 1 and 2 (respectively). And so far this is true.
However when I do something like this:
insert into test (name) values ('FRED')
on duplicate key update date_modified=now();
then insert a new record, I'm expecting it to be 3, however now I'm shown an ID of 4; skipping the place spot for 3.
Normally this wouldn't be an issue but I'm using millions of records which have thousands of updates every day.. and I don't really want to even have to think about running out of ID's simply because I'm skipping a ton of numbers..
Anyclue to why this is happening?
MySQL version: 5.1.44
Thank you
My guess is that the INSERT itself kicks off the code that generates the next ID number. When the duplicate key is detected, and ON DUPLICATE KEY UPDATE is executed, the ID number is abandoned. (No SQL dbms guarantees that automatic sequences will be without gaps, AFAIK.)
MySQL docs say
In general, you should try to avoid using an ON DUPLICATE KEY UPDATE
clause on tables with multiple unique indexes.
That page also says
If a table contains an AUTO_INCREMENT column and INSERT ... ON
DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID()
function returns the AUTO_INCREMENT value.
which stops far short of describing the internal behavior I guessed at above.
Can't test here; will try later.
Is it possible to change your key to unsigned bigint - 18,446,744,073,709,551,615 is a lot of records - thus delaying the running out of ID's
Found this in mysql manual http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html
Use a large enough integer data type for the AUTO_INCREMENT column to hold the
maximum sequence value you will need. When the column reaches the upper limit of
the data type, the next attempt to generate a sequence number fails. For example,
if you use TINYINT, the maximum permissible sequence number is 127.
For TINYINT UNSIGNED, the maximum is 255.
More reading here http://dev.mysql.com/doc/refman/5.6/en/information-functions.html#function_last-insert-id it could be inferred that the insert to a transactional table is a rollback so the manual says "LAST_INSERT_ID() is not restored to that before the transaction"
What about for a possible solution to use a table to generate the ID's and then insert into your main table as the PK using LAST_INSERT_ID();
From the manual:
Create a table to hold the sequence counter and initialize it:
mysql> CREATE TABLE sequence (id INT NOT NULL);
mysql> INSERT INTO sequence VALUES (0);
Use the table to generate sequence numbers like this:
mysql> UPDATE sequence SET id=LAST_INSERT_ID(id+1);
mysql> SELECT LAST_INSERT_ID();
The UPDATE statement increments the sequence counter and causes the next call to
LAST_INSERT_ID() to return the updated value. The SELECT statement retrieves that
value. The mysql_insert_id() C API function can also be used to get the value.
See Section 20.9.3.37, “mysql_insert_id()”.
It's really a bug how you can see here: http://bugs.mysql.com/bug.php?id=26316
But, apparently, they fixed it on 5.1.47 and it was declared as INNODB plugin problem.
A duplicate, but same problem, you can see here too: http://bugs.mysql.com/bug.php?id=53791 referenced to the first page mentioned here in this answer.