Retrieve varchar autogenerated primary key through triggers using JDBCTemplate - mysql

I am using MySQL Database and Spring JdbcTemplates to access the DB. I have a table called logs which has the following fields:-
`id` varchar(100) NOT NULL DEFAULT '11111111111111111',
`user_id` varchar(100) NOT NULL,
`service_id` int(11) NOT NULL,
`start_time` timestamp NOT NULL,
`creation_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`modification_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
I have a trigger on top of it:-
CREATE TRIGGER trigger_logs_insert BEFORE INSERT ON logs
FOR EACH ROW
SET NEW.creation_time = UTC_TIMESTAMP(), NEW.modification_time = UTC_TIMESTAMP(), NEW.id = (SELECT UUID());
I want the Spring jdbcTemplate code which retrieves the Id generated by the Trigger on the insert of a record.
I tried KeyHolder(GeneratedKeyHolder) but that is meant for numbers.
I want a code that can instantaneously retrieve the id.

Related

Is there a way to use a MySQL trigger to duplicate a record in a table, but modify the data before insert?

I am applying a series of triggers to a few tables in our database - these will serve the purpose of creating soft-delete/shadow records when certain relevant data is updated.
An example, consider this table:
CREATE TABLE `cms_content` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(40) NOT NULL,
`tag` varchar(20) NOT NULL,
`data` text NOT NULL,
`is_active` tinyint(1) unsigned NOT NULL DEFAULT '0',
`created_by` int(10) unsigned DEFAULT NULL,
`updated_by` int(10) unsigned DEFAULT NULL,
`created` datetime DEFAULT CURRENT_TIMESTAMP,
`modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT=' ';
Using this query
UPDATE cms_content SET `tag` = 'user-cities-field' WHERE id = 3;
When this query is executed, I want to essentially perform the following manipulations:
Set the INSERT id of the incoming record to NULL, so that AUTO_INCREMENT will set the next value accordingly.
Insert a copy of the record that was updated, with the only modification being that the is_active flag needs to get set to 1
I know that you cannot update the table from within here as MySQL will block it to prevent recursion.
If there is a way, can you essentially select the record being updated, prior to being updated, and then INSERT the modified record?
Would it be more useful to use a stored function to handle this?
What I need to do is to select the OLD record pre-update, and then change the value of the is_active flag on that record before it is inserted. The code I have been working with is below.
Trigger
CREATE DEFINER=`root`#`localhost` TRIGGER `cms_content_AFTER_UPDATE` BEFORE UPDATE ON `cms_content` FOR EACH ROW BEGIN
IF (NEW.is_active = 1) THEN
SET NEW.id = NULL;
INSERT INTO `tester`.`cms_content` (SELECT *, 0 as is_active from `cms_content` WHERE `id` = OLD.`id`);
#UPDATE `tester`.`cms_content` SET is_active = 0 WHERE `id` = OLD.`id`;
END IF;
END

Create trigger and stored procedure that updates Datetime when user is authenticated

I created a Login System in PHP and MySQL and I have the following table for the users:
CREATE TABLE `users` (
`ID` int(11) NOT NULL,
`Authenticated` tinyint(1) NOT NULL DEFAULT 0,
`Name` varchar(20) NOT NULL,
`Surname` varchar(20) NOT NULL,
`Username` varchar(20) NOT NULL,
`Email` varchar(255) NOT NULL,
`Password` varchar(70) NOT NULL,
`Created_At` datetime DEFAULT current_timestamp(),
`Authenticated_At` datetime DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
When the user signs up, a user is inserted in the table users with Authenticated = 0. I, as the admin, have to authenticate the user using:
UPDATE users SET Authenticated = 1 WHERE ID = {$id};
What I'd like to know is how to create a trigger and a stored procedure that updates the Authenticated_At column to the current Date and Time after the aforementioned UPDATE query.
Thanks in advance.
1) The simplest possible solution :
UPDATE users SET Authenticated = 1, Authenticated_At = NOW() WHERE ID = {$id};
2) Another solution is to set a DEFAULT value for the timestamp value. This is implemented in the table definition, like :
CREATE TABLE `users` (
`ID` int(11) NOT NULL,
`Authenticated` tinyint(1) NOT NULL DEFAULT 0,
`Name` varchar(20) NOT NULL,
`Surname` varchar(20) NOT NULL,
`Username` varchar(20) NOT NULL,
`Email` varchar(255) NOT NULL,
`Password` varchar(70) NOT NULL,
`Created_At` datetime DEFAULT current_timestamp(),
`Authenticated_At` datetime DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
From the documentation :
An auto-updated column is automatically updated to the current timestamp when the value of any other column in the row is changed from its current value. An auto-updated column remains unchanged if all other columns are set to their current values. To prevent an auto-updated column from updating when other columns change, explicitly set it to its current value. To update an auto-updated column even when other columns do not change, explicitly set it to the value it should have (for example, set it to CURRENT_TIMESTAMP).
In order for the Authenticated_At timestamp to be automatically updated every time the record is updated (while not updating Created_At), you want :
UPDATE users SET Authenticated = 1, Created_At = Created_At WHERE ID = {$id};
3) As wisely commented by #Raymond Nijland, the best solution is to define the timestamp column to be autoupdated only on UPDATE operations, like :
`Authenticated_At` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

Mysql Insert with milisecond

We're building chat system for our project. When user create chat group or send message to a group, we have to take user event time with milisecond. The sample database is below.
CREATE TABLE `chats` (
`id` int(11) NOT NULL,
`chat_id` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`status` float NOT NULL DEFAULT '1',
`chat_user` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`user_type` varchar(11) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'users',
`last_seen` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`delete_date` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`update_date` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`create_date` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
The problem is, when we insert new data into table, mysql takes current time as "0000-00-00 00:00:00.000". All zero, not even date. But if we edit that data after insert, current_timestamp works perfect.
From the MySQL documentation:
When inserting a new row, the default value for a column with an expression default can be inserted either by omitting the column name or by specifying the column as DEFAULT (just as for columns with literal defaults):
So, your options here for getting the default value to kick in are either doing an insert which does not mention the column at all, or using the placeholder DEFAULT. Both of the following should generate the same result:
INSERT INTO chats (id, chat_id, status, chat_user, user_type, last_seen, delete_date,
update_date, create_date)
VALUES
(1, 1, 1.0, 'tim', 'admin', DEFAULT, DEFAULT, DEFAULT, DEFAULT);
and
INSERT INTO chats (id, chat_id, status, chat_user, user_type)
VALUES
(1, 1, 1.0, 'tim', 'admin');
$timestamp=round(microtime(true) * 1000);
store $timestamp variable value in your database column. This is utc based timestamp and you can easily convert it into local time as well.

How to set a default constant value for timestamp columns?

I have a table with a nullable timestamp field (enddate)
CREATE TABLE `fee` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(50) NOT NULL DEFAULT 'FIXED',
`name` varchar(100) NOT NULL,
`description` varchar(255) DEFAULT NULL,
`startdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`enddate` datetime NOT NULL DEFAULT '2038-01-18 22:00:00',
PRIMARY KEY (`id`),
) ENGINE=InnoDB;
I run an insert, passing a null to startdate and enddate, expecting that it would use my default values. So running:
INSERT INTO `fee` (`type`, `name`, `description`, `startdate`, `enddate`)
VALUES
('FIXED', 'Delivery fee', NULL, NULL, NULL);
Would insert:
27, FIXED, Delivery fee, NULL, NOW(), '2038-01-18 22:00:00'
But it inserts:
27, FIXED, Delivery fee, NULL, NOW(), NOW()
I tried this in mysql 5.5, 5.6 and 5.7, based on their documentation:
Use of DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP is specific to TIMESTAMP. The DEFAULT clause also can be used to specify a constant (nonautomatic) default value; for example, DEFAULT 0 or DEFAULT '2000-01-01 00:00:00'.
Question is, what am I doing wrong?
When you set default value for any field in table, you only should pass the value when you actually wants to insert something else rather then default value. You were setting it to null with your query but IN your CREATE query
`enddate` datetime NOT NULL DEFAULT '2038-01-18 22:00:00'
you have set it as it should be 'NOT NULL'.

Create trigger to update column value when update or insert happens in the table

I am new to writing mysql triggers.
here is the create sql statement
CREATE TABLE BRAND_PROFILE_MAPPING (
PROFILE_MAPPING_ID BIGINT(20) NOT NULL AUTO_INCREMENT,
DOTLOOP_PROFILE_ID BIGINT(20) NULL DEFAULT NULL,
BRAND_PROFILE_ID VARCHAR(255) NULL DEFAULT NULL,
PROFILE_TYPE VARCHAR(90) NULL DEFAULT NULL,
PROFILE_NAME VARCHAR(225) NULL DEFAULT NULL,
SOURCE VARCHAR(255) NULL DEFAULT NULL,
PROFILE_HASH VARCHAR(32) NULL DEFAULT NULL,
ENTERED_DATE DATETIME NULL DEFAULT NULL,
CHANGED_DATE DATETIME NULL DEFAULT NULL,
PRIMARY KEY (PROFILE_MAPPING_ID)
);
i created table based on above structure.here i have 2 fields ENTERED_DATE DATETIME
CHANGED_DATE DATETIME , date columns i want to write trigger if any insert operation both date fields should be inserted if there is any update operation,changed date field should be updated.
Appreciate your help.Thanks in advance!!.
Remove profile_mapping_id from list of values as it is auto incremental.
CREATE TRIGGER `brand_profile_mapping_trigger` AFTER INSERT ON brand_profile_mapping FOR EACH ROW
BEGIN insert into **brand_profile_mapping_log** values(NEW.dotloop_profile_id,NEW.brand_profile_id,NEW.profile_type,NEW.profile_name,NEW.source,NEW.profile_hash);
END
If you want both columns to be populated by triggers you can do it in the following way
CREATE TRIGGER brand_profile_mapping_before_insert_trigger
BEFORE INSERT ON brand_profile_mapping -- you have to use BEFORE event
FOR EACH ROW
SET NEW.entered_date = CURRENT_DATE,
NEW.changed_date = CURRENT_DATE;
CREATE TRIGGER brand_profile_mapping_before_update_trigger
BEFORE UPDATE ON brand_profile_mapping -- you have to use BEFORE event
FOR EACH ROW
SET NEW.entered_date = OLD.entered_date, -- preserve the original value, so it can't be overridden
NEW.changed_date = CURRENT_DATE;
Here is a SQLFiddle demo