how to execute a trigger everyday at once in sql - mysql

we are doing a project on microbanking and we need to calculate the interest rate in database level. So we used procedures and triggers for that. but the trigger needs to execute everyday at once to perform below given procedure. Can you provide a solution to create that trigger. Thanks in advance
DELIMITER //
create procedure addFDInterestToAccount(in account_number bigint(20))
BEGIN
declare interest float default 0;
declare account_type varchar(10);
declare rate float;
declare savings_account bigint(20);
start transaction;
select balance from fd_account where account_no = account_number into interest;
SELECT plan_id from fd_account where account_no = account_number into account_type;
SELECT saving_account_no from fd_account where account_no = account_number into savings_account;
select interest_rate from fd_plan where plan_id = account_type into rate;
set interest = interest*rate/1200;
insert into transaction (transaction_id, account_no, credit_debit, date_time, amount, type_, agent_id, is_fee) values (null, savings_account, 'debit', now(), interest, 'not_special', null, false);
update account set balance = balance + interest where account_no = savings_account;
commit;
END //
DELIMITER ;
call addFDInterestToAccount(90842311);

As far as I understood your requirement, I think you can use SQL Events for this. The general syntax goes like this,
CREATE [OR REPLACE]
[DEFINER = { user | CURRENT_USER | role | CURRENT_ROLE }]
EVENT
[IF NOT EXISTS]
event_name
ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
DO sql_statement;
schedule:
AT timestamp [+ INTERVAL interval] ...
| EVERY interval
[STARTS timestamp [+ INTERVAL interval] ...]
[ENDS timestamp [+ INTERVAL interval] ...]
interval:
quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |
WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |
DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}
You can modify/use following code for achiving this,
CREATE EVENT example
ON SCHEDULE EVERY 1 DAY
STARTS CURRENT_TIMESTAMP
DO call addFDInterestToAccount(90842311);
For further information you can vist the link here
Also make sure you run this query before running the event
SET GLOBAL event_scheduler = ON;

A trigger is defined as a procedure that runs in response to an insert, update, or delete statement. It will run every time you perform one of those DML operations. You cannot schedule a trigger to run once a day.
From the MySql documentation (but applicable to all databases that implement triggers):
A trigger is defined to activate when a statement inserts, updates, or
deletes rows in the associated table. These row operations are trigger
events.
Instead, you need to look for a task scheduler. Each OS will have its own or you could find a third-party scheduler software.

Related

SQL lookup like function

I have 5 columns in SQL table
Id | activity | start date | Finish date | Predecessor activity
1 | shuttering | 1/1/2019 | 3/1/2019 |
2 | concrete | | 6/1/2019 | 1
The above is an example of my table
I need to plan my activities and all the activities are interlinked
The ID 2 succeeds activity 1
So start date of ID 2 is finish date of 1
I need all the start dates to be auto generated except first one based on predecessor activity
Based on this table
CREATE TABLE Schedule1
(`Id` int, `activity` varchar(10), `start_date` datetime
, `Finish_date` datetime, `Predecessor_activity` int)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO Schedule1
(`Id`, `activity`, `start_date`, `Finish_date`, `Predecessor_activity`)
VALUES
(1, 'shuttering', '2019-01-01', '2019-03-01 01:00:00', NULL),
(2, 'concrete', NULL, '2019-06-01 02:00:00', 1),
(3, 'concrete', NULL, '2019-08-01 02:00:00', 2),
(4, 'concrete', NULL, '2019-10-01 02:00:00', 3);
This sql statemenbt
UPDATE Schedule1 t2
Left JOIN Schedule1 t1 ON t2.Predecessor_activity = t1.Id
SET t2.start_date = IFNULL(t2.start_date,t1.Finish_date);
gets you
Id activity start_date Finish_date Predecessor_activity
1 shuttering 2019-01-01 00:00:00 2019-03-01 01:00:00
2 concrete 2019-03-01 01:00:00 2019-06-01 02:00:00 1
3 concrete 2019-06-01 02:00:00 2019-08-01 02:00:00 2
4 concrete 2019-08-01 02:00:00 2019-10-01 02:00:00 3
for the use of trigger like insert or update
like this
#DELIMITER //
DROP TRIGGER IF EXISTS my_update_trigger;
CREATE DEFINER=root#localhost TRIGGER my_update_trigger
AFTER update ON `schedule1`
FOR EACH ROW
BEGIN
-- Call the common procedure ran if there is an INSERT or UPDATE on `table`
-- NEW.id is an example parameter passed to the procedure but is not required
-- if you do not need to pass anything to your procedure.
CALL procedure_to_run_schedule()//
END//
DELIMITER ;
We nee a new Table, because updating the same table isn't allowed for triggers.
So we create a new table that is identical to our original
DROP TABLE IF EXISTS newschedul;
CREATE TABLE newschedule SElect * From Schedule1;
And then we add a new stored procedure.
What it does, After you inserted or updated your original table, it copies all data to the new table and uses above statement to make the new schedule.
so you can access the actual schedule by selecting rows from the. Updfating and isnert you only make in the schedule to avoid the problmes you described
DELIMITER //
DROP PROCEDURE IF EXISTS procedure_to_run_schedule//
CREATE DEFINER=root#localhost PROCEDURE procedure_to_run_schedule()
READS SQL DATA
BEGIN
SET SQL_SAFE_UPDATES = 0;
DELETE FROM newschedule;
INSERT INTO newschedule
SELECT * FROM Schedule1;
UPDATE newschedule t2
Left JOIN newschedule t1 ON t2.Predecessor_activity = t1.Id
SET t2.start_date = IFNULL(t2.start_date,t1.Finish_date) ;
SET SQL_SAFE_UPDATES = 1;
END//
DELIMITER

Schedule Event in MySQL

I have been trying to find this answer for quite some time with no avail. Here is what I have to do. I create the very first record in the table below. Then I would like to schedule an event that is recurrent once a week to insert a new record into this table. All I need is this event to do is add a week from the field of the last row in the table once a week.
preferred output (something like this)
+----+------------+------------+
| id | start | end |
+----+------------+------------+
| 1 | 2014-12-04 | 2014-12-11 | <-- Manually Inputed (base dates)
| 2 | 2014-12-11 | 2014-12-18 | <-- SQL Scheduled Events below
| 3 | 2014-12-18 | 2014-12-25 | (Every Thursday :D)
| 4 | 2014-12-25 | 2015-01-01 |
+----+------------+------------+
SQL statement so far
INSERT INTO `publication_dates` (`id`, `Start`, `End`) VALUES (null,"2014-12-04", DATE_ADD("2014-12-04",INTERVAL +1 WEEK));
I haven't created an event for this because I have literally no idea how to get the information from the row before it. This will help me get over the hurdle I've hit in my laravel project.
Thank you for your time in advance!
MySQL Systax Error for
DELIMITER &&
CREATE EVENT new_publication
ON SCHEDULE EVERY 1 WEEK STARTS '2014-12-04 00:00:00'
DO BEGIN
INSERT INTO publication_dates (`Start`, `End`)
VALUES (NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY));
END &&
You can achieve this using the mysql event scheduler if you let the first row to be created by the event as well.
Start the event on the first date that you want to enter. And the event should run the insert query below.
INSERT INTO publication_dates (`start`, `end`)
VALUES (NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY));
For events to work, you need to launch the mysql instance with event scheduler on or you can turn it on by running this query:
SET GLOBAL event_scheduler = ON;
Then you have to create an event that will run every Thursday, say at midnight.
DELIMITER &&
CREATE EVENT run_on_thursdays
ON SCHEDULE EVERY 1 WEEK STARTS <starting thursday> ENDS <ending thursday>
do begin
<the insert query from above>
END &&
This will enter the first value on the and keep adding a row every Thursday until the ending Thursday.

EVENT not executing as per the code in MySQL

I have created an event which will update the balance in table 'try_event' after every 5 minutes according to the balance and time at which the row is inserted.
EVENT code:
delimiter $$
CREATE EVENT `event`
ON SCHEDULE every 1 second
DO
begin
-- update balance by 2%
UPDATE try_event
SET Balance = case
WHEN timestampdiff(minute,date_created,current_timestamp) >0 and timestampdiff(minute,date_created,current_timestamp) MOD 5 = 0 and (balance>2000 and balance<3000) then Balance * 1.02
end;
end $$
delimiter ;
TABLE :
create table try_event(balance numeric(10,2) not null,date_created timestamp);
INSERTED ROWS:
insert into try_event values(2500,default);
insert into try_event values(1000,default);
but still it is giving the balance=2500 after 5 minutes.
When I remove "(balance>2000 and balance<3000)" the whole balance column is updated and result is:
2550
1020
I just created a test table on an instance of MySQL 5.5.29 (actually Percona Server, which is MySQL with some patches and new feature). It worked fine, it updated the 2500 balance and did not update the 1000 balance.
Here's a check that shows that the update happened (including automatically updating the TIMESTAMP column):
mysql> SELECT timestampdiff(MINUTE, date_created, current_timestamp) AS td,
balance FROM try_event;
+------+---------+
| td | balance |
+------+---------+
| 8 | 1000 |
| 3 | 2550 |
+------+---------+
I made slight changes to the event definition:
When using CASE expressions, it's worthwhile to represent an "ELSE" clause because otherwise if the WHEN condition is false, and you have no ELSE clause, the result of the CASE expression is just NULL.
UPDATE try_event
SET Balance = CASE
WHEN timestampdiff(minute,date_created,current_timestamp) >0
AND timestampdiff(minute,date_created,current_timestamp) MOD 5 = 0
AND balance>2000 and balance<3000
THEN Balance * 1.02
ELSE Balance -- this is what I added.
END;
Is it possible your balance column is declared NOT NULL, so the UPDATE is trying to set balance to NULL and it's simply failing?
I also remove the parentheses around the balance range comparison, but that shouldn't make any difference.

How to update two tables at a time using a single stored procedure?

I have two tables in my database Requests and Balance tracker which has no relation.... but I want to select data from two tables and bind it two grid...
Requests
EmpID | EmpRqsts | EmpDescription | ApproverID | ApprovedAmount | RequestPriority
1 | asdfsb | sadbfsbdf | 1 |
2 | asbfd | sjkfbsd | 1 |
Balance Tracker
EmpId | BalanceAmnt | LastUpdated | lastApprovedAmount
1 | 5000 | sdfbk |
2 | 3000 | sjbfsh |
Now I want to update both tables at a time, based on the EmpID. Whenever amount is approved, it should be updated in request table column [ApprovedAmount] and with priority...
When [ApprovedAmount] is updated [BalanceAmnt] Balance Tracker of also should be Updated by adding the amount approved,[LastUpdated],[lastApprovedAmount] should be updated with date and time
Can anyone help me with the query please....
First create a stored procedure to update your [ApprovedAmount] column
create procedure SP_UpdateRequestedAmount
(#EmpID int,
#AmountApproved varchar (50),
#RequestPriority varchar (50))
as
begin
Update Requests
set ApprovedAmount = #AmountApproved,
Request_Priority = #RequestPriority
where
Emp_ID = #EmpID
end
Then use a triger to update the other table when ever [AmountApproved] column is updated
CREATE TRIGGER tr_ApprovedAmount_UPDATE
ON Requests
AFTER UPDATE
AS
--Make sure Priority was changed
IF NOT UPDATE(ApprovedAmount)
RETURN
--Determine if Priority was changed to high
-- PUT your queries for Updatating other table
declare #Balance_LastUpdated date
declare #ApprovedDate date
UPDATE Balance Tracker
SET Balance Tracker.Balance_BalanceAmount = Balance Tracker.Balance_BalanceAmount + PTS_Requests.Request_IsApproved,
Balance_LastUpdated = #Balance_LastUpdated,
Balance_LastApproval = #ApprovedDate
FROM
Balance Tracker
INNER JOIN
Requests ON Balance Tracker.Emp_ID = Requests.Emp_ID
Hope this helps.........
Please try this also with out trigger
CREATE procedure SP_UpdateRequestedAmount
(
#EmpID int,
#AmountApproved varchar (50),
#RequestPriority varchar (50)
)
as
begin
--Declare a variable for know current ApprovedAmount (that is before updation)
Declare #CurrentApprovedAmount AS INT
--set current ApprovedAmount
SET #AmountApproved =(SELECT ApprovedAmount FROM Requests WHERE EmpID=#EmpID)
--check is #CurrentApprovedAmount differ from #AmountApproved
IF (#CurrentApprovedAmount!=#AmountApproved)
BEGIN
--Here we need to update Requests and BalanceTracker
END
ELSE
BEGIN
--only update Requests -- no change in AmountApproved
END
go

Move rows from TableA into Table-Archive

Is it possible to move rows that are 3 days old into an other table called "Table_Archive" automatically in mysql ones a week?
tableA ex:
ID | stringvalue | Timestamp
1 | abc | 2011-10-01
2 | abc2 | 2011-10-02
3 | abc3 | 2011-10-05
4 | abc4 | 2011-10-10
5 | abc5 | 2011-10-11
After the move
tableA:
ID | stringvalue | Timestamp
4 | abc4 | 2011-10-10
5 | abc5 | 2011-10-11
Table_Archive:
ID | stringvalue | Timestamp
1 | abc | 2011-10-01
2 | abc2 | 2011-10-02
3 | abc3 | 2011-10-05
And when new input comes into tableA it wont be any problems with ID (PK) in the next move?
What Ive got:
CREATE PROCEDURE clean_tables ()
BEGIN
BEGIN TRANSACTION;
DECLARE _now DATETIME;
SET _now := NOW();
INSERT
INTO Table_Archive
SELECT *
FROM TableA
WHERE timestamp < _now - 3;
FOR UPDATE;
DELETE
FROM TableA
WHERE timestamp < _now - 3;
COMMIT;
END
How do I change _now to be the date 3 days ago?
Personally, I would make use of the MySQL Event Scheduler. This is a built in event scheduler rather like CRON in Linux.
You can specify it to call a procedure, procedures or functions or run a bit of SQL at designated intervals.
Read the MySQL docs but an example would be:
CREATE EVENT mydatabase.myevent
ON SCHEDULE EVERY 1 WEEK STARTS CURRENT_TIMESTAMP + INTERVAL 10 MINUTE
DO
call clean_tables();
So this is saying "call clean_tables() once a week and make the first call in 10 minutes' time"
One gotcha is that the event scheduler is (I think) disabled by default. To turn it on run:
SET GLOBAL event_scheduler = ON;
You can then run:
SHOW PROCESSLIST;
To see whether the event scheduler thread is running.
As for preserving your Table A ID column (if you must). I would keep the ID on Table_Archive as unique to that table i.e make it the primary key & auto_increment and then have a 'Original_TableA_ID' column in which to store the TableA ID. You can put a unique index on this if you want.
So Table_Archive would be like:
create table `Table_Archive` (
ID int unsigned primary key auto_increment, -- < primary key auto increment
tableAId unsigned int not null, -- < id column from TableA
stringValue varchar(100),
timestamp datetime,
UNIQUE KEY `archiveUidx1` (`tableAId`) -- < maintain uniqueness of TableA.ID column in Archive table
);
Nobody seems to have answered your original question "How do I change _now to be the date 3 days ago?". You do that using INTERVAL:
DELIMITER $
CREATE PROCEDURE clean_tables ()
BEGIN
BEGIN TRANSACTION;
DECLARE _now DATETIME;
SET _now := NOW();
INSERT
INTO Table_Archive
SELECT *
FROM TableA
WHERE timestamp < _now - interval 3 day;
FOR UPDATE;
DELETE
FROM TableA
WHERE timestamp < _now - interval 3 day;
COMMIT;
END$
DELIMITER ;
One final point is that you should consider creating an index on the timestamp column on TableA to improve the performance of you clean_tables() procedure.
You may need to have a look into cron jobs if you want that script/query to be executed automatically.
If you are using cpanel have a look into http://www.siteground.com/tutorials/cpanel/cron_jobs.htm
Adding to the best answer (imo) by Tom Mac regarding the event scheduler - be aware that when backing up the schema, you have to specify that you want the events backed up with it via the --events=TRUE flag.
If you're exporting manually in the workbench, the latest version has a checkbox on the main 'Export To Disk' tab - older versions hide it away in the Advanced Export Options tab.
It is possible, MySQL will execute query automatically at specific time using MySQL Event Scheduler. Check this link for more details.
https://dev.mysql.com/doc/refman/5.7/en/event-scheduler.html