I want to create a table with a PK column with the current year
CREATE TABLE IF NOT EXISTS `example` (
`yearId` YEAR NOT NULL DEFAULT year(curdate()),
PRIMARY KEY (`yearId`))
ENGINE = InnoDB
But it is not correct.
I know that I can save the CURRENT_TIMESTAMP
CREATE TABLE IF NOT EXISTS `example` (
`yearId` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`yearId`))
ENGINE = InnoDB
But I only want the year.
Is there any way to do it?
Just call the YEAR() function and pass that value to it.
CREATE TABLE IF NOT EXISTS `example` (
`yearId` TIMESTAMP NOT NULL DEFAULT YEAR(CURRENT_TIMESTAMP),
PRIMARY KEY (`yearId`))
ENGINE = InnoDB
Click here for more date and time functions.
P.S. You should probably set the data type for that column to YEAR(4) to ensure that only valid values for a year are entered.
Related
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 a large table named 'roomlogs' which has nearly 1 million entries.
The structure of the table:
id --> PK
roomId --> varchar FK to rooms table
userId --> varchar FK to users table
enterTime --> Date and Time
exitTime --> Date and Time
status --> bool
I have the previous indexing on roomID, I recently added an index on the userId column.
So, When I run a stored procedure with following code it is taking more time like on average 50 seconds. WHich it should not take.
DELIMITER ;;
CREATE DEFINER=`root`#`%` PROCEDURE `enter_room`(IN pRoomId varchar(200), IN puserId varchar(50), IN ptime datetime, IN phidden int, pcheckid int, pexit datetime)
begin
update roomlogs set
roomlogs.exitTime = ptime,
roomlogs.`status` = 1
where
roomlogs.userId = puserId
and roomlogs.`status` = 0
and DATEDIFF(ptime,roomlogs.enterTime) = 0;
INSERT into roomlogs
( roomlogs.roomId,
roomlogs.userId,
roomlogs.enterTime,
roomlogs.exitTime,
roomlogs.hidden,
roomlogs.checkinId )
value
( pRoomId,
userId,
ptime,
pexit,
phidden,
pcheckid);
select *
from
roomlogs
where
roomlogs.id= LAST_INSERT_ID();
end ;;
DELIMITER ;
What Can be the reason for it to take this much time:
I added an index recently so previous rows are not indexed.
There is no selection on storage type for any indexes right now. Should I change it to B-tree?
On my website, I get 20-30 simultaneous call on other procedures also while this procedure has 10-20 simultaneous calls, does the update query in the procedure make a lock? But in MySQL.slow_logs table for each query the lock _time shows 0.
Is there any other reason for this behaviour?
Edit: Here is the SHOW TABLE:
CREATE TABLE `roomlogs` (
`roomId` varchar(200) CHARACTER SET latin1 DEFAULT NULL,
`userID` varchar(50) CHARACTER SET latin1 DEFAULT NULL,
`enterTime` datetime DEFAULT NULL,
`exitTime` datetime DEFAULT NULL,
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` int(11) DEFAULT '0',
`hidden` int(11) DEFAULT '0',
`checkinId` int(11) DEFAULT '-1',
PRIMARY KEY (`id`),
KEY `RoomLogIndex` (`roomId`),
KEY `RoomLogIDIndex` (`id`),
KEY `USERID` (`userID`)
) ENGINE=InnoDB AUTO_INCREMENT=1064216 DEFAULT CHARSET=utf8
I can also see that this query is running more number of times like 100000 times per day (nearly continuously).
SELECT count(*) from roomlogs where roomId=proomId and status='0';
Because of this query reads from the same table, does InnoDB block or create a lock on update query because I can see that when the above-stored procedure is running more number of times then this query is taking more time.
Here is the link for MySQL variables: https://docs.google.com/document/d/17_MVaU4yvpQfVDT83yhSjkLHsgYd-z2mg6X7GwvYZGE/edit?usp=sharing
roomlogs needs this 'composite' index:
INDEX(userId, `status`, enterTime)
I added an index recently so previous rows are not indexed.
Not true. Adding an INDEX indexes the entire table.
The default index type is BTree; no need to explicitly specify it.
does the update query in the procedure make a lock?
It does some form of locking. What is the value of autocommit? Do you explicitly use BEGIN and COMMIT? Is the table ENGINE=InnoDB? Please provide SHOW CREATE TABLE.
MySQL.slow_logs table for each query the lock _time shows 0.
The INSERT you show seems to be inserting the same row as the UPDATE. Maybe you need INSERT ... ON DUPLICATE KEY UPDATE ...?
Don't "hide an index column in a function"; instead of DATEDIFF(roomlogs.enterTime,NOW()) = 0, do
AND enterTime >= CURDATE()
AND enterTime < CURDATE() + INTERVAL 1 DAY
This allows the index to be used more fully.
KEY `RoomLogIndex` (`roomId`), Change to (roomId, status)
KEY `RoomLogIDIndex` (`id`), Remove, redundant with the PK
Buffer pool in only 97,517,568 -- make it more like 9G.
I have two columns in table users namely registerDate and lastVisitDate which consist of datetime data type. I would like to do the following.
Set registerDate defaults value to MySQL NOW()
Set lastVisitDate default value to 0000-00-00 00:00:00 Instead of null which it uses by default.
Because the table already exists and has existing records, I would like to use Modify table. I've tried using the two piece of code below, but neither works.
ALTER TABLE users MODIFY registerDate datetime DEFAULT NOW()
ALTER TABLE users MODIFY registerDate datetime DEFAULT CURRENT_TIMESTAMP;
It gives me Error : ERROR 1067 (42000): Invalid default value for 'registerDate'
Is it possible for me to set the default datetime value to NOW() in MySQL?
As of MySQL 5.6.5, you can use the DATETIME type with a dynamic default value:
CREATE TABLE foo (
creation_time DATETIME DEFAULT CURRENT_TIMESTAMP,
modification_time DATETIME ON UPDATE CURRENT_TIMESTAMP
)
Or even combine both rules:
modification_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
Reference:
http://dev.mysql.com/doc/refman/5.7/en/timestamp-initialization.html
http://optimize-this.blogspot.com/2012/04/datetime-default-now-finally-available.html
Prior to 5.6.5, you need to use the TIMESTAMP data type, which automatically updates whenever the record is modified. Unfortunately, however, only one auto-updated TIMESTAMP field can exist per table.
CREATE TABLE mytable (
mydate TIMESTAMP
)
See: http://dev.mysql.com/doc/refman/5.1/en/create-table.html
If you want to prevent MySQL from updating the timestamp value on UPDATE (so that it only triggers on INSERT) you can change the definition to:
CREATE TABLE mytable (
mydate TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
I use a trigger as a workaround to set a datetime field to NOW() for new inserts:
CREATE TRIGGER `triggername` BEFORE INSERT ON `tablename`
FOR EACH ROW
SET NEW.datetimefield = NOW()
it should work for updates too
Answers by Johan & Leonardo involve converting to a timestamp field. Although this is probably ok for the use case presented in the question (storing RegisterDate and LastVisitDate), it is not a universal solution. See datetime vs timestamp question.
My solution
ALTER TABLE `table_name` MODIFY COLUMN `column_name` TIMESTAMP NOT
NULL DEFAULT CURRENT_TIMESTAMP;
EUREKA !!!
For all those who lost heart trying to set a default DATETIME value in MySQL, I know exactly how you feel/felt. So here it is:
`ALTER TABLE `table_name` CHANGE `column_name` DATETIME NOT NULL DEFAULT 0
Carefully observe that I haven't added single quotes/double quotes around the 0.
Important update:
This answer was posted long back. Back then, it worked on my (probably latest) installation of MySQL and I felt like sharing it. Please read the comments below before you decide to use this solution now.
On versions mysql 5.6.5 and newer, you can use precise datetimes and set default values as well. There is a subtle bit though, which is to pass in the precision value to both the datetime and the NOW() function call.
This Example Works:
ALTER TABLE my_table MODIFY created datetime(6) NOT NULL DEFAULT NOW(6);
This Example Does not Work:
ALTER TABLE my_table MODIFY created datetime(6) NOT NULL DEFAULT NOW();
mysql 5.6 docs say that CURRENT_TIMESTAMP can be used as default for both TIMESTAMP and DATETIME data types:
http://dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html
`ALTER TABLE `table_name` CHANGE `column_name`
timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
ON UPDATE CURRENT_TIMESTAMP
Can be used to update the timestamp on update.
The best way is using "DEFAULT 0".
Other way:
/************ ROLE ************/
drop table if exists `role`;
create table `role` (
`id_role` bigint(20) unsigned not null auto_increment,
`date_created` datetime,
`date_deleted` datetime,
`name` varchar(35) not null,
`description` text,
primary key (`id_role`)
) comment='';
drop trigger if exists `role_date_created`;
create trigger `role_date_created` before insert
on `role`
for each row
set new.`date_created` = now();
This worked for me, using MySQL:
ALTER TABLE `table_name` MODIFY `column_name` datetime NOT NULL DEFAULT NOW();
ALTER TABLE table_name
CHANGE COLUMN date_column_name date_column_name DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP;
Finally, This worked for me!
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dateCreated` datetime DEFAULT CURRENT_TIMESTAMP,
`dateUpdated` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `mobile_UNIQUE` (`mobile`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
Not sure if this is still active but here goes.
Regarding setting the defaults to Now(), I don't see that to be possible for the DATETIME data type. If you want to use that data type, set the date when you perform the insert like this:
INSERT INTO Yourtable (Field1, YourDateField) VALUES('val1', (select now()))
My version of mySQL is 5.5
This worked for me - just changed INSERT to UPDATE for my table.
INSERT INTO Yourtable (Field1, YourDateField) VALUES('val1', (select now()))
If i execute my sql create table statement i get an errormessage that says:
Invalid default value for 'end'
CREATE TABLE IF NOT EXISTS `monkeybutler`.`Setuptimeslot` (
`id` INT NOT NULL,
`begin` TIMESTAMP NOT NULL,
`end` TIMESTAMP NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
If I change the statement and comment out the "end"-column it works, but as soon as i try to create 2 columns of type TIMESTAMP it doesnt work anymore. How can I insert both columns without getting an error?
(This is the complete Create Table Statement and my mysql Version is 5.6.19)
I using a MySQL server (5.5.27 - Community Server). I have a table with this definition:
CREATE TABLE IF NOT EXISTS tbl_messages (
`msg_id` VARCHAR(50) NOT NULL ,
`msg_text` VARCHAR(50) NULL ,
PRIMARY KEY (`msg_id`);
I write a trigger that, when I do an insert, the server sets the msg_id column with the current time including microseconds with this format "yyyymmddhhnnssuuuuuu". "u" is for microseconds.
I created a trigger:
create trigger tbl_messages_trigger
before insert on tbl_messages
for each row
BEGIN
SET NEW.msg_id = DATE_FORMAT(NOW(),'%Y%m%d%H%i%s%f');
END;$$
But the msg_id column only gets values like this: 20130302144818*000000*, with microseconds in zero. ¿Is it possible capture the microseconds?
TIA,
From the code provided I guess that you are trying to use microsecond to minimize probability of getting same msg_id for different rows.
Also, msg_id is the primary key, which should not present any object-specific data but only be unique. There is a good link about: http://en.wikipedia.org/wiki/Surrogate_key
The best way to deal with primary keys in MySql is AUTO_INCREMENT column attribute. If you need insert time for messages, you may provide column for it:
CREATE TABLE tbl_messages
(
`msg_id` bigint(20) NOT NULL AUTO_INCREMENT,
`msg_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`msg_text` VARCHAR(50) NULL,
PRIMARY KEY (`msg_id`)
);