Update using a procedure in MySQL - mysql

I've spent all day trying to get this to work.
I have a procedure that performs calculations on dates based on an occurrence type. It returns two new datetime fields from a SELECT.
I want to use this procedure to update an events table. Something like this.
UPDATE
events
SET
start = new_start,
end = new_end
FROM CALL updateEvents(events.occurance, events.day_num, start, end)
WHERE
end < NOW();
I'm using MySQL workbench but it reports that 'FROM' is not valid input at this position.
Here is the procedure.
CREATE DEFINER=`admin`#`%` PROCEDURE `updateEvents`(occurance VARCHAR(20), day_num INT, start_time DATETIME, end_time DATETIME)
BEGIN
DECLARE time_interval INT;
DECLARE new_start DATETIME;
DECLARE last_day DATETIME;
DECLARE last_hours INT;
SET time_interval = UNIX_TIMESTAMP(end_time) - UNIX_TIMESTAMP(start_time);
SET last_hours = UNIX_TIMESTAMP(start_time) - UNIX_TIMESTAMP(DATE(start_time));
SET last_day = FROM_UNIXTIME(UNIX_TIMESTAMP(LAST_DAY(start_time)) + last_hours, "%Y-%m-%d %H:%i:%s");
SET new_start =
CASE occurance
WHEN 'daily' THEN DATE_ADD(start_time, INTERVAL 1 DAY)
WHEN 'weekly' THEN DATE_ADD(start_time, INTERVAL 1 WEEK)
WHEN 'monthly' THEN DATE_ADD(start_time, INTERVAL 1 MONTH)
WHEN 'bimonthly' THEN DATE_ADD(start_time, INTERVAL 2 MONTH)
WHEN 'quarterly' THEN DATE_ADD(start_time, INTERVAL 1 QUARTER)
WHEN 'firstof' THEN
CASE
WHEN DATE_ADD(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s'), INTERVAL (7+day_num - WEEKDAY(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s')))%7 DAY) > start_time
THEN DATE_ADD(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s'), INTERVAL (7+day_num - WEEKDAY(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s')))%7 DAY)
ELSE DATE_ADD(DATE_FORMAT(DATE_ADD(start_time, INTERVAL 1 MONTH), '%Y-%m-01 %H:$i:$s'), INTERVAL (7+day_num - WEEKDAY(DATE_FORMAT(DATE_ADD(start_time, INTERVAL 1 MONTH), '%Y-%m-01 %H:$i:$s')))%7 DAY)
END
WHEN 'secondof' THEN
CASE
WHEN DATE_ADD(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s'), INTERVAL (7+day_num - WEEKDAY(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s')))%14 DAY) > start_time
THEN DATE_ADD(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s'), INTERVAL (7+day_num - WEEKDAY(DATE_FORMAT(start_time, '%Y-%m-01 %H:$i:$s')))%14 DAY)
ELSE DATE_ADD(DATE_FORMAT(DATE_ADD(start_time, INTERVAL 1 MONTH), '%Y-%m-01 %H:$i:$s'), INTERVAL (7+day_num - WEEKDAY(DATE_FORMAT(DATE_ADD(start_time, INTERVAL 1 MONTH), '%Y-%m-01 %H:$i:$s')))%14 DAY)
END
WHEN 'lastof' THEN
CASE
WHEN DATE_SUB(last_day, INTERVAL ((WEEKDAY(last_day)+7-day_num))%7 DAY) > start_time
THEN DATE_SUB(last_day, INTERVAL ((WEEKDAY(last_day)+7-day_num))%7 DAY)
ELSE DATE_SUB(DATE_ADD(last_day, INTERVAL 1 MONTH), INTERVAL ((WEEKDAY(DATE_ADD(last_day, INTERVAL 1 MONTH))+7-day_num))%7 DAY)
END
ELSE
start_time
END;
SELECT
new_start,
FROM_UNIXTIME(UNIX_TIMESTAMP(new_start) + time_interval,"%Y-%m-%d %H:%i:%s") AS new_end;
END
PS. excuse my mis-spelling of occurrence.

I think you're looking for this: Can a stored procedure/function return a table?
You have to write the UPDATE statement inside of the procedure...
good luck

Related

To make date changes with if condition in mysql

for this my query is =
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
from `tbl_sales`
WHERE IF((SalesDate = CURDATE() - INTERVAL 1 DAY) = null, SalesDate=CURDATE() - INTERVAL 2 DAY,SalesDate= CURDATE() - INTERVAL 1 DAY)
so this is my response
so in If condition I want to make sure that if the data in yesterday data is null or 0 then it will take day before yesterday
Perhaps something like this:
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
FROM `tbl_sales`
GROUP BY SalesDate
HAVING SalesDate = CASE WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=0
THEN CURDATE() - INTERVAL 2 DAY
WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=1
AND amount IS NULL
THEN CURDATE() - INTERVAL 2 DAY
ELSE CURDATE() - INTERVAL 1 DAY END;
When you do (SalesDate = CURDATE() - INTERVAL 1 DAY) it will return false=0 and true=1. Therefore doing (SalesDate = CURDATE() - INTERVAL 1 DAY) = NULL, although it should be .. IS NULL instead of .. = NULL.. either way, it won't work. Let's inspect the CASE expression in HAVING part.
If it return 0 means there's no matching with date specified, then take 2 days before:
CASE WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=0
THEN CURDATE() - INTERVAL 2 DAY
If it has match for the date checking and return 1 BUT with NULL amount, then take 2 days before as well:
WHEN (SalesDate = CURDATE() - INTERVAL 1 DAY)=1
AND amount IS NULL
THEN CURDATE() - INTERVAL 2 DAY
Else take yesterday date:
ELSE CURDATE() - INTERVAL 1 DAY END;
Demo fiddle
You need to cast your column to date:
SELECT SalesDate,COUNT(Shape) as pcs,
ROUND(SUM(TotalAmount),2) as amount,
ROUND(SUM(Carat),2) as carat,
ROUND(ROUND(SUM(TotalAmount),2)/ROUND(SUM(Carat),2),2) as avgprice
from `tbl_sales`
WHERE IF((CAST(SalesDate AS date) = CURDATE() - INTERVAL 1 DAY), CAST(SalesDate AS date) = CURDATE() - INTERVAL 2 DAY, CAST(SalesDate AS date) = CURDATE() - INTERVAL 1 DAY)

How can i used less than equal or between function FROM DUAL table?

Im trying to get the date from previous week to current and it seemd between or >= are not working here.
WITH curr_cyc_dt AS (
SELECT BETWEEN TO_DATE ('20181228', 'yyyymmdd') AND TO_DATE ('20190104', 'yyyymmdd') cyc_dt
FROM DUAL
)
set #myDate = CURDATE();
set #rowNumber = 0;
select date_sub(#myDate, interval #rowNumber day),
(#rowNumber := #rowNumber + 1) as rownum
from information_schema.columns
LIMIT 7;
BETWEEN does not work like that, it will not automagically generate a list of dates for you. It is a comparison operator that checks if a date belongs to a date interval.
The simplest way to generate a list of days for the last 7 days (until today included) :
WITH curr_cyc_dt AS (
SELECT
CURDATE(),
DATE_SUB(CURDATE(), INTERVAL 1 DAY),
DATE_SUB(CURDATE(), INTERVAL 3 DAY),
DATE_SUB(CURDATE(), INTERVAL 4 DAY),
DATE_SUB(CURDATE(), INTERVAL 5 DAY),
DATE_SUB(CURDATE(), INTERVAL 6 DAY),
DATE_SUB(CURDATE(), INTERVAL 7 DAY)
)
...
PS : FROM DUAL is superfluous in MySQL

Specific date with current_month and previous_month

Is it possible to make the year and month part of the date dynamic (based on current year and month) instead of hard coded?
SELECT SUM(`amount`)
FROM employees
WHERE (`date` between "2018-08-26" and "2018-09-26") AND `status` = 'Pending';
In the above example, if the current month is 9 then the query should be 08-26 and 09-26, if the current month is 10 then 09-26 and 10-26 and so on.
If you want to query data for last month, it's enough to use such query:
SELECT * FROM my_table
WHERE some_datetime_column > DATE_ADD(NOW(), INTERVAL -1 MONTH);
Also, if you want to get current month/year, try this:
SELECT MONTH(NOW()), YEAR(NOW())
Demo
UPDATE
Try this:
--here you specify the day of the month you want
SELECT #days := 26 - DAY(NOW());
SELECT #startDate := DATE_ADD(CAST(NOW() AS DATE), INTERVAL #days DAY),
#endDate := DATE_ADD(DATE_ADD(CAST(NOW() AS DATE), INTERVAL #days DAY), INTERVAL -1 MONTH)
Another demo
Then you can use it like:
SELECT * FROM t
WHERE date_column BETWEEN #startDate AND #endDate
Here is how you can build the desired dates:
SELECT
CURRENT_DATE,
STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), 26), '%Y-%m-%d'),
STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), 26), '%Y-%m-%d') - INTERVAL 1 MONTH
-- 2018-09-25 | 2018-09-26 | 2018-08-26
And use the above in your query:
SELECT SUM(`amount`)
FROM employees
WHERE `date` BETWEEN
STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), 26), '%Y-%m-%d') - INTERVAL 1 MONTH AND
STR_TO_DATE(CONCAT_WS('-', YEAR(CURRENT_DATE), MONTH(CURRENT_DATE), 26), '%Y-%m-%d')
AND `status` = 'Pending';
Try below with now() and last month (DATE_SUB(NOW(), INTERVAL 1 MONTH)):
SELECT SUM(`amount`) FROM employees
WHERE (`date` between DATE_SUB(NOW(), INTERVAL 1 MONTH) and now())
AND `status` = 'Pending';
To Get Current Month use
MONTH(NOW())
To Get Current Year use
YEAR(NOW())
But you don't need these
Use this-
SELECT SUM(`amount`) FROM employees
WHERE (`date` between DATE_ADD(CURDATE(), INTERVAL -1 MONTH) and CURDATE())
AND `status` = 'Pending';
Use CURDATE() to get the current date.
To get same date with previous month use:
DATE_ADD(CURDATE(), INTERVAL -1 MONTH)
As of now on 25/9/2018
SELECT CURDATE()
Output:
2018-09-25
For previous month
SELECT DATE_ADD(CURDATE(), INTERVAL -1 MONTH)
Output:
2018-08-25
Instead of raw query you can use procedure, where it will dynamically create date based on your provided date.
DELIMITER $$
-- Call Get_Sum (15) -- Dynamically you pass the date
DROP PROCEDURE IF EXISTS Get_Sum$$
DELIMITER ;
DELIMITER $$
--
-- Create procedure "Get_Sum"
CREATE DEFINER = 'root'#'localhost'
PROCEDURE Get_Sum(IN Day SMALLINT)
BEGIN
Declare current_month datetime;
Declare previous_month datetime;
Select STR_TO_DATE(CONCAT(year(now()),'-',month(NOW()),'-',Day), '%Y-%m-%d') INTO current_month;
Select DATE_SUB(current_month, INTERVAL 1 MONTH) into previous_month;
SELECT SUM(amount) FROM employees
WHERE (date between previous_month and current_month ) AND status = 'Pending';
END
$$
DELIMITER ;

Im trying to get all the Mondays from today to a certain date...this query works until I add the dayofweek function to it, and then it returns no rows

set #i = -1;
select adddate(curdate(), INTERVAL #i:=#i+1 day) AS ndate, DAYNAME(adddate(curdate(), INTERVAL #i day)) DAYN, dayofweek(adddate(curdate(), INTERVAL #i day)) daynu FROM PayrollDates where dayofweek(adddate(curdate(), INTERVAL #i day)) > 4 and adddate(curdate(), INTERVAL #i-1 day) < '2018-03-01'

Mysql select date having mod result is equal to zero

My Table is
id name reg_date
1 ABC 2018-08-16
2 PQR 2018-08-10
3 LMN 2018-07-27
4 AAA 2018-01-01
5 BBB 2018-08-11
I want to get all user register on seven days interval before of given date. lets suppose I pass '2017-08-17'. Now I want to pass two date ('2017-08-17','2017-08-19'). so I want which date match betwwen this two date. right now mysql query is
SELECT *
FROM myTable
WHERE
MOD(UNIX_TIMESTAMP(DATE('2017-08-17')) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) = 0
Result will be
id name date match_date
2 PQR 2018-08-10 2017-08-17
3 LMN 2018-07-27 2017-08-17
5 BBB 2018-08-11 2017-08-18
If I understand you correctly, you want to find all dates falling on a 7 day boundary of one or more dates within a range. First appreciate that if your date range is 7 days or greater, then all dates in the table will be returned by definition. Not wanting to give you a solution heavily involving dynamic SQL, I instead chose to use an alternative. For each row I compute whether that date would lie on a boundary with a date in your range. If so, then that record is retained and the matching date from the range is displayed. I encourage you to explore the demo below if you are curious about how this query works.
-- assign the bounds of the date range here
-- note that a range of 7 or more days will by definition simply return all records
SET #start_date = '2017-08-18';
SET #end_date = '2017-08-17';
SELECT
t.id,
t.name,
t.reg_date,
CASE WHEN t.mod1 = 0 THEN #start_date
WHEN t.mod2 = 0 AND #end_date <= #start_date - INTERVAL 1 DAY
THEN #start_date - INTERVAL 1 DAY
WHEN t.mod3 = 0 AND #end_date <= #start_date - INTERVAL 2 DAY
THEN #start_date - INTERVAL 2 DAY
WHEN t.mod4 = 0 AND #end_date <= #start_date - INTERVAL 3 DAY
THEN #start_date - INTERVAL 3 DAY
WHEN t.mod5 = 0 AND #end_date <= #start_date - INTERVAL 4 DAY
THEN #start_date - INTERVAL 4 DAY
WHEN t.mod6 = 0 AND #end_date <= #start_date - INTERVAL 5 DAY
THEN #start_date - INTERVAL 5 DAY
WHEN t.mod7 = 0 AND #end_date <= #start_date - INTERVAL 6 DAY
THEN #start_date - INTERVAL 6 DAY
END AS match_date
FROM
(
SELECT
id,
name,
reg_date,
MOD(UNIX_TIMESTAMP(#start_date) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod1,
MOD(UNIX_TIMESTAMP(#start_date - INTERVAL 1 DAY) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod2,
MOD(UNIX_TIMESTAMP(#start_date - INTERVAL 2 DAY) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod3,
MOD(UNIX_TIMESTAMP(#start_date - INTERVAL 3 DAY) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod4,
MOD(UNIX_TIMESTAMP(#start_date - INTERVAL 4 DAY) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod5,
MOD(UNIX_TIMESTAMP(#start_date - INTERVAL 5 DAY) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod6,
MOD(UNIX_TIMESTAMP(#start_date - INTERVAL 6 DAY) -
UNIX_TIMESTAMP(DATE(reg_date)), 7*24*60*60) AS mod7
FROM yourTable
) t
WHERE
t.mod1 = 0 OR
(t.mod2 = 0 AND #end_date <= #start_date - INTERVAL 1 DAY) OR
(t.mod3 = 0 AND #end_date <= #start_date - INTERVAL 2 DAY) OR
(t.mod4 = 0 AND #end_date <= #start_date - INTERVAL 3 DAY) OR
(t.mod5 = 0 AND #end_date <= #start_date - INTERVAL 4 DAY) OR
(t.mod6 = 0 AND #end_date <= #start_date - INTERVAL 5 DAY) OR
(t.mod7 = 0 AND #end_date <= #start_date - INTERVAL 6 DAY)
Demo here:
Rextester
As i understand your question i think you can use BETWEEN keyword.
where columna_name between date1 AND date2