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
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)
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
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 ;
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'
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