I'd like to have a tricky SQL statement as an Event that runs every couple of minutes.
Currently, I'm doing so with Java, using 3 separate statements that executing sequentiality in a transaction connection.
Q: I don't know how to construct such an SQL statement without Java. If impossible to have a single SQL statement, I'd like to use transaction (as I'm using in Java) and rollback in case of failure in any of those separate statements.
My Case:
I have 3 tables: "Factory", "Plan", "Machine".
I want to do something as below:
1.
WHERE Machines.annualCheck == "TRUE"
SET Machine.status = "IN_ANNUAL_CHECK"
For machines that got updated I need to do the following:
2.1 Update the related factory
WHERE Factory.id == Machine.linkFactoryID
UPDATE Factory.totalActiveMachines = --1
2.2 Delete the upcoming plans that planned to be handled by the related machine
DELETE rows WHERE Plan.willHandleByMachineID = Machine.ID
p.s. I'm using MySQL
Thank you!
Update:
In following to Simonare suggestion, I tired to do the following:
DELIMITER $
CREATE PROCEDURE annualCheck(IN Machine_ID int, IN Factory_ID int)
BEGIN
UPDATE machine_table
SET machine_table.annualCheck = 'IN_ANNUAL_CHECK'
WHERE machine_table.machine_id = Machine_ID;
UPDATE factory_table
SET factory_table.totalActiveMachines = factory_table.totalActiveMachines - 1
WHERE factory_table.factory_id = Factory_ID;
DELETE FROM plan_table WHERE plan_table.assign_to_machine = Machine_ID
END$
DELIMITER $$
BEGIN
SELECT #m_id = machine_id, #f_id = link_factory_id
FROM machine_table
WHERE machine_table.annualCheck = 'TRUE';
END$$
CALL annualCheck(#m_id,#f_id)
I don't know why, but I'm running into syntax errors - one after the other.
It's my first time to use PROCEDURE and DELIMITER. Am I doing it right?
you can use stored procedure
delimiter //
CREATE PROCEDURE myProc (IN Machine_ID int)
BEGIN
UPDATE myTable
SET Machine.status = "IN_ANNUAL_CHECK"
WHERE Machines.annualCheck == "TRUE";
Update the related factory
WHERE Factory.id == Machine.linkFactoryID
UPDATE Factory.totalActiveMachines = totalActiveMachines -1;
DELETE FROM Plan WHERE Plan.willHandleByMachineID = Machine_ID;
END//
then you can execute it either from mysql
CALL simpleproc(#a);
or from Java
It is also possible to create trigger on the Machine table, something like this:
CREATE TRIGGER `TRG_Machines_AfterUpdate` AFTER UPDATE ON `Machine` FOR EACH ROW BEGIN
IF OLD.annualCheck = 'TRUE' AND NEW.annualCheck = 'IN_ANNUAL_CHECK' THEN
UPDATE
Factory
SET
totalActiveMachines = totalActiveMachines - 1
WHERE
id = NEW.linkFactoryID
;
DELETE FROM
Plan
WHERE
willHandleByMachineID = NEW.ID
;
END;
END
So you can just issue normal update:
UPDATE Machine SET annualCheck = 'IN_ANNUAL_CHECK' WHERE annualCheck = 'TRUE'
Related
I am programming MYSQL and I use Python on Raspberry PI 4.
I need to drop table when all the values in my status_s column are equal to "DONE". I cannot figure out how to drop table under a certain condition. MYSQL tables can be found here for testing:
https://www.db-fiddle.com/f/siZmmKWLjRDdpYX6deEPYF/1
Initially, the status_s values are not "DONE". As my program runs, the values update and eventually all of them will be "DONE", at that point, I do not want to have this table anymore as it is not important.
Thanks in advance
UPDATE Adding snippet of Python program
def update_data_when_complete(conn,table_name):
cur = conn.cursor()
sql = "SELECT COUNT(DISTINCT(ID)) = SUM(Status = 'DONE') FROM {table}"
cur.execute(sql.format(table=table_name))
complete_result = cur.fetchone()
conn.commit()
#print("COmplete result = ",complete_result[0])
# if complete_result[0] is 1 here, all rows are "DONE" and must delete table after few minutes
if(complete_result[0] == 1):
sql = "DROP TABLE {table}"
cur.execute(sql.format(table=table_name))
conn.commit()
else:
print("Table not fully complete yet")
Use Event Scheduler.
Create event procedure:
CREATE EVENT remove_temptable
ON SCHEDULE
EVERY 1 MINUTE
COMMENT 'Remove `temptable` when its `status_s` column is equal to "DONE" in all rows.'
DO
BEGIN
IF EXISTS ( SELECT NULL
FROM INFORMATOIN_SCHEMA.TABLES
WHERE TABLE_SCHEMA = 'my_database'
AND TABLE_NAME = 'temptable' ) THEN
IF !( SELECT SUM(status_s != 'DONE')
FROM my_database.temptable ) THEN
DROP TABLE my_database.temptable;
END iF;
END IF;
END;
This procedure will check the table temptable for its existence firstly. If it exists then the procedure checks does a row with non-NULL value in status_s column other than 'DONE' exists. If not then the procedure drops the table.
The procedure is executed each minute. You may adjust how often it is executed. Also, when it is created, you may enable or disable it using ALTER EVENT (for example you may enable it after temptable creation and disable after you ensure the table is dropped).
Do not forget to enable Event Scheduler.
I have to create a trigger in a table proyect, to check if all the tests for the proyect are 'ready'. If all of them are ready, I need to search the proyect and put the status of the proyect as 'ready'. If not, Incomplete.
I'm aware that I need to create one trigger for the UPDATE, and another one for the INSERT. I've planned something like this, But I can not make it work.
I created this solution, if the total number of test for that proyect, is below to the number of test ready for that proyect, then the proyect is not ready. and if both are equals, the proyect is ready.
I don't know why it doesn't work:
CREATE TRIGGER update-proyect
AFTER INSERT ON tests
FOR EACH ROW
SET #total = select COUNT(*)
from tests
where IdProyect= NEW.IdProyect;
SET #ready = select COUNT(*)
from prueba
from tests
where IdProyect= NEW.IdProyect
AND status = 'ready';
IF (#total == #ready)
UPDATE proyect SET status = 'Ready' WHERE IdProyect = NEW.IdProyect;
ELSE
UPDATE proyect SET status = 'Incomplete' WHERE IdProyect = NEW.IdProyect;
END IF;
Loads of errors update-proyect is an invalid trigger name change to update_proyect, If you have more than 1 statement in a trigger they have to be encased in a begin and end statements, a select after a set has to be encased in braces, there is no == comparison relation operator in mysql either use = or null safe equals <=>, an if statement has to have a then statement.
This at least syntaxes.
DROP TRIGGER IF EXISTS update_proyect;
DELIMITER $$
CREATE TRIGGER update_proyect
AFTER INSERT ON tests
FOR EACH ROW
BEGIN
SET #total = (select COUNT(*)
from tests
where IdProyect= NEW.IdProyect
);
SET #ready = (select COUNT(*)
from prueba
#from tests
where IdProyect= NEW.IdProyect
AND status = 'ready'
);
IF (#total = #ready) THEN
UPDATE proyect SET status = 'Ready' WHERE IdProyect = NEW.IdProyect;
ELSE
UPDATE proyect SET status = 'Incomplete' WHERE IdProyect = NEW.IdProyect;
END IF;
END $$
DELIMITER ;
I have a MySQL database in which I have the following rows (by exemple) created by default (id, task and case may be different but the current value is always 1)
....idtaskcaseuser............datecurrent
238......31001.....0..............null..........1
239......41001.....0..............null..........1
I have to randomly create rows like this with insert statement (new rows). As you can see a date is filled and de current equal 0
....idtaskcaseuser............datecurrent
240......51001.....12015.04.03..........0
241......21002.....12015.04.03..........0
When I come across one of the lines created by default I want to use an update instead of an insert statement.
So I created the following procedure in MySQL
DELIMITER //
DROP PROCEDURE IF EXISTS FillProgress//
CREATE PROCEDURE FillProgress ( get_case INT(10),get_task INT(10), get_user INT(10) )
BEGIN
DECLARE test tinyint(1);
SET test = (SELECT COUNT(*) FROM progress WHERE case_id = get_case AND task_id = get_task);
IF test = 1 THEN
UPDATE progress SET current = 0, date = NOW(), user_id = get_user WHERE task_id = get_id AND case_id = get_case;
ELSE
INSERT INTO progress(task_id,case_id,user_id,date,current) VALUES (get_task,get_case,get_user,NOW(),0);
END IF;
END; //
DELIMITER ;
I use count to see if a already have a row with the same case and task. If it's true (test=1) I use UPDATE, otherwise and use INSERT.
If I test with the following row already wrote in the database
....idtaskcaseuserdatecurrent
241......41001.....0..null..........1
I use CALL FillProgress(1001,4,1);
The row is not updated, but I do not have any error message.
11:38:02 CALL FillProgress(1001,4,1) 0 row(s) affected 0.000 sec
And if I manually use my update query
UPDATE progress SET current = 0, date = NOW(), user_id = 1 WHERE task_id = 4 AND case_id = 1001;
It works like a charm.
The insert query also works fine.
The UPDATE query within the procedure has a "WHERE task_id = get_id" clause, however I don't see get_id being defined in the procedure; there is a "get_task" parameter for the stored procedure, though.
Here is my PROCEDURE:
CREATE DEFINER=`root`#`localhost` PROCEDURE `user_active_account`(IN i_email VARCHAR(255),
IN i_active_code VARCHAR(255))
BEGIN
START TRANSACTION;
DELETE FROM activeCodes WHERE active_code = i_active_code;
UPDATE users SET status = 1 WHERE email = i_email;
COMMIT;
END
I got a problem here, I would like to execute DELETE FROM activeCodes WHERE active_code = i_active_code success, if this line cannot run success (For example, it can't delete any things), the UPDATE users SET status = 1 WHERE email = i_email can not be executed. How can I focus this behaviour? Thanks.
check mysql_affected_rows. if greater than 0, then there definitely has been a delete. Hope that helps
I'm converting some old legacy Interbase database to MySql and I am having some trouble converting triggers. This is what I came so far, but can't seem to understand what are the errors in the following triggers. Can you help fix the syntax?
DELIMITER ^
In these 2 cases it says into new.FinancialCode is incorrect. What is the correct form to accomplish this? (Lookup a value in a table and change it in the updated row)
Create Trigger triggerFinancialCode BEFORE UPDATE ON FLOW
FOR EACH ROW
begin
Select FinancialCode FROM Accounts where AccountCode = new.AccountCode
into new.FinancialCode ;
end ^
Create Trigger triggerFinancialCodePredicted BEFORE UPDATE ON PREDICTED_FLOW
FOR EACH ROW
begin
Select FinancialCode FROM Accounts where AccountCode = new.AccountCode
into new.FinancialCode ;
end ^
Try this code -
CREATE TRIGGER triggerFinancialCode BEFORE UPDATE ON FLOW
FOR EACH ROW
BEGIN
SET #var = NULL;
SELECT FinancialCode INTO #var FROM Accounts WHERE AccountCode = NEW.AccountCode;
SET NEW.FinancialCode = #var;
END
Do the same for second trigger.