Mysql select date having mod result is equal to zero - mysql

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

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)

Select rows from 6 am to 6 am

Help create a query that will select records from the table for the past period from 6AM until 6AM, the table has a timestamp field.
I will explain, for example:
Now: 2019-06-15 04:44:42
Period: 2019-06-13 06:00:00 - 2019-06-14 06:00:00
Now: 2019-06-15 07:44:42
Period: 2019-06-14 06:00:00 - 2019-06-15 06:00:00
Now: 2019-06-16 01:44:42
Period: 2019-06-14 06:00:00 - 2019-06-15 06:00:00
I think I was not the easiest request:
SELECT * FROM `table` WHERE `timestamp`
BETWEEN
DATE_ADD(DATE(NOW() - INTERVAL '1 6' DAY_HOUR), INTERVAL 6 HOUR)
AND
DATE_ADD(DATE(NOW() - INTERVAL '0 6' DAY_HOUR), INTERVAL 6 HOUR);
How simpler?
You can get the upper range limit with:
date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR
The lower limit would be exactly one day (24 hours) earlier:
date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR - INTERVAL 1 day
So your query could be:
SELECT *
FROM `table` t
WHERE t.timestamp >= date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR - INTERVAL 1 day
AND t.timestamp < date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR
But to avoid code duplication I would rewrite it to:
SELECT t.*
FROM `table` t
CROSS JOIN (
SELECT date(now() - INTERVAL 6 HOUR) + INTERVAL 6 HOUR as upper_limit
) r -- r for "range"
WHERE t.timestamp >= r.upper_limit - INTERVAL 1 day
AND t.timestamp < r.upper_limit
You can though use <= r.upper_limit instead of < r.upper_limit to get the same result as with BETWEEN.
SELECT start, start +interval 24 hour end
FROM ( SELECT date(now())
- interval if(hour(now())>6, 1, 2) day
+ interval 6 hour
as start
) dates;

Number of Working Days between two dates[LOGIC]

I have a function is MySql which calculates the number of working dates between two given dates but I would like to know the logic that is being used in it.
The sql function is as follows:
CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
- (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);
ABS(DATEDIFF(date2, date1)) + 1
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
- (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7)
;
ABS is used throughout to ensure each result is a positive integer, in case the dates are backward (if the start point is after the end point).
ABS(DATEDIFF(date2, date1)) + 1
DATEDIFF returns the integer number of calendar days between the dates of 2 datetime values (in effect setting time to 00:00:00+00000 on both dates). Because DATEDIFF uses date only the duration of the second day is lost, so add 1 to compensate.
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
Calculate the start of the week for both dates using ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY) and ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY) and then get the number of days between those dates. Divide that number by 7 gives the number of weeks spanned between the dates. Multiply that number by 2 gives number of weekend days involved in the span. Subtract those weekend days from the raw number of days previously calculated gives the overall number of weekdays between the dates.
However the given start/end datetimes may individually fall on a weekend day, so:
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
If one of the given dates is a Sunday, subtract 1
- (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7)
If one of the given dates is a Saturday, subtract 1
Resulting in the number of "workdays" where the workweek excludes Saturday & Sunday.
In case it is of interest, here is a query that breaks out each function or set of function calls as individual columns so you can trace each. Adjust the subquery supplying 2 dates to suit.
select
date1
, date2
, DATEDIFF(date2, date1) "datediff"
, ABS(DATEDIFF(date2, date1)) abs_datediff
, ABS(DATEDIFF(date2, date1)) + 1 diff_2end_dt
, DAYOFWEEK(date2) dt2_dow
, ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY) start_of_wk_dt2
, DAYOFWEEK(date1) dt1_dow
, ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY) start_of_wk_dt1
, DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY)) diff_wksby7
, ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) abs_diff_wksby7
, ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2 diff_wkends
, DAYOFWEEK(IF(date1 < date2, date1, date2)) dow_min
, DAYOFWEEK(IF(date1 > date2, date1, date2)) dow_max
from (
select date_add(now(), INTERVAL -34 DAY) as date1, date_add(now(), INTERVAL -2 DAY) as date2
) d

Average time between two datetimes for this month and last month

We have a table with two fields tkTimeOpen and tkTimeClosed. We need to find the average wait time for this month and last month. I've been unable to get the right SQL query to pull out what I need.
This is how the date-time is recorded; 2017-01-25 10:35
This Month's Average;
SELECT SUM(DATEDIFF(MINUTE,tkTimeOpen,tkTimeClose)) * 1.0
/ (SELECT COUNT(*) * 1.0 FROM e_ticket)
FROM e_ticket
WHERE YEAR(tkTimeOpen) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH) AND MONTH(tkTimeOpen) = MONTH(CURRENT_DATE - INTERVAL 0 MONTH)
Last Month's Average
SELECT SUM(DATEDIFF(MINUTE,tkTimeOpen,tkTimeClose)) * 1.0
/ (SELECT COUNT(*) * 1.0 FROM e_ticket)
FROM e_ticket
WHERE YEAR(tkTimeOpen) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH) AND MONTH(tkTimeOpen) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)
I've tried a lot of variations but it doesn't give the desired output.
If anyone could help that would be great!
Thank you
This should give you the average minutes for last month and this month combined:
SELECT AVG(TIMESTAMPDIFF(MINUTE, tkTimeOpen, tkTimeClose))
FROM e_ticket
WHERE tkTimeOpen >= DATE_ADD(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH)), INTERVAL 1 DAY);
If you still need to get the averages separately, you can keep your WHERE clause similar to what you have...
For this month:
SELECT AVG(TIMESTAMPDIFF(MINUTE, tkTimeOpen, tkTimeClose))
FROM e_ticket
WHERE YEAR(tkTimeOpen) = YEAR(NOW()) AND MONTH(tkTimeOpen) = MONTH(NOW());
And for last month:
SELECT AVG(TIMESTAMPDIFF(MINUTE, tkTimeOpen, tkTimeClose))
FROM e_ticket
WHERE YEAR(tkTimeOpen) = YEAR(NOW() - INTERVAL 1 MONTH) AND MONTH(tkTimeOpen) = MONTH(NOW() - INTERVAL 1 MONTH);
One function you could use is TIMESTAMPDIFF - not DATEDIFF
You can use AVG() instead of SUM() / COUNT()
SELECT AVG(TIMESTAMPDIFF(MINUTE,tkTimeOpen,tkTimeClose))
FROM e_ticket
WHERE YEAR(tkTimeOpen) = YEAR(CURRENT_DATE - INTERVAL 1 MONTH)
AND MONTH(tkTimeOpen) = MONTH(CURRENT_DATE - INTERVAL 1 MONTH)

Update using a procedure in 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