I want to add an attribute to an while condition on MySQL - mysql

i'm doing my first DB on mySQL and I want to make an underground like system. To start the system I want to make them go from one station to another on a fixed time of 2 seconds so I use the following code
delimiter |
CREATE EVENT runBlue
ON SCHEDULE EVERY 2 SECOND
DO
BEGIN
WHILE (SELECT Actual_Station FROM route WHERE Actual_Station) < 311 DO
UPDATE mydb.route SET Actual_Station = (Actual_Station+1);
END WHILE;
WHILE (SELECT Actual_Station FROM route WHERE Actual_Station) >= 300 DO
UPDATE mydb.route SET Actual_Station = (Actual_Station-1);
END WHILE;
END |
delimiter ;
What concerns me is that there is no increment to the Actual_Station that is represented by an INT, the reason why I am doing this is because the underground is divided in 3 routes, this is the example for the first one that goes form station 300 to station 311.

Related

Is updating with inline select atomic in mysql?

I have an app that calculates points for a user, based on certain rules, for every dollar they spent on my portal. I am using the following stored procedure to update the points of the user:
DROP PROCEDURE IF EXISTS `Update_Points`;
DELIMITER $$
CREATE PROCEDURE `Update_Points` (
pUserId BIGINT,
pPoints DECIMAL(13,2), // points accrued for the amount 'pAmount'
pAmount DECIMAL(13,2) // amount spent by the user
)
SPROC:BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
INSERT INTO AuditTable(UserId, Amount, Points)
VALUES (pUserId, pAmount, pPoints);
UPDATE PlayerPoints
SET Points = Points + pPoints
WHERE UserId = pUserId;
SELECT ROW_COUNT() INTO #RowsUpdated;
COMMIT;
SELECT #RowsUpdated;
END$$
DELIMITER ;
I am seeing discrepancies in total points accrued by some of the users. I know this because we have another backend database that stores user transactions.
We have multiple instances of our applications running to handle the load so one idea was that it could this stored procedure that could cause the accrued points discrepancy, based on the idea that the following snippet might not be atomic
UPDATE PlayerPoints
SET Points = Points + pPoints
WHERE UserId = pUserId;
So my question to you gurus of mysql is whether the above UPDATE statement is atomic or not?
The PlayerPoints table has following structure:
UserId
Amount
Points
1
30
50
1
10
20
2
35
30
3
10
20
2
35
30

How to fix AFTER UPDATE Trigger

I created a User Point system for my website. The table looks like this:
user_id name article gallery description total
------------------------------------------------------------
1 joe 7 3 0 10
2 hary 3 5 5 13
3 ana 1 1 2 4
I need an AFTER UPDATE trigger that will make the update SUM in the column total when the value changes in the column, article, gallery or description
DELIMITER $$
CREATE TRIGGER total_trg
AFTER UPDATE point_system FOR EACH ROW
BEGIN
UPDATE point_system SET total = (article + gallery + description) FROM point_system WHERE user_id = NEW.user_id;
END
$$
DELIMITER ;
This trigger does not work. Why?
You cannot modify a table's contents from a trigger on that table (except for the row the trigger is operating on, but not in that way); in this case, what you need is a BEFORE UPDATE trigger, in which you would just
SET NEW.total = NEW.article + NEW.gallery + NEW.description;
You use NEW and OLD to access (and modify in BEFORE triggers) the field values of the row responsible for the trigger firing.

MySQL: select random individual from available to populate new table

I am trying to automate the production of a roster based on leave dates and working preferences. I have generated some data to work with and I now have two tables - one with a list of individuals and their preferences for working on particular days of the week(e.g. some prefer to work on a Tuesday, others only every other Wednesday, etc), and another with leave dates for individuals. That looks like this, where firstpref and secondpref represent weekdays with Mon = 1, Sun = 7 and firstprefclw represents a marker for which week of a 2 week pattern someone prefers (0 = no pref, 1 = wk 1 preferred, 2 = wk2 preferred)
initials | firstpref | firstprefclw | secondpref | secondprefclw
KP | 3 | 0 | 1 | 0
BD | 2 | 1 | 1 | 0
LW | 3 | 0 | 4 | 1
Then there is a table leave_entries which basically has the initials, a start date, and an end date for each leave request.
Finally, there is a pre-calculated clwdates table which contains a marker (a 1 or 2) for each day in one of its columns as to what week of the roster pattern it is.
I have run this query:
SELECT #tdate, DATE_FORMAT(#tdate,'%W') AS whatDay, GROUP_CONCAT(t1.initials separator ',') AS available
FROM people AS t1
WHERE ((t1.firstpref = (DAYOFWEEK(#tdate))-1
AND (t1.firstprefclw = 0 OR (t1.firstprefclw = (SELECT c_dates.clw from clwdates AS c_dates LIMIT i,1))))
OR (t1.secondpref = (DAYOFWEEK(#tdate))-1
AND (t1.secondprefclw = 0 OR (t1.secondprefclw = (SELECT c_dates.clw from clwdates AS c_dates LIMIT i,1)))
OR ((DAYOFWEEK(#tdate))-1 IN (0,5,6))
AND t1.initials NOT IN (SELECT initials FROM leave_entries WHERE #tdate BETWEEN leave_entries.start_date and leave_entries.end_date)
);
My output from that is a list of dates with initials of the pattern:
2018-01-03;Wednesday;KP,LW,TH
My desired output is
2018-01-03;Wednesday;KP
Where the initials of the person have been randomly selected from the list of available people generated by the first set of SELECTs.
I have seen a SO post where a suggestion of how to do this has been made involving SUBSTRING_INDEX (How to select Random Sub string,which seperated by coma(",") From a string), however I note the comment that CSV is not the way to go, and since I have a table which is not CSV, I am wondering:
How can I randomly select an individual's initials from the available ones and create a table which is basically date ; random_person?
So I figured out how to do it.
The first select (outlined above) forms the heart of a PROCEDURE called ROWPERROW() and generates a table called available_people
This is probably filthy MySQL code, but it works:
SET #tdate = 0
DROP TABLE IF EXISTS on_call;
CREATE TABLE working(tdate DATE, whatDay VARCHAR(20), selected VARCHAR(255));
DELIMITER //
DROP PROCEDURE IF EXISTS ROWPERROW2;
CREATE PROCEDURE ROWPERROW2()
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE kk INT DEFAULT 0;
SET n=90; -- or however many days the roster is going to run for
SET kk=0;
WHILE kk<n DO
SET #tdate = (SELECT c_dates.fulldate from clwdates AS c_dates LIMIT kk,1);
INSERT INTO working
SELECT #tdate, DATE_FORMAT(#tdate,'%W') AS whatDay, t1.available
FROM available_people AS t1 -- this is the table created by the first query above
WHERE tdate = #tdate ORDER BY RAND() LIMIT 1;
SET kk = kk + 1;
END WHILE;
end;
//
DELIMITER ;
CALL ROWPERROW2();
SELECT * from working;

insert data into one table from another table on specific condition

I have "table1" in which master data store like -
id name create_date validity expire_date
1 A 2015-08-01 3 2015-11-01
2 B 2015-09-01 12 2016-08-01
3 C 2015-09-15 1 2015-10-15
But now want to insert data in "table2" for expire_date according to validity period like without changing in front end. using trigger or procedure want to achieve this task.
id parent_id expire_date
1 1 2015-09-01
2 1 2015-10-01
3 1 2015-11-01
How can I achieve this using procedure or trigger.
It's hard to be specific because your question is not specific.
In general, here's the procedure to follow to design a query to insert stuff from one table into another.
First, write a SELECT query yielding a resultset containing the rows and columns you want inserted into your table. Use a list of columns to get the right columns, and appropriate WHERE clauses to get the right rows. Eyeball that query and that resultset to make sure it contains the correct information.
Second, prepend that debugged SELECT query with
INSERT INTO target_tablename (col, col, col)
Test this to make sure the correct rows are being inserted into your target table.
Third, create yourself an EVENT in your MySQL server to run the query you have just written. The event will, at the appropriate times of day, run your query.
If you take these steps out of order, you'll probably be very confused.
Can achieve the task using Store Procedure -
CREATE DEFINER=`root`#`localhost` PROCEDURE `addexpire`(IN uname varchar(50), IN cdate date, IN vm int)
BEGIN
insert into table1 (name,create_date,validity) values (uname,cdate,vm);
BEGIN
declare uparent_id INT;
declare v_val int default 0;
SET uparent_id = LAST_INSERT_ID();
while v_val < vm do
BEGIN
declare expire_date date;
SET expire_date = DATE_ADD(cdate,INTERVAL v_val+1 MONTH);
insert into table2 (parent_id,expire_date) values (uparent_id,expire_date);
set v_val=v_val+1;
END;
end while;
END;
END

MySQL trigger to create timer

There is a special data type 'time' in MySQL.
How would a trigger look if I want my 'time' value to start counting when some state_id changes from 1 to 2? For example:
CREATE TRIGGER log_time AFTER UPDATE ON usr
FOR EACH ROW
BEGIN
IF usr.st_id = 2 THEN
#.... - thats what i dont know
END IF;
END;
It would stop counting when the state_id changes back from 2 to 1.
Instead of starting/stopping the counter (I don't know if that's even possible), you should store the value in 2 different columns (and then substract to get the time when needed)
DELIMITER $$
CREATE TRIGGER log_time AFTER UPDATE ON usr
FOR EACH ROW
BEGIN
IF new.st_id = 2 THEN
UPDATE <table> set <log_start_time> = CURTIME() <where_clause>;
elseif new.st_id = 1 THEN
UPDATE <table> set <log_end_time> = CURTIME() <where_clause>;
END IF;
END;
$$
DELIMITER;
OR in 1 column by storing initial value and then updating it in the trigger
DELIMITER $$
CREATE TRIGGER log_time AFTER UPDATE ON usr
FOR EACH ROW
BEGIN
IF new.st_id = 2 THEN
UPDATE <table> set <logtime> = CURTIME() <where_clause>;
else if new.st_id = 1 THEN
UPDATE <table> set <logtime> = subtime(CURTIME(), select statement to get original value) <where_clause>;
END IF;
END;
$$
DELIMITER;
Okay I'm new to coding and was wondering if this would even be possible and if so what would be the best way to get around this problem
Okay in my database I have a row for current time and a row for duration and I am wanting to find a way so that when the time is the value of T + D it would change a colour (green) ? Or even better if it could be done so if equal to or under 2 mins amber colour and over 2 mins red colour ( kind of like a traffic light idea)
Hope this makes sense
T | D
---------------
22:50 | 6 (mins)
At 22:56 this would change colour on website
Thank You