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
Related
I am using Below code to add a first day of the month column to the table with an expression to update automatically. But it's throwing a syntax error. someone pls do help.
ALTER TABLE `abc`.`t1`
ADD COLUMN `First_Day` DATE NULL DEFAULT select DATE_ADD(DATE_ADD(LAST_DAY(report_date),
INTERVAL 1 DAY),
INTERVAL - 1 MONTH) AFTER `Totals`;
mysql won't allow to use expressions for setting default values.
you can create trigger for this purpose.
delimiter $$
CREATE TRIGGER test_trigger BEFORE INSERT ON `product`
FOR EACH ROW SET
NEW.myCol= DATE_ADD(DATE_ADD(LAST_DAY(new.report_date),
INTERVAL 1 DAY),
INTERVAL - 1 MONTH);
END$$
delimiter;
I would question why you would wish to store this but if you must a generated column might do.
drop table if exists t;
create table t(id int, report_date date);
ALTER TABLE t
ADD COLUMN `First_Day` DATE as
(date_add(date_add(last_day(date(report_date)),interval 1 day),interval -1 month));
insert into t (id,report_date) values
(1,'2018-01-08'),(2,'2018-02-09');
select * from t;
+------+-------------+------------+
| id | report_date | First_Day |
+------+-------------+------------+
| 1 | 2018-01-08 | 2018-01-01 |
| 2 | 2018-02-09 | 2018-02-01 |
+------+-------------+------------+
2 rows in set (0.00 sec)
I you choose to go this way or via a trigger you will have to write a one off update to populate this column for existing data.
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.
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.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I make a row generator in mysql
generate_series equivalent in mysql
I've got a trouble with creating mysql Query.
My PHP script executes this query on each run:
INSERT INTO Executes SET UserIp='%s' (%s is user IP)
Executes table is:
ExecuteId UNSIGNED BIGINT AI PRIMARY
Date TIMESTAMP DEFAULT CURRENT_TIMESTAMP INDEX
UserIp CHAR(24) ... | Some Columns
I want to retrive number of Executes in each hour. The most obvious solution would be:
SELECT COUNT(*) as ExecutesNum, DATE(Date) as D, HOUR(Date) as H GROUP BY D, H
And it works, BUT it does not create rows for hours where there were no executes.
What should I modify to get result like:
1 | 2012-09-01 | 14
**0 | 2012-09-01 | 15**
11 | 2012-09-01 | 16
1 | 2012-09-01 | 17
This is a rather common problem, which I usually solve by creating a temporary table containing all the hours, like this:
DROP TABLE IF EXISTS hours;
CREATE TABLE hours (hour VARCHAR(13) PRIMARY KEY);
DROP PROCEDURE IF EXISTS fill_hours;
DELIMITER |
CREATE PROCEDURE fill_hours(start_time DATETIME, end_time DATETIME)
BEGIN
DECLARE crt_time DATETIME;
SET crt_time=DATE_SUB(start_time, INTERVAL DATE_FORMAT(start_time, '%i:%s') MINUTE_SECOND);
WHILE crt_time < end_time DO
INSERT INTO hours VALUES(DATE_FORMAT(crt_time, '%Y-%m-%d-%H'));
SET crt_time = DATE_ADD(crt_time, INTERVAL 1 HOUR);
END WHILE;
END |
CALL fill_hours( (SELECT MIN(Date) FROM Executes), (SELECT MAX(Date) FROM Executes) );
You can then join this table to the original one to get what you want:
SELECT
h.hour,
COUNT(e.ExecuteId)
FROM hours h
LEFT JOIN Executes e ON DATE_FORMAT(e.Date, "%Y-%m-%d-%H") = h.hour
GROUP BY h.hour
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