MySQL storing TIMESTAMP with milliseconds - mysql

I need to create a database to store some logs which can occurs once per millisecond.
I've created the following table:
CREATE TABLE `log` (
`DataEvento` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`CodiceEvento` int(11) NOT NULL,
`IdApplicativo` int(11) NOT NULL,
PRIMARY KEY (`DataEvento`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
And a stored procedure:
CREATE DEFINER=`root`#`localhost` PROCEDURE `ScriviEvento`(IN evt_id INT, IN app_id INT, IN evt_descr TEXT)
BEGIN
DECLARE timestamp_now TIMESTAMP(3) DEFAULT NOW(3);
INSERT INTO log (DataEvento, CodiceEvento, IdApplicativo) VALUES (timestamp_now, evt_id, app_id);
IF (LENGTH(evt_descr) > 0) THEN
INSERT INTO descrizionelog (DataEvento, DescrizioneEvento) VALUES (timestamp_now, evt_descr);
END IF;
END
Inserting manually some entries I get the correct timestamp with milliseconds but if I create a thread
with a Sleep(1) I got duplicate key error, same happens if I press execute button fast in workbench with
CALL(1, 0, '');
Is there a workaround to this (excluding using an auto-increment id), or am I doing something wrong?

You are doing something wrong by assuming that the timestamp is going to be unique for log records. That really doesn't make sense.
I'm not sure why you are opposed to an auto-increment solution. This would be the right approach:
CREATE TABLE `log` (
LogId int auto_increment primary key,
`DataEvento` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
`CodiceEvento` int NOT NULL,
`IdApplicativo` int NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;

Related

Specific field parameter when creating a table MySQL

I'm using MySQL Workbench.
I would like to create a table named courseInfo and I want to put a column named moduleCode in it, but I want it to always be similar in format: CFSM H0000 where the four zeros are a number that increases starting with 0000.
For example:
CFSM H0001
CFSM H0002
[..]
You cannot auto-increment character type columns in MySQL, as auto-increment is only possible on integer type columns. One (alphanumeric) auto-incrementing moduleCode column would therefore not be possible. However, you could try splitting up the moduleCode into two columns, for example like so:
CREATE TABLE `courseInfo` (
`prefix` CHAR(6) NOT NULL DEFAULT 'CFSM H',
`id` SMALLINT(4) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
KEY (`id`)
) AUTO_INCREMENT = 0;
Where prefix could for example be "CFSM H" and id could be 0001
Then, upon executing SELECT statements, you could merge the prefix column with the id column into a moduleCode column with CONCAT, e.g.:
SELECT CONCAT(`prefix`, `id`) as `moduleCode` FROM `courseInfo`;
An alternative approach (from MySQL version 5.7 and up) seems to be the use of a generated column, for example:
CREATE TABLE `courseInfo` (
`prefix` CHAR(6) NOT NULL DEFAULT 'CFSM H',
`id` SMALLINT(4) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
`moduleCode` CHAR(10) AS (CONCAT(`prefix`, `id`)),
KEY (`id`)
) AUTO_INCREMENT = 0;
However, the above example of a generated column would not work, because moduleCode is dependent on an auto-increment column, and the auto-increment is not executed yet at the time the generated column is computed. See also: https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html. It would throw an ER_GENERATED_COLUMN_REF_AUTO_INC error.
You could therefore use the first solution, or try to add moduleCode as a column and use an AFTER INSERT trigger to update its value:
CREATE TABLE `courseInfo` (
`prefix` CHAR(6) NOT NULL DEFAULT 'CFSM H',
`id` SMALLINT(4) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT,
`moduleCode` CHAR(10),
KEY (`id`),
UNIQUE KEY `unique_index` (`prefix`,`id`)
) AUTO_INCREMENT = 0;
DELIMITER //
CREATE TRIGGER `addModuleCode` AFTER INSERT ON `courseInfo`
FOR EACH ROW
BEGIN
UPDATE `courseInfo` SET `moduleCode` = CONCAT(NEW.`prefix`, NEW.`id`) WHERE `prefix` = NEW.`prefix` AND `id` = NEW.`id`;
END;//
DELIMITER ;

How do you check if a row exists within a stored procedure if-block in Oracle MySQL

I currently build a database and write stored procedures for an Android app. I am long time programmer and created some databases years ago, but did not really work with stored procedures until now. The problem that I have at the moment is that I find no right way to check if a given string (specified by stringId) and a given language (specified by languageId) does not exist, and if a translated string already exists before I go on and insert a new translated string into the table TranslatedStrings. I looked up many similar questions and lots of other websites and although some seem to have had the exact same problem their solution did work for them but not for me.
Here is my current Create Procedure script:
create procedure `InsertTranslatedString`(in stringId int(10) unsigned, in translationSource tinyint(3) unsigned, in translationLanguageId int(10) unsigned,
in translatedString mediumtext, out insertedTranslatedStringId int(10) unsigned, out returnValue int(10))
reads sql data
modifies sql data
begin
-- if the string id does not exists
if (select count(1) from `Strings` where `stringId` = stringId) = 0
then
-- return error code
set returnValue = -1;
set insertedTranslatedStringId = 0;
-- if the language id does not exists
elseif (select count(1) from `Languages` where `languageId` = translationLanguageId) = 0
then
-- return error code
set returnValue = -2;
set insertedTranslatedStringId = 0;
-- if the translated string already exists
elseif (select count(1) from `TranslatedStrings` where `stringId` = stringId and `languageId` = translationLanguageId) > 0
then
-- return error code
set returnValue = -3;
set insertedTranslatedStringId = 0;
-- if we are ready to go
else
-- insert the actual translated string
insert into TranslatedStrings (`stringId`, `languageId`, `value`, `translationSource`, `createdDateTime`)
values (stringId, translationLanguageId, translatedString, translationSource, now());
select #newTranslatedStringId := last_insert_id();
-- give back output parameters
set insertedTranslatedStringId = #newTranslatedStringId;
set returnValue = 0;
end if;
end $$
The creation of the procedure works like charm.
I call the procedure with call InsertTranslatedString(76, 0, 1, 'German (Germany)', #insertedTranslatedStringId, #returnValue); Both stringId 76 and languageId 1 do not exist.
When I make this call I notice that the if-elseif-elseif-else block skips the first if (stringId check) even though it should enter its then block. The procedure however enters the first elseif (languageId check) which works fine.
I also tried out if-checks like these: if not exists (select 1 from 'Strings' where 'stringId' = stringId) but there the exists() function seemed to always return true not matter if the select returned a row or no row; the procedure would then skip right through to the second elseif just because I used a elseif exists (select... there. The actual select however does not return any row if I run it separately. Very confusing.
Here are the three referenced tables:
CREATE TABLE `Languages` (
`languageId` int(10) unsigned NOT NULL,
`nameStringId` int(10) unsigned NOT NULL,
`languageCode` varchar(5) DEFAULT NULL,
`hiddenInSettings` tinyint(1) DEFAULT '0',
PRIMARY KEY (`languageId`),
KEY `FK_Languages_nameStringId` (`nameStringId`),
CONSTRAINT `FK_Languages_nameStringId` FOREIGN KEY (`nameStringId`) REFERENCES `Strings` (`stringId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contains all supported and automatically translated languages'
CREATE TABLE `Strings` (
`stringId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`originalValue` mediumtext NOT NULL,
`originalLanguageId` int(10) unsigned NOT NULL,
PRIMARY KEY (`stringId`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='contains all language-independent strings instances'
CREATE TABLE `TranslatedStrings` (
`stringId` int(10) unsigned NOT NULL,
`languageId` int(10) unsigned NOT NULL,
`value` mediumtext NOT NULL,
`translationSource` tinyint(3) unsigned DEFAULT '0',
`createdDateTime` datetime DEFAULT NULL,
`lastModifiedDateTime` datetime DEFAULT NULL,
`incorrectTranslationState` tinyint(3) unsigned DEFAULT '0',
`incorrectTranslationReporterId` int(10) unsigned DEFAULT NULL,
`incorrectTranslationReportedDateTime` datetime DEFAULT NULL,
PRIMARY KEY (`stringId`,`languageId`),
KEY `FK_TranslatedStrings_languageId` (`languageId`),
KEY `FK_TranslatedStrings_incorrectTranslationReporterId` (`incorrectTranslationReporterId`),
CONSTRAINT `FK_TranslatedStrings_incorrectTranslationReporterId` FOREIGN KEY (`incorrectTranslationReporterId`) REFERENCES `Users` (`userId`) ON DELETE CASCADE,
CONSTRAINT `FK_TranslatedStrings_languageId` FOREIGN KEY (`languageId`) REFERENCES `Languages` (`languageId`) ON DELETE CASCADE,
CONSTRAINT `FK_TranslatedStrings_stringId` FOREIGN KEY (`stringId`) REFERENCES `Strings` (`stringId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='contains all localized and automatically translated strings'
When I created the tables I did not create these KEY entries by the way, they were created by MySQL Server. Odd that they only resemble some of the CONSTRAINT entries and not all.
Since Strings only has a single-column primary key and no foreign keys I'm puzzled that its corresponding if-statement isn't triggered. What I am doing wrong?

How to calculate time difference automatically in MySQL?

I have a database table. The creation query is listed as below.
CREATE TABLE `prime_clock` (
`stage` int(11) NOT NULL,
`name` varchar(50) DEFAULT NULL,
`start_time` time NOT NULL,
`end_time` time NOT NULL,
`difference` time NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Consider I have a sample entry as
INSERT INTO `prime_clock` (`stage`, `name`, `start_time`, `end_time`, `difference`) VALUES
(1, 'fff', '12:33:00', '13:00:00', '00:00:00');
For primary key I used
ALTER TABLE `prime_clock`
ADD PRIMARY KEY (`stage`);
Now the question is How do I find duration between the start and end time; I.e. end_time - start_time and store in difference automatically as add a new row or make a modification in start time or end time.
Also, I can do it manually using
UPDATE `prime_clock` SET `difference`=TIMEDIFF(`end_time`,`start_time`) WHERE 1
You could go ahead with one of the following approaches:
Generated columns (explained here): You can define the table as follows:
CREATE TABLE prime_clock (
stage int(11) NOT NULL,
name varchar(50) DEFAULT NULL,
start_time time NOT NULL,
end_time time NOT NULL,
difference time AS TIMEDIFF(end_time, start_time) STORED
ENGINE=InnoDB DEFAULT CHARSET=latin1;
Trigger: You can write a BEFORE INSERT trigger that calculates difference for every inserted row, e.g.:
DELIMITER //
CREATE TRIGGER calculate_difference
BEFORE INSERT
ON table FOR EACH ROW
BEGIN
SET NEW.difference = TIMEDIFF(end_time, start_time);
END; //
DELIMITER ;

Why does MySQL return 1175 code after calling UPDATE procedure WITH where clause which uses primary key?

I know that I can unchecked the 'safe update' mode but I want to understand why MySQL server returns this error even when all things look like correct?
I'm trying to call update procedure to update row in table country with statement
call sellcontroller.country_update(1, 'United Kingdom', 'GB', 'GBR', 'GBR');
but it throws an exception "Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column."
I'm definitely sure that I'm using a WHERE clause with table primary key and correct data type. And even more the same update statement used outside from procedure works correctly.
Code of the procedure is
CREATE PROCEDURE `country_update` (
in idCountry int(6),
in nameCountry varchar(255),
in codeISO2 varchar(2),
in codeISO3 varchar(3),
in codeCitizen varchar(5))
BEGIN
UPDATE `sellcontroller`.`country`
SET
`nameCountry` = nameCountry,
`codeISO2` = codeISO2,
`codeISO3` = codeISO3,
`codeCitizen` = codeCitizen
WHERE `idCountry` = idCountry;
END
The table creation statement for now is
CREATE TABLE `country` (
`idCountry` int(6) NOT NULL AUTO_INCREMENT,
`nameCountry` varchar(255) DEFAULT NULL,
`codeISO2` varchar(2) DEFAULT NULL,
`codeISO3` varchar(3) DEFAULT NULL',
`codeCitizen` varchar(5) DEFAULT NULL,
PRIMARY KEY (`idCountry`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

mysql how to update a foreign key automatically

this is my tables
CREATE TABLE IF NOT EXISTS `carslibrary` (
`CarID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`CarName` varchar(255) NOT NULL,
PRIMARY KEY (`CarID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=4 ;
CREATE TABLE IF NOT EXISTS `colorslibrary` (
`ColorID` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ColorName` varchar(255) NOT NULL,
PRIMARY KEY (`ColorID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;
CREATE TABLE IF NOT EXISTS `facerecord` (
`carslibrary_ID` int(10) unsigned NOT NULL,
`colorslibrary_ID` int(11) unsigned NOT NULL,
KEY `carslibrary_ID` (`carslibrary_ID`),
KEY `colorslibrary_ID` (`colorslibrary_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
i noticed carslibrary_ID attribute inside facerecord table is not automatically updated when i add a car record inside carslibrary table, what should i do to be able to?
Firstly, you'll need to have a default value specified for the facerecord.colorslibrary_ID since you will not 'know' what it is when inserting into the carslibrary table. That said you could alter your DDL for the facerecord table to be:
CREATE TABLE `facerecord` (
`carslibrary_ID` int(10) unsigned NOT NULL,
`colorslibrary_ID` int(10) unsigned NOT NULL DEFAULT '0',
KEY `carslibrary_ID` (`carslibrary_ID`),
KEY `colorslibrary_ID` (`colorslibrary_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I've also changed the datatype of the colorslibrary_ID column to match that of the colorslibrary.ColorID column in case you ever feel like setting up a foreign key between facerecord.colorslibrary_ID and colorslibrary.ColorID ;). For the sake of completeness you should insert a row into the colorslibrary table with a ColorID = 0. Hence:
insert into `colorslibrary` (ColorName) values ('unknown color');
update `colorslibrary` set ColorID = 0 where ColorName = 'unknown color';
Then you can go ahead and define your trigger to insert into the facerecord table:
delimiter $$
CREATE TRIGGER carslibrary_trigger
AFTER insert ON carslibrary
FOR EACH ROW
BEGIN
insert into facerecord (carslibrary_ID) values (new.CarID);
END$$
delimiter;
All new rows inserted into the facerecord table will then be inserted with a colorslibrary_ID that relates to the 'unknown color' colorslibrary.ColorName.You can then manually update the facerecord.colorslibrary_ID as and when you know it.
Good luck!
PS If you need to remove any existing AFTER insert triggers from the carslibrary table you can do so by firstly finding the existing triggers:
select trigger_name
from information_schema.triggers
where event_object_table = 'carslibrary'
and action_timing = 'AFTER'
and event_manipulation= 'INSERT';
Then take the name of the trigger returned by the above statement (lets say the string 'carslibrary_trigger' is returned) and run:
drop trigger carslibrary_trigger;
Then re-run the CREATE TRIGGER script.
Once a trigger is set up it will automatically perform the action you have specified when the trigger action you have specified occurs. In this case we are telling the database "after an insert happens into the carslibrary table automatically insert a row into the facerecord table using the CarID of the new carslibrary row to populate the facerecord.carslibrary_ID column". As with most things the best way is to try it! Once you have created the trigger manually insert a new row into the 'carslibrarytable. Now look at the data in thefacerecord` table - you should see a new row that has been inserted by the trigger firing.
It sounds like you would benefit from learning about triggers. I recommend the docs on the MySQL site because this answer is way longer than I first intended it to be!
You will need to use triggers. See http://dev.mysql.com/doc/refman/5.0/en/triggers.html