MySQL Trigger Code to enter statement based on another value - mysql

EDIT **********
I couldn't get the below code to work so I have tried to run it in the diagram tool on Workbench. This is my code
CREATE DEFINER = CURRENT_USER TRIGGER `MeasureUp_Data`.`bmd_results_BEFORE_INSERT` BEFORE INSERT ON `bmd_l_arm` FOR EACH ROW
BEGIN
INSERT INTO bmd_results VALUES ( new.bmd_l_arm_typ
CASE new.l_arm_tscore
WHEN < -2.5 THEN 'osteoporosis'
WHEN > -2.4 < -1.0 THEN 'osteopenia'
WHEN > -1.0 THEN 'normal'
ELSE NULL
END);
END
Im getting red crosses all though the code. Basically the values will be automatically entered into data.bmd_l_arm and I want the field in data.bmd_results labelled bmd_l_arm_typ to have the text entry based on the numerical result pushed into l_arm_tscore
Thanks for you ongoing help!
I am very new to the coding game and have been creating a Db on MySQL to add some value to my company. I have created the DB schema and want to have a field in one of my table insert a value based on a entry which comes into another table. Basically this is for a medical reporting database and I would like the diagnosis to appear in text on in as a field entry.
This is the table which I would like the values to appear, more specially i would like the column (for example) bmd_sp_typ to inset a VARCHAR (I will specify the result) based on a numerical result in a different table.
CREATE TABLE IF NOT EXISTS `MeasureUp_Data`.`bmd_results` (
`access_no` INT NOT NULL,
`bmd_sp_typ` VARCHAR(45) NULL,
PRIMARY KEY (`access_no`),
INDEX `pat_id_FK_idx` (`pat_id` ASC),
INDEX `fk_site_bmd_site_idx` (`site_id` ASC),
UNIQUE INDEX `pat_id_UNIQUE` (`pat_id` ASC),
UNIQUE INDEX `site_id_UNIQUE` (`site_id` ASC),
UNIQUE INDEX `access_no_UNIQUE` (`access_no` ASC),
CONSTRAINT `fk_demo_results_id`
FOREIGN KEY (`pat_id`)
REFERENCES `MeasureUp_Data`.`patient_demo` (`pat_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_site_bmd_site`
FOREIGN KEY (`site_id`)
REFERENCES `MeasureUp_Data`.`site_cont` (`site_id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
The table where the numerical result will be found is below. Basically is the value for spine_total_bmd is X then Y will be inserted into bmd_sp_type, alternatively, if spine_total_bmd is A then B will be inserted.
CREATE TABLE IF NOT EXISTS `MeasureUp_Data`.`bmd_spine` (
`access_no` INT NOT NULL,
`spine_total_bmd` INT NULL,
`spine_total_tscore` INT NULL,
`spine_total_zscore` INT NULL,
`spine_total_peakref` INT NULL,
`spine_total_agemat` INT NULL,
PRIMARY KEY (`access_no`),
CONSTRAINT `fk_bmd_spine_access`
FOREIGN KEY (`access_no`)
REFERENCES `MeasureUp_Data`.`bmd_results` (`access_no`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
Any help for this coding noob will be greatly appreciated.

You can write an INSERT trigger -
CREATE TRIGGER trigger
BEFORE INSERT
ON bmd_spine
FOR EACH ROW
BEGIN
INSERT INTO bmd_results VALUES (
new.access_no,
CASE new.spine_total_bmd
WHEN 1 THEN 'y'
WHEN 2 THEN 'b'
ELSE NULL
END);
END
Also, you can just select data from the table and change values on the fly, and do not store duplicated values. Here it is an example -
SELECT
access_no,
CASE spine_total_bmd
WHEN 1 THEN 'y'
WHEN 2 THEN 'b'
ELSE NULL
END
FROM
bmd_spine;

Related

How to compare and use only time from datetime format in sql? My insertion is given in datetime format

Please note that this is not my full code for the query. I just need to understand how to compare the time only.
Here is my table creation code
CREATE TABLE IF NOT EXISTS `mydb`.`ActivityBooking` (
`ActivityTime` datetime NOT NULL,
`NumPeople` INT NULL,
`ActivityID` VARCHAR(45) NOT NULL,
`GuideID` VARCHAR(10) NOT NULL,
`Reservation_ReservationID` VARCHAR(10) NOT NULL,
PRIMARY KEY (`ActivityTime`, `ActivityID`),
INDEX `fk_ActivityBooking_Activity1_idx` (`ActivityID` ASC) VISIBLE,
INDEX `fk_ActivityBooking_Staff1_idx` (`GuideID` ASC) VISIBLE,
INDEX `fk_ActivityBooking_Reservation1_idx` (`Reservation_ReservationID` ASC) VISIBLE,
CONSTRAINT `fk_ActivityBooking_Activity1`
FOREIGN KEY (`ActivityID`)
REFERENCES `mydb`.`Activity` (`ActivityID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_ActivityBooking_Staff1`
FOREIGN KEY (`GuideID`)
REFERENCES `mydb`.`Staff` (`StaffID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_ActivityBooking_Reservation1`
FOREIGN KEY (`Reservation_ReservationID`)
REFERENCES `mydb`.`Reservation` (`ReservationID`)
ON DELETE NO ACTION
ON UPDATE NO ACTION);
Table insertion
Insert into activitybooking values('2020-10-7 15:17:00',6,'C01','S5','R321');
Insert into activitybooking values('2020-12-8 16:15:00',7,'D01','S2','R321');
Insert into activitybooking values('2020-11-9 18:12:00',2,'E01','R321','S4');
Currently I am stuck because I want to display results for bookings made after mid-day and before 4pm. But I don't know how to just compare the time from the datetime format. I am not adding the codes for the other tables in order to keep the information here minimum. But if needed I can provide.
select customerfname, customerlname, activityname
from customer, activitybooking,activity
where activity.activityid = activitybooking.activityid
and activitytime between time('12-0-0') and time('16-0-0');
What you need to do is apply the TIME function to your activitytime column and then compare it to 12:00:00 and 16:00:00:
TIME(activitytime) BETWEEN '12:00:00' AND '16:00:00'
Note if you don't want to include 16:00:00 replace that with 15:59:59. Also, if you write the time strings in HH:mm:ss format then you don't need to apply TIME to them and can just compare directly.

Why are INSERTS into my MySQL table taking so long

I am building a MySQL accounts database. I have a routine which imports the entire database from a json file. The routine runs inside a single transaction,
drops all the records from every table, calls:
ALTER TABLE <tablename> AUTO_INCREMENT = 1
on each table, then loads the tables from data using INSERT statements like
INSERT INTO Journal (idJournal, DocumentId, AccountId, Memo, JournalNum,
Amount, Outstanding, Cleared, NameAddressId)
VALUES (11423, 4454, 14, 'Deposit', 1, 53.33, 53.33, 'X', 292)
(Note that the tables are loaded in the right order, so the related records already exist).
I am finding the insert statements are taking a long time (some up to 70 msec), especially compared with loading the same data from a mysqldump.
Is there anything I can do to speed this up (other than using mysqldump instead, which I don't want to do because I want the backup data to be in json format)?
Table definition:
CREATE TABLE IF NOT EXISTS `accounts`.`Journal` (
`idJournal` INT NOT NULL AUTO_INCREMENT,
`DocumentId` INT NOT NULL,
`AccountId` INT NOT NULL,
`Memo` VARCHAR(45) NULL,
`JournalNum` INT NOT NULL,
`Amount` DECIMAL(10,2) NOT NULL,
`Outstanding` DECIMAL(10,2) NOT NULL DEFAULT 0,
`Cleared` CHAR(1) NOT NULL,
`NameAddressId` INT NULL,
PRIMARY KEY (`idJournal`),
INDEX `fk_Journal_Document1_idx` (`DocumentId` ASC),
INDEX `fk_Journal_Account1_idx` (`AccountId` ASC),
UNIQUE INDEX `Document_Num` (`DocumentId` ASC, `JournalNum` ASC),
INDEX `fk_Journal_NameAddress1_idx` (`NameAddressId` ASC),
CONSTRAINT `fk_Journal_Document1`
FOREIGN KEY (`DocumentId`)
REFERENCES `accounts`.`Document` (`idDocument`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Journal_Account1`
FOREIGN KEY (`AccountId`)
REFERENCES `accounts`.`Account` (`idAccount`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_Journal_NameAddress1`
FOREIGN KEY (`NameAddressId`)
REFERENCES `accounts`.`NameAddress` (`idNameAddress`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
When performing multiple inserts, it's more performant to insert multiple lines in a single statement, especially if you have a lot of secondary indexes:
INSERT INTO Journal (idJournal, DocumentId, AccountId, Memo, JournalNum,
Amount, Outstanding, Cleared, NameAddressId)
VALUES (11423, 4454, 14, 'Deposit', 1, 53.33, 53.33, 'X', 292),
(11424, 4455, 15, 'Deposit', 1, 23.33, 23.33, 'X', 293),
...
That way, the indexes are only updated once (at the end of the statement), rather than after each insert.
If your database grows beyond 1GB, you're going to have problems because you'll reach the limit of max_allowed_packet. In that case, you may have to break it up into multiple queries.
When you say "drops all the records", I hope you mean drop table or truncate table rather than actually deleting all the records.
This works with "no" interruption of usage of the table:
CREATE TABLE new LIKE real;
Load new by batched INSERTs (or whatever).
RENAME TABLE real TO old, new TO real; -- Instantaneous and atomic
DROP TABLE old;
No TRUNCATE, no AUTO_INCREMENT=1

Constraint on the same row

If there is possible insert of the same row in table I want to ignore this one. Here the table with foreign key game_id and 2 fields step_num and cell, they could differ and should differ. Cell should be 0-8 and always different for game_id. Step_num the same, but 1-9. But I can't set unique, because the could be the same, but in different game_id's.
Here is part of the script:
create table games(
id int not null auto_increment primary key,
name varchar(255) not null unique ,
status varchar(255) not null,
createDate DATETIME
);
create table steps(
game_id int not null ,
step_num int not null,
cell int not null,
constraint cell_unique on games(id),
constraint chk_number check(step_number > 0 and step_number < 10),
constraint fk_game foreign key (game_id) references games(id) on delete cascade,
constraint chk_cell check(cell >= 0 and cell <= 8)
);
INSERT IGNORE didn't worked adn INSERT ON DUPLICATE KEY I think not what I need. If I try Insert (2, 2, 2) several times, it should ignore. I prevent this actions on the back-end side, but want, that db was correct and automatically prevent from similar actions.
What are the ways to do it correctly?
You have 2 options:
Define composite primary key using ( game_id, step_num, cell ). This restricts repeated row data like 2, 2, 2.
Define a before insert trigger that checks duplicates and
to restrict, updates the same row with same values, affecting no rows.
And as per my knowledge check constraints have no effect in MySQL.

defining new trigger sql error

My goal in general is like that:
I have a a table with many translations - each translation have a rating - the average of all ratings from the user.
each translation have a unique Id, and in the second table I am saving for each user that ranked a translation the rating he\she gave (userId, translationId, rating)
now everytime a user rank a new translation or change his old rate I want to update the average rating of this translation
I have the following tables:
Create Table if not exists Translation
(TranslationID int (12) NOT NULL UNIQUE AUTO_INCREMENT,
UserID int (10) NOT NULL,
ImageID int (10) NOT NULL,
ChainID int (2) NOT NULL,
Translation text,
TranslationRating double Default 0 CHECK (TranslationRating>=0 AND TranslationRating<=5),
NumOfRatings int (10) Default 0,
CONSTRAINT translations PRIMARY KEY (UserID,ImageID, ChainID),
FOREIGN KEY (UserID) REFERENCES Users(UserID) ON DELETE CASCADE,
FOREIGN KEY (ImageID) REFERENCES Images(ImageID) ON DELETE CASCADE)
Create Table if not exists TranslationsRating
(UserID int (10) NOT NULL ,
TranslationID int (3) NOT NULL,
Rating double Default 0 CHECK (TranslationRating>=0 AND TranslationRating<=5),
CONSTRAINT known_lang PRIMARY KEY (UserID,TranslationID),
FOREIGN KEY (UserID) REFERENCES Users(UserID) ON DELETE CASCADE,
FOREIGN KEY (TranslationID) REFERENCES Translation(TranslationID) ON DELETE CASCAD
this means that everytime a new row is inserted into 'TranslationsRating' or I update the rating column in this table I want to take the translationId of the row that was just changed and in the 'translation' table update this translationId rating (find all rating for this Id in 'TranslationsRating' and calc the average)
I'm trying to define the following trigger:
CREATE TRIGGER UPDATE_TRANS_RATING
AFTER UPDATE ON TRANSLATIONSRATING
FOR EACH ROW
BEGIN
UPDATE TRANSLATION SET TRANSLATIONRATING = (SELECT AVG(RATING) FROM TRANSLATIONSRATING
WHERE TRANSLATIONSRATING.TRANSLATIONID = RATINGNEW.ID)
END;
and I'm getting the following error message (I'm using phpMyAdmin):
MySQL said: #1303 - Can't create a TRIGGER from within another stored routine
my question is what is this error, and if my trigger is written in a good way that will achive my goal

sql: change primary key to another list of unique elements

i want to change the ids of a table to some other unique value.
This is a simplified example:
CREATE TABLE IF NOT EXISTS test (
id int(11) NOT NULL,
reverse_id int(11) NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY reverse_id (reverse_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO test (id, reverse_id) VALUES ('1', '2'), ('2', '1');
UPDATE test SET id = reverse_id;
# Duplicate entry '2' for key 'PRIMARY'
I am looking for a command that checks only at the end of the UPDATE for the uniqueness of the id elements.
[I know that I can create a second row and change the status of this row to primary, then i can update the ids and reset the primary status, but i want to have one command, without adding or changing other rows, tables]
This is not possible with MySQL as far as I know.
It neither evaluates constraint on statement level (it does that on row level while processing) nor does it allow you to define them to be deferred (so the constraint would be evaluated at commit time).
The only option I can see if you want to "renumber" your primary key: drop the primary key, renumber the ids then re-create the primary key.
What if you create the table having reverse_id as its primary key? - that is unique in your definition so it is a valid candidate for primary key.
Primary keys are unique by definition - this constraint is stopping you from achieving what you want