MySQL Version: '5.7.37-0ubuntu0.18.04.1'
I have the goals of
Updating rows in table ost_ticket after one week of no new activity
Update or Insert into table ost_ticket__cdata one row for each row updated in ost_ticket
I will be using MySQL Event Scheduler to call the code that will accomplish the above two goals on an hourly basis.
My tendency is to put the code in a stored procedure, which is then called by the event scheduler.
My challenge is that I'm not sure how to transition from goal 1 to goal 2. How can I Update / insert into the child table for only those rows affected on the parent table, and only as a result of the event scheduler job (in other words, I don't want to use a trigger any time the parent table is updated, only when the "one-week-old" condition is satisfied)
Draft of the stored procedure with my rambling commentary is below...
USE `osticket`;
DROP procedure IF EXISTS `AutoClose';
DELIMITER //
Create Procedure AutoClose ()
Begin
# GOAL 1: UPDATE ROWS THAT ARE ONE WEEK OLD...
UPDATE ost_ticket t
SET
t.status_id = 3, # 3 = "Closed"
t.closed = date_add(t.lastupdate, interval 7 day),
t.updated = date_add(t.lastupdate, interval 7 day)
t.lastupdate = date_add(t.lastupdate, interval 7 day),
WHERE t.status_id = 2 # 2 = "Resolved"
AND now() >= date_add(t.lastupdate, interval 7 day);
# GOAL 2: UPSERT ADDITIONAL INFORMATION ON CHILD TABLE
# DONT THINK THIS WILL WORK HERE... HOW DO I RUN THE FOLLOWING CODE
# FOR EACH ROW AFFECTED BY THE UPDATE ABOVE?
INSERT INTO ost_ticket__cdata (ticket_id, subject, priority, autoclosed)
ON DUPLICATE KEY UPDATE autoclosed = '1';
values
(x, y, 2, 1)
End //
DELIMITER;
Related
Trying to create a trigger ensuring that there is at least 30 days between appointments but this doesn't seem to work:
delimiter //
create trigger time_between_doses
before insert on appointment
for each row
begin
if datediff((select appointment_time from appointment where new.patientSSN = patientSSN),
new.appointment_time) < 30
THEN SIGNAL SQLSTATE '45000'
SET MYSQL_ERRNO = 9996,
MESSAGE_TEXT = 'Not 30 days between appointments for this patient';
end if;
end //
delimiter ;
The query that you want to check would use exists. It is not 100% clear what the "30 days" means. Presumably you want to know if this returns any rows:
select a.*
from appointment a
where new.patientSSN = a.patientSSN and
new.appointment_time < a.appointment_time + interval 30 day;
One thing that is unclear is whether the 30 day limit goes into the past as well as the future. And whether it applies to only to appointments in the past or also to appointments in the future.
Your version is an error waiting to happen because you are using a subquery where a single value is expected. If the subquery returns multiple rows, then the code will generate an error. The above logic should be used with exists.
Hi my problem relates to adding days onto a date from two different tables in MySql in the Mamp environment.
Membership type to Membership transaction is 1 to many
The link is type_id
Date is in yyyy/mm/dd format also as this is the only format that Mamp will allow from my research.
I want a new end date column that links to the column duration from the membership type table. I want to add Duration_day onto start_date to produce an end date that matches up with the type_id. (So they link up to give the correct end date)
I want it to be automatically calculated when the start date and type-id are saved
Any help would be appreciated
Thanks
You will need a trigger on INSERT/UPDATE - a calculated column (for MySQL v5.7.6+) will not work in your case (it can only refer to columns in the same table).
The 2 triggers may look like this
CREATE DEFINER = 'root'#'%' TRIGGER `m_duration_ins_tr1` BEFORE INSERT ON `membership`
FOR EACH ROW
BEGIN
DECLARE duration INTEGER;
SELECT m_duration INTO duration FROM membership_type WHERE id = NEW.type_id;
SET NEW.end_date := DATE_ADD(NEW.start_date, INTERVAL duration DAY);
END;
CREATE DEFINER = 'root'#'%' TRIGGER `m_duration_ins_tr1` BEFORE UPDATE ON `membership`
FOR EACH ROW
BEGIN
DECLARE duration INTEGER;
SELECT m_duration INTO duration FROM membership_type WHERE id = NEW.type_id;
SET NEW.end_date := DATE_ADD(NEW.start_date, INTERVAL duration DAY);
END;
I have a MySQL database with one big table in it. After a while, it becomes too full and performance degrades. Every Sunday, I want to delete rows whose last update is older than a certain number of days ago.
How do I do that?
Make a Scheduled Event to run your query every night. Check out Event Scheduler as well.
CREATE EVENT `purge_table` ON SCHEDULE
EVERY 1 DAY
ON COMPLETION NOT PRESERVE
ENABLE
COMMENT ''
DO BEGIN
DELETE FROM my_table WHERE my_timestamp_field <= now() - INTERVAL 5 DAY
END
What is the table design? Do you have a column with a timestamp?
Assuming you do, you could use that timestamp value with a datediff(your_date,CURDATE()) in a delete command.
Delete from table where datediff(date_col, CURDATE ()) > your_num_days.
Self Answer
Make a web server that sends the following SQL to the database every weekend:
DELETE FROM table WHERE timestamp < DATE_SUB(NOW(), INTERVAL 7 DAY);
or
DELETE FROM table
WHERE timestamp < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 7 DAY))
I might need locking to prevent accumulation of jobs, like so:
DELIMITER //
CREATE EVENT testlock_event ON SCHEDULE EVERY 2 SECOND DO
BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
BEGIN
DO RELEASE_LOCK('testlock_event');
END;
IF GET_LOCK('testlock_event', 0) THEN
-- add some business logic here, for example:
-- insert into test.testlock_event values(NULL, NOW());
END IF;
DO RELEASE_LOCK('testlock_event');
END;
//
DELIMITER ;
Final answer:
CREATE EVENT `purge_table` ON SCHEDULE
EVERY 1 DAY
ON COMPLETION NOT PRESERVE
ENABLE
COMMENT ''
DO BEGIN
IF GET_LOCK('purge_table', 0) THEN
DELETE FROM table WHERE timestamp < UNIX_TIMESTAMP(DATE_SUB(NOW(), INTERVAL 7 DAY));
END;
Maybe you can provide more information on how you are pushing the data to the DB and how you are working on the DB in general? Therefore we can help you and don't have to struggle with the dark...
I'll provide an easy solution: It's kind of workaround, but works:
Everytime you touch the data you update a time stamp in the updated rows.
Therefore you could easily filter them out every sunday.
UPDATE
The answer, the author provided by himself, was discussed at Stackoverflow and seems not to work in exactly that way, compare the discussion.
I am using a trigger with some calculation on table A to fill a table B with these calculated values.
Due to crash table A was filled here and there with faulty values, so the calculations result put in table B are here and there not correct.
How can I go through all the rows (in a certain range) and let the trigger recalculate the values and overwrite them in table B.
table A have values of elec meter and gas meter every 5 minutes.
There are about 700 entries wrong.
any suggestion would be aprechiated, thanks
the trigger contents is and initiated after table A update:
BEGIN
SELECT max(ElectraHighP1 + ElectraLowP1) - min(ElectraHighP1 + ElectraLowP1) FROM data_rr WHERE DATE (FROM_UNIXTIME(timestamp)) = curdate() INTO #var1;
SELECT max(SolarHighP1 + SolarLowP1) - min(SolarHighP1 + SolarLowP1) FROM data_rr WHERE DATE(FROM_UNIXTIME(timestamp)) = curdate() INTO #var2;
SELECT max(GasConsumedTotalP1) - min(GasConsumedTotalP1) FROM data_rr WHERE DATE(FROM_UNIXTIME(timestamp)) = curdate() INTO #var3;
INSERT INTO DayData (ElectraUsedToday, SolarDeliveryToday, GasConsumedToday ) VALUES (#var1, #var2,#var3);
END
Calculates the dayvalues of energy tables.
DELIMITER |
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO
BEGIN
DELETE FROM vehicle WHERE last_updated < (NOW() - INTERVAL 5 MINUTE)
END |
DELIMITER ;
Above I have a MySQL event that runs every minute deleting rows that haven't been updated for 5 minutes. I have another table called saved_vehicles. All of the rows in vehicle will have a row in the saved_vehicle table. What I want to do is essentially copy over the last_updated time to the saved_vehicle table (for example purposes, imagine the saved_vehicle field would be last_known_online_time. This essentially saves a copy of the vehicle with its last known online time.
Essentially I'm creating a backup before deleting the row.
Insert into saved_vehicles before delete.
Try this:
DELIMITER |
CREATE EVENT myevent
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 MINUTE
DO
BEGIN
SET #time = NOW() - INTERVAL 5 MINUTE;
# select * is not very smart, it will also copy your primary key,
# so you can get error about duplicates. Listing fields would work here.
INSERT INTO saved_vehicle (SELECT * FROM vehicle WHERE last_updated < #time);
DELETE FROM vehicle WHERE last_updated < #time;
END |
DELIMITER ;
To avoid listing fields i've mentioned in comment try to select all fields except your primary key column.
To do this check how to select all columns except one
update
I through about insert i mentioned above - and if your saved_vehicle table has same structure as vehicle table, but its primary key has different name than vehicle (f.e. base_id, when vehicle PK is id) and its int auto_increment then it will work nice as it is.