sql Trigger ensuring 30 days between appointments not working - mysql

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.

Related

Updating both parent and child table in stored procedure

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;

Adding days to monthly events in MySQL

DELIMETER $$
CREATE EVENT loan_balance ON SCHEDULE EVERY '1' MONTH AND '5' DAYS
DO BEGIN UPDATE users SET loan_balance = total_loans_collected -
total_loans_paid;
END$$
DELIMETER;
Hello! I want to update this table on the 5th of every month and not just monthly. The "AND '5' DAYS isn't making it work.
You need a slightly different ON SCHEDULE phrase.
AT '2018-04-01 03:01' + INTERVAL 5 DAY EVERY MONTH
fires your event at 03:01 local time on the fifth day of every month.
03:01 is a good time for a scheduled job because it doesn't get messed up by standard-time / daylight-time switchovers.
Instead of using a trigger to update the loan_balance column, you can turn it into a generated column.
ALTER TABLE users MODIFY COLUMN loan_balance INT GENERATED ALWAYS AS
(total_loans_collected - total_loans_paid) STORED;
Unless I'm missing something, I believe this is the most optimal approach, and it is certainly easier to maintain.

How to count occurrences in date range for each day on a column

I have a problem for which a 15 minute search on SO couldn't get an answer. I have a database with a table called bugs, which is used to store some info about bugs in a system we are developing. Columns of importance are open_date, close_date and status of severity of the bug introduced. I need to make an SQL statement to display counted number of opened bugs for each of dates from a range of dates which is entered. A bug is considered open on “2012-01-01” if it is created on or
before “2012-01-01” (i.e. the same day) and closed on or after “2012-01-02” (i.e. day after that date).
I have made an sql for finding unit functionality of the requirement:
SELECT COUNT(DATE(Open_Date)) BugsOpen
, DATE(Open_Date) Dated
FROM bugs
WHERE DATE(open_date) <= (STR_TO_DATE('21/10/17','%d/%m/%Y'))
AND DATE(close_date) >= (DATE_ADD(STR_TO_DATE('21/10/17','%d/%m/%Y'),INTERVAL 1 DAY))
OR close_date IS NULL);
Which is working but I need this in like a function call or stored procedure call, ex. showBugs('21/10/17 - 29/10/17'), to display for each of the dates in the range input in this function/procedure.
I have found a way to extract to and from dates.
SELECT SUBSTRING('21/10/17 - 29/10/17', -19, 8) as from_date,
SUBSTRING('21/10/17 - 29/10/17' FROM 12) as to_date;
But I am really having trouble writing a simple procedure. I have started writing some code:
DROP PROCEDURE IF EXISTS showBugs;
CREATE DEFINER = 'root'#'localhost' PROCEDURE showBugs(rangeOfDates TEXT)
BEGIN
SET #from_date = SUBSTRING(rangeOfDates, -19, 8);
SET #to_date = SUBSTRING(rangeOfDates FROM 12);
REPEAT SET #from_date
END REPEAT;
END;
call showBugs('21/10/17 - 29/10/17');
I am really in a rut here and would be grateful if someone is to help me either with stored procedure or function implementation.

How do I clear old entries from a MySQL database table?

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.

MySQL date difference check within a trigger

Within a trigger before I insert some data into a table, I would want it to check, whether the difference of dates of events I am entering is greater than or equal to 1 day. There can only be one event in one club taking place each day.
Sample story
If there already is 2014-01-01 19:00:00 date in database and I'm trying to insert another record with 2014-01-01 date (hour does not matter), it should not allow it.
Partial code from the trigger
DECLARE k INT DEFAULT 0;
/* This is where I get the error, ABS is to make it always positive to go through
checking, so that it wont matter whether the NEW date is before or after */
SELECT ABS(DATEDIFF(DATE_FORMAT(`performance_date`, '\'%Y-%m-%d %H:%i:%s\''),
DATE_FORMAT(NEW.`performance_date`, '\'%Y-%m-%d %H:%i:%s\''))) INTO k;
/* Below code is out of scope for this question */
IF k = 0 THEN
SIGNAL SQLSTATE '58005'
SET MESSAGE_TEXT = 'Wrong! Only 1 performance in 1 club is allowed per day! Change your date, or club!';
END IF;
Error Code: 1054. Unknown column 'performance_date' in 'field list'
I've tried something as simple as:
...DATEDIFF(`performance_date`, NEW.`performance_date`)
You can use a SELECT ... INTO var_list query to COUNT how many entries are already in the database that match your times:
I'm assuming that you mean one entry per day, and I'm assuming that the performance_date column is of DATETIME or TIMESTAMP type.
DECLARE k INT DEFAULT 0;
/* Count number of performances occurring on the same date as the
performance being inserted */
SELECT COUNT(*)
FROM tbl
WHERE performance_date
BETWEEN DATE(NEW.`performance_date`)
AND DATE(DATE_ADD(NEW.`performance_date`, INTERVAL 1 DAY))
INTO k;
/* If k is not 0, error as there is already a performance */
IF k != 0 THEN
SIGNAL SQLSTATE '58005'
SET MESSAGE_TEXT = 'Wrong! Only 1 performance in 1 club is allowed per day! Change your date, or club!';
END IF;
For clarity, if you have a performance with performance_date as 2014-01-01 19:00:00, and you insert a new performance with date 2014-01-01 08:30:00 (for example) then the above code will run this query, which will return a COUNT of 1, which will then cause the trigger to give that error:
SELECT COUNT(*)
FROM tbl
WHERE performance_date
BETWEEN DATE("2014-01-01 08:30:00") AND DATE(DATE_ADD("2014-01-01 08:30:00", INTERVAL 1 DAY))
# The line above will become:
# BETWEEN "2014-01-01" AND "2014-01-02"
INTO k