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
Related
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;
I have a table:
vacation_days:
id name work_days hire
-------------------------------------
1 John 369 20151226
2 Mike 767 20141123
3 Josh 1166 20131020
There is a formula to get hire:
UPDATE vacation_days SET work_days = DATEDIFF(CURDATE(),DATE(hire))
However if I add a new row I get null values:
id name work_days hire
-------------------------------------
1 John 369 20151226
2 Mike 767 20141123
3 Josh 1166 20131020
4 Richard NULL 20120623
I have tried to use a trigger like so:
CREATE TRIGGER onInsert BEFORE INSERT ON vacation_days
FOR EACH ROW
BEGIN
SET NEW.work_days = DATEDIFF(CURDATE(),DATE(hire))
END;
However I get an error:
You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near
''vacation_days' FOR EACH ROW SET work_days = DATEDIFF(CURDATE(), DATE
(NEW.hire))' at line 1
Don't update! Just use a view:
create view v_vacation_days
select vd.*, DATEDIFF(CURDATE(), DATE(vd.hire)) as workdays
from vacation_days vd;
Then the value will be up-to-date whenever you query the view.
Note: You need to remove workdays from the table definition.
Here you are using Insert Before, But the Hire data is not available until inserted, so you can not get the Hire date for the calculations. You want to indicate NEW or OLD Hire data for the usage.
Use this following Insert Before Trigger for your usage,
DELIMITER //
CREATE TRIGGER vacation_days_before_insert
BEFORE INSERT
ON vacation_days FOR EACH ROW
BEGIN
-- Insert record into table
INSERT INTO vacation_days
( id,
name,
work_days,
hire)
VALUES
( NEW.id,
NEW.name,
DATEDIFF(CURDATE(),DATE(NEW.hire)),
NEW.hire );
END; //
DELIMITER ;
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
How to have this code/output in MySql:
Had a recursive cte in MSSQL to fill a table with random data without loop e.g begin/end. Searched for similar logic in MySql but most or all solutions were using begin/end or for loops. Wonder if you could suggest a solution without loop in MySql.
Thanks
--MSSQL cte:------------------------------------
with t1( idi,val ) as
(
select
idi=1
,val=cast( 1 as real)
union all
select
idi=idi+1
,val=cast(val+rand() as real)
from t1
where idi<5
)
select idi,val from t1
-----------------------------------------------
Output in MSSQL:( semi random values)
idi | val
-------------
1 | 1
2 | 1.11
3 | 1.23
4 | 1.35
5 | 1.46
Edit:
Regarding discussions which considers set based codes as loop based codes indeed, I could understand this but just out of interest gave it a try in MSSQL 2008r2, here is the result:
1- above code with 32000 recursion took 2.812 sec
2- above output created with WHILE BEGIN END loop for 32000 took 53.640 sec
Obviously this is a big difference in execution time.
Here is the loop based code:
insert into #t1(idi,val)
select
idi=1
,val=1
declare #ii int = 2
while #ii<32000
begin
insert into #t1(idi,val)
select
idi=idi+1
,val=val+rand()
from #t1
where idi=#ii-1
set #ii=#ii+1
end
select * from #t1
MySql doesn't support CTE.
You need a procedure or some tricky queries like this one:
set #id=0;
set #val=0;
SELECT #id:=#id+1 As id,
#val:=#val+rand() As val
FROM information_schema.tables x
CROSS JOIN information_schema.tables y
LIMIT 10
I have a dataset being returned that has monthly values for different 'Goals.' The goals has unique ID's and the month/date values will always be the same for the goals. The difference is sometimes one goal doesn't have values for all the same months as the other goal because it might start at a later date, and i want to 'consolidate' the results and sum them together based on the 'First' startBalance for each goal. Example dataset would be;
goalID monthDate startBalance
1 1/1/2014 10
1 2/1/2014 15
1 3/1/2014 22
1 4/1/2014 30
2 4/1/2014 13
2 5/1/2014 29
What i want to do is display these consolidated (summed) values in a table based on the 'First' (earliest Month/Year) value for each goal. The result would look like;
Year startBalance
2014 23
This is because the 'First' value for goalID of 1 is 10 and the 'First' value for goalID of 2 is '13' but when I try to group by the
Year(Fields!MonthDate.Value)
and use the expression;
Sum(First(Fields!startBalance.Value))
I receive the error;
The Value expression for the textrun ‘StartingValue3.Paragraphs[0].TextRuns[0]’ uses a First, Last or Previous aggregate in an outer aggregate. These aggregate functions cannot be specified as nested aggregates.
Does anyone know if my grouping is incorrect, or if there's a different way i can get the 'First' value for the goalIDs summed together correctly?
You have to change
Sum(First(Fields!startBalance.Value))
to
Sum(Fields!startBalance.Value)
This is Code that you exactly want:
Copy
create table #temp
(id int,
monthDate date,
value int)
insert into #temp values(1,'1/1/2014',10)
insert into #temp values(1,'1/2/2014',15)
insert into #temp values(1,'1/3/2014',20)
insert into #temp values(2,'1/4/2014',25)
insert into #temp values(2,'1/5/2014',19)
declare #min int,#max int
select #min=MIN(ID) from #temp
select #max=MAX(ID) from #temp
select * from #temp --This is your main table
select top 0 * into #res
from #temp
while(#min<=#max)
begin
declare #minDT date
set #minDT=(select MIN(MonthDate) from #temp where id=#min)
insert into #res
select *
from #temp
where ID=#min
and Convert(Date,monthDate,103)=Convert(Date,#minDT,103)
set #min=#min+1
end
select * from #res --This is Result
drop table #res
drop table #temp