I am trying to format a date and a time that comes in one column called DATE as DD/MM/YYYY (Varchar) and in another column called TIME as HH:MM:SS into one variable to insert into another column (in Datetime data type). The code below is my procedure.
DROP PROCEDURE IF EXISTS TESTProc;
DELIMITER //
CREATE PROCEDURE TESTproc()
BEGIN
DECLARE LYEAR VARCHAR(45);
DECLARE LMONTH VARCHAR(45);
DECLARE LDAY VARCHAR(45);
DECLARE LTIME VARCHAR(45);
DECLARE LDATETIME DATETIME;
SELECT TIME FROM db.test_table INTO LTIME;
SELECT SUBSTRING(DATE,6,4) FROM db.test_table INTO LYEAR;
SELECT SUBSTRING(DATE,3,2) FROM db.test_table INTO LMONTH;
SELECT SUBSTRING(DATE,1,1) FROM db.test_table INTO LDAY;
SELECT CONCAT(LYEAR,'-', LMONTH,'-','0',LDAY,' ',LTIME) INTO LDATETIME;
INSERT INTO db.test_table(VC19) VALUES (LDATETIME);
END //
Call TESTProc;
When I run the procedure, I get an error code back:
Call TESTProc; Error Code: 1292. Incorrect datetime value: '2013-31-01 16:00:40' for column 'LDATETIME' at row 2
I only have one row in db.test_table. I do not have a column in the table called 'LDATETIME', this is just my local variable. I can see from the error that my format is correct for the DateTime 'YYYY-MM-DD HH:MM:SS'.
why I am getting this error?
Update: Here is how my code looks now:
DROP PROCEDURE IF EXISTS DateProc;
DELIMITER //
CREATE PROCEDURE Dateproc()
BEGIN
DECLARE LTIME VARCHAR(45);
DECLARE LDATE VARCHAR(45);
DECLARE LDATETIME DATETIME;
SELECT TIME FROM db.date_table INTO LTIME;
SELECT DATE FROM db.date_table INTO LDATE;
IF LENGTH(LDATE) = 9 AND SUBSTRING(LDATE,2,1) = '/'
THEN SET LDATETIME = CONCAT(SUBSTRING(LDATE,6,4),'-0',SUBSTRING(LDATE,1,1),'-',SUBSTRING(LDATE,3,2), ' ', LTIME);
ELSE IF LENGTH(LDATE) = 9 AND SUBSTRING(LDATE,3,1) = '/'
THEN SET LDATETIME = CONCAT(SUBSTRING(LDATE,6,4),'-',SUBSTRING(LDATE,1,2),'-0',SUBSTRING(LDATE,4,1), ' ', LTIME);
ELSE IF LENGTH(LDATE) = 10
THEN SET LDATETIME = CONCAT(SUBSTRING(LDATE,7,4),'-',SUBSTRING(LDATE,1,2),'-',SUBSTRING(LDATE,4,2), ' ', LTIME);
ELSE IF LENGTH(LDATE) = 8
THEN SET LDATETIME = CONCAT(SUBSTRING(LDATE,5,4),'-0',SUBSTRING(LDATE,1,1),'-0',SUBSTRING(LDATE,3,1), ' ', LTIME);
END IF;
END IF;
END IF;
END IF;
INSERT INTO db.date_table(table_name) VALUES (LDATETIME);
END //
CALL DateProc;
This seems to work and accounts for any variable date that may end up in my original date column.
Look at the value:
'2013-31-01 16:00:40'
That's trying to use a month of 31.
It's not clear whether that just means your test data is wrong, or whether you need to change these lines:
SELECT SUBSTRING(DATE,3,2) FROM db.test_table INTO LMONTH;
SELECT SUBSTRING(DATE,1,1) FROM db.test_table INTO LDAY;
to:
SELECT SUBSTRING(DATE,1,2) FROM db.test_table INTO LMONTH;
SELECT SUBSTRING(DATE,4,2) FROM db.test_table INTO LDAY;
Note the change from 1 to 2 for the substring starting at 1 anyway, and the change of the second starting position from 3 to 4. You want two-digit month and day values, right? If your data format is actually D/M/YYYY (i.e. only using two digits when they're required) then you won't be able to use fixed substring positions.
Somehow your LMONTH and LDAY values seem to be reversed as LMONTH is getting written as 31 and LDAY as 01 - which obviously incorrect. Check the data within your source table.
Related
Two tables Borrower(rollno,name,bookissue_date) and Fine(rollno,name,amount)
delimiter //
create procedure student( in roll_no int,in Nameofbook varchar(40))
begin
declare Dateofiss1 date;
Declare cur cursor for
select Dateofiss from Borrower where Roll_no = roll into Dateofiss1;
OPEN cur;
fetch cur into Dateofiss1
if(datediff(sysdate(),Dateofiss1)<15) then varchar(20))
update Borrower set status='R'where Roll_no=roll_no
elseif(datediff(sysdate(),Dateofiss1)>=15)and datediff (sysdate(),Dateofiss1<30)
SET FINEAMOUNT=5*(datediff(sysdate(),Dateofiss1)-15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
update.borrower set status='R' where Roll_no='rollno';
elseif (datediff(sysdate(),Dateofiss1)>30)
SET FINEAMOUNT=50*(datediff(sysdate(),Dateofiss1)-15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
update.borrower set status='R' where Roll_no='rollno';
close cur;
end if
select * from Borrower;
elect * from Fine;
end
You have a number of syntax errors.
You have an extraneous varchar(20)) in the first if statement.
You're missing THEN in the ELSEIF statements.
You wrote update.borrower instead of update borrower.
You have roll_no in quotes in some of your update statements.
The roll_no parameter is the same as a table column, since column names are case-insensitive. The condition where Roll_no = roll_no will match every row because of this. Give the parameter a different name.
In a SELECT, the INTO clause goes after FROM, not at the end.
There's no need to use a cursor if you're using SELECT INTO. Just execute the query and it will set the variable.
You can also simplify the code by putting the date difference in a variable, so you don't have to repeatedly calculate it. And in the ELSEIF you don't need to test >= 15, since you'll only get there if the < 15 test failed.
The UPDATE statement is the same in all conditions, so it doesn't need to be in the IF at all.
delimiter //
create procedure student( in p_roll_no int,in Nameofbook varchar(40))
begin
declare Dateofiss1 date;
declare diff INT;
select Dateofiss from Borrower into Dateofiss1 where Roll_no = p_roll_no;
OPEN cur;
SET diff = datediff(sysdate(),Dateofiss1)
IF diff BETWEEN 15 AND 29 THEN
SET FINEAMOUNT= 5 * (diff - 15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
else
SET FINEAMOUNT= 50 * (diff - 15)
insert into Fine(Roll_no,Date,amount)values(rollno,sysdate,fineamount);
end if
update Borrower set status='R'where Roll_no=p_roll_no
select * from Borrower;
select * from Fine;
end
I'm trying to transpose a postgres trigger to a mysql trigger. It automatically adds fields to the row according to the date added
CREATE FUNCTION convert_date ()
RETURNS trigger
AS $$
declare
date_min DATE;
date_max DATE;
temp_year INTEGER;
begin
SELECT SUBSTRING(NEW."dc_date_label",0,5)::integer
INTO temp_year;
SELECT date(temp_year || '-01-10')
INTO date_min;
SELECT date(temp_year +1 || '-09-30')
INTO date_max;
NEW."dc_date_start" = date_min;
NEW."dc_date_end" = date_max;
RETURN new;
end;
CREATE TRIGGER trig_b_i_compute_date()
BEFORE INSERT
ON campaigns
FOR EACH ROW
EXECUTE PROCEDURE convert_date();
This is what i've done on mysql :
DELIMITER //
CREATE TRIGGER trig_b_i_compute_date
BEFORE INSERT ON campaigns
FOR EACH ROW
BEGIN
DECLARE date_min DATE;
DECLARE date_max DATE;
DECLARE temp_year INTEGER;
SET temp_year = SELECT CONVERT( SUBSTRING(NEW.dc_date_label,1,5), UNSIGNED INTEGER) ;
SET date_min = SELECT CONVERT( CONCAT(temp_year,'-01-10'), DATE);
SET date_max = SELECT CONVERT( CONCAT(temp_year + 1, '09-30'), DATE);
SET NEW.dc_date_start = date_min;
SET NEW.dc_date_end = date_max;
END;
//
DELIMITER ;
However I get an error :
MySQL server version for the right syntax to use near 'SELECT CONVERT( SUBSTRING(NEW.dc_date_label,1,5), UNSIGNED INTEGER) ;
What is wrong with the procedure ?
If you use SELECT in a SET statement, you need to put it in parentheses:
SET temp_year = (SELECT ...);
But in your case you don't need a SELECT and you can just skip it:
SET temp_year = CONVERT(...);
You can also use the SELECT INTO syntax in MySQL:
SELECT CONVERT(...) INTO temp_year;
And there is no need to declare date_min and date_max. Also no need to cast everything explicitly. Your trigger body could be:
DECLARE temp_year INTEGER;
SET temp_year = CONVERT( SUBSTRING(NEW.dc_date_label,1,5), UNSIGNED);
SET NEW.dc_date_start = CONCAT(temp_year, '-01-10');
SET NEW.dc_date_end = CONCAT(temp_year + 1, '-09-30');
I don't know how dc_date_label looks like, and why the year should be 5 characters long. So I kept the year extraction as it is. But if it's a DATE, DATETIME or TIMESTAMP, you can just use the YEAR function:
SET temp_year = YEAR(NEW.dc_date_label);
And since it's much shorter, you could also use it inline and skip the temp_year variable:
SET NEW.dc_date_start = CONCAT(YEAR(NEW.dc_date_label), '-01-10');
SET NEW.dc_date_end = CONCAT(YEAR(NEW.dc_date_label) + 1, '-09-30');
And last one: Remove the semicolon after END. It might work, but it doesn't belong there.
I have a medium sized stored procedure going on here below. My problem is that it doesn't do anything and I have no idea why.
1.) First of all, the code:
DROP PROCEDURE IF EXISTS deleteabundant_fixshared_shiftResources;
DELIMITER //
CREATE PROCEDURE deleteabundant_fixshared_shiftResources ()
BEGIN
DECLARE finish_flag BOOLEAN DEFAULT FALSE;
DECLARE id INT(11);
DECLARE startTime DATETIME;
DECLARE endTime DATETIME;
DECLARE shid INT(11);
DECLARE resid INT(11);
DECLARE id_inner INT(11);
DECLARE startTime_inner DATETIME;
DECLARE endTime_inner DATETIME;
DECLARE shid_inner INT(11);
DECLARE resid_inner INT(11);
DECLARE cr130 CURSOR FOR SELECT shift_resource_id, start_date, end_date, shift_id, resource_id FROM temp_shift_resource;
DECLARE cr131 CURSOR FOR SELECT shift_resource_id, start_date, end_date, shift_id, resource_id FROM temp_shift_resource;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET finish_flag = TRUE;
START TRANSACTION;
OPEN cr130;
OPEN cr131;
OUTERLOOP: LOOP
FETCH cr130 into id, startTime, endTime, shid, resid;
IF finish_flag THEN LEAVE OUTERLOOP; END IF;
INNERLOOP: LOOP
FETCH cr131 INTO id_inner, startTime_inner, endTime_inner, shid_inner, resid_inner;
IF finish_flag THEN LEAVE INNERLOOP; END IF;
IF (id!=id_inner) THEN
IF (resid=resid_inner AND shid_inner!=9) THEN
-- logic to determine if the dates are wrong:
IF (startTime<=startTime_inner AND endTime>=endTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FD", shid_inner, resid_inner, startTime_inner, endTime_inner );
DELETE FROM temp_shift_resource WHERE shift_resource_id = id_inner;
ELSEIF (endTime>=endTime_inner AND startTime<=endTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FU", shid_inner, resid_inner, startTime_inner, endTime_inner );
UPDATE temp_shift_resource set endTime_inner=(startTime - INTERVAL 1 DAY) where shift_resource_id = id_inner;
ELSEIF (startTime<=startTime_inner AND endTime>=startTime_inner) THEN
INSERT INTO repairchange ( shift_resource_id, changetype, shift_id, resource_id, start_date, end_date )
VALUES ( id_inner, "FU", shid_inner, resid_inner, startTime_inner, endTime_inner );
UPDATE temp_shift_resource set startTime_inner=(endTime + INTERVAL 1 DAY) where shift_resource_id = id_inner;
END IF;
END IF;
END IF;
END LOOP INNERLOOP;
SET finish_flag = FALSE;
END LOOP OUTERLOOP;
CLOSE cr130;
CLOSE cr131;
COMMIT;
END //
DELIMITER ;
call deleteabundant_fixshared_shiftResources();
2.) Description of what I want to do:
Basically, I have a table full of workshifts. Due to code bugs, some of these shifts have a wrong date assigned to them, and I have to fix the database.
I have to run through the whole table, and compare the rows that are assigned to the same resource_id, which represents a person. So if a person has two shifts that look like (2016-05-10 to 2016-05-20) and (2016-05-15 to 2016-05-23) for example, I have to fix it so that one of them will be trimmed to (2016-05-10 to 2016-05-14) and (2016-05-15 to 2016-05-23).
A shift that is a nightshift, marked as shift_id=9, must not be modified at all.
I insert rows into the repairchange table if a change or a deletion has been made
3.) The procedure runs, but does nothing. I have examples in the database for wrong rows, one example is the one I wrote above. I suspect it is the nested loop, because I want to loop and fetch through the same table, but I haven't found anything on that.
I got the message
0 row(s) affected, 1 warning(s): 1329 No data - zero rows fetched, selected, or processed
but I have seen this before and my stored procedures have worked even though they output this warning.
Any ideas or tips are welcome. Thank you for your time!
I figured it out, after quite some debugging:
I opened the cursors before both of the loops. This meant that after the first walk-through of the inner loop, the cursor was standing at +1 of the LAST row of the table, and when the new outer loop iteration started the second inner loop iteration, the cursor was still at the end position.
Thus it did not run. I replaced the inner-cursor opening and closing into the outer loop, and now it works properly.
My table has a column date_period which stores Date in the format YYYYMM. I want to write a query which inserts date in date_period column in the format YYYYMM if there is no entry till current month.
For Example: the date period has entry till October 2015 so it will contain the value 201510. Now I want to check and insert data till current month if it is not present. So the entries will be now 201511, 201512, 201601
How can I achieve this?
try this way, may it will help you
DECLARE #v DATE= getdate()
declare #Currentdate varchar(10)
set #Currentdate=CONVERT(VARCHAR(10), #v, 112)
/*#Currentdate string is in format '20160129'*/
IF NOT EXISTS(select * from Table1 where date_period=LEFT(#Currentdate,6))
begin
insert into Table1(date_period)values(LEFT(#Currentdate,6))
end
Try this
i think this will be the complete solution for your problem
declare #monthcount int
DECLARE #v DATE= getdate()
declare #lastsavedMonth varchar(20)= (select MAX(date_period) from Table1)
declare #Lastsaveddate varchar(20)= #lastsavedMonth+''+RIGHT(CONVERT(VARCHAR, 100 + DATEPART(d,#v)), 2)
set #monthcount=datediff(month,#Lastsaveddate,CONVERT(VARCHAR(10), #v, 112))
while #monthcount>=0
begin
declare #dateofsavingmonth varchar(20)
if(#monthcount=0)
begin
set #dateofsavingmonth=CONVERT(VARCHAR(10),#v,112)
end
else
begin
set #dateofsavingmonth=CONVERT(VARCHAR(10), dateadd(month,-#monthcount,#v),112)
end
IF NOT EXISTS(select * from Table1 where date_period=LEFT(#dateofsavingmonth,6))
begin
insert into Table1(date_period)values(LEFT(#dateofsavingmonth,6))
end
set #monthcount =#monthcount-1
end
I'm very new to MySQL database. In Excel I have a formula that looks at the date cell and then states from that what Season the row of data is from.
In Excel I use this formula which looks at the month and day to determine which if the values from the array it falls into:
=LOOKUP(TEXT([DATE_CELL],"mmdd"),{"0101","0321","0621","0922","1221";"Winter","Spring","Summer","Autumn","Winter"})
Is there any way to setup a view or tag this onto a table in MySQL in order to update the season by itself? Many thanks for taking a look.
I would create a function like this:
CREATE DEFINER = 'root'#'localhost' FUNCTION `getSeason`(P_date DATE)
RETURNS varchar(10) CHARSET latin1
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE v_season VARCHAR(10);
DECLARE v_month integer;
DECLARE v_day integer;
select date_format(P_date,'%m'),date_format(P_date,'%d') into v_month,v_day;
if (v_month<3 or (v_month=3 and v_day<21)) then
set v_season="Winter";
else if (v_month<6 or (v_month=6 and v_day>=21)) then
set v_season="Spring";
else if (v_month<9 or (v_month=9 and v_day>=21)) then
set v_season="Summer";
else if (v_month<12 or (v_month=12 and v_day<=21)) then
set v_season="Autumn";
else
set v_season="Winter";
end if;
end if;
end if;
end if;
RETURN v_season;
END;
And use the function in your WHERE clause: where getSeason(myDaeField)='Winter'
Or in your select :select getSeason(myDateField) as Season