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
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)
I am trying to get records from last one year and upto last date of provious month i.e. not including the current month. Here's my query:
SELECT `customer_id`, `customer_name`, `customer_date`
FROM `customers`
WHERE DATE(`customer_date`) <= (CURDATE() - INTERVAL 1 MONTH)
AND DATE(customer_date) >= (CURDATE() - INTERVAL 12 MONTH)
This query fetches records from 1 May, 2018 to 8 April 2019.
INTERVAL 1 MONTH fetches records 30 days ago. What I need to do something here?
I want to exclude current month records, so query should return records upto 30 April 2019. How do we do that?
You must correctly calculate the first and last days of range with help LAST_DAY() function. For example:
Calculate the first day of the range
SELECT LAST_DAY(CURDATE() - INTERVAL 13 MONTH) + INTERVAL 1 DAY
Output:
2018-05-01
Calculate last day of the range
SELECT LAST_DAY(CURDATE() - INTERVAL 1 MONTH)
Output:
2019-04-30
The full query might look like:
SELECT `customer_id`, `customer_name`, `customer_date`
FROM `customers`
WHERE `customer_date` >= LAST_DAY(CURDATE() - INTERVAL 13 MONTH) + INTERVAL 1 DAY
AND `customer_date` <= SELECT LAST_DAY(CURDATE() - INTERVAL 1 MONTH)
To get data up to the previous month:
where customer_date < curdate() + interval (1 - day(curdate()) day
Why? First note that there is no function call on the customer_date. So, this expression is index-compatible and can use an index.
Second, this structure works both for dates and date/times. That is very handy, because it may not always be obvious if a column has a time component (people are not very good about naming columns to capture this information).
You claim that the "12 months" ago portion works. That doesn't look correct to me. For the complete logic:
where customer_date < curdate() + interval (1 - day(curdate()) day and
customer_date >= (curdate() + interval (1 - day(curdate()) day) - interval 1 year)
SELECT `customer_id`, `customer_name`, `customer_date` FROM `customers` WHERE
MONTH(`customer_date`) <= (CURDATE() - INTERVAL 1 MONTH) AND
MONTH(customer_date) >= (CURDATE() - INTERVAL 12 MONTH)
hope this help
I'm trying to return rows between yesterday 15:00 and today 07:30, but can't seem to get it work.
I've tried the following two methods, but they haven't worked.
Note:
Getdate() should be CURDATE() in MySQL
TIMESERIAL is denied to my user account in the database
Code Examples:
where dateadd(dd, datediff(dd,0,Getdate()),0)- 1
and dateadd(dd, datediff(dd,0,Getdate()),0)- 1) + '23:59:59'
where [Table].[Date Time] Between Date()-1 + TimeSerial(18,0,0)
And Date() + TimeSerial(18,0,0)
you need to use the DATE_ADD and then INTERVAL n HOUR OR MINUTE.
Please check the attached fiddle. http://rextester.com/JIXU4144
select DATE_ADD(current_date, INTERVAL -9 HOUR);
select DATE_ADD(current_date, INTERVAL 450 minute);
select * from temp
where createdOn between '2018-08-28 15:00:00' and '2018-08-29 07:30:00';
select * from temp
where createdOn between DATE_ADD(current_date, INTERVAL -9 HOUR) and DATE_ADD(current_date, INTERVAL 450 minute)
If you are using MySQL, you can do:
where col >= curdate() - interval 1 day + interval 15 hour and
col < curdate() + interval 7.5 * 60 minute
You can also write this a bit more readably as:
where col >= curdate() - interval 1 day + interval 15 hour and
col < curdate() + interval '7:30' hour_minute
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)
I want to get data for the dates between 2015-05-01 and 2015-06-01 using SQL.
Please help me with the query.
The query I used is:
select *,count(id) as multiple_visitors
from table1
where id=123
and (date(server_time) between (CURDATE() - INTERVAL 31 DAY) AND CURDATE())
group by user_id having count(id)>1
You can do this with month() and year():
where month(server_time) = month(curdate() - interval 1 month) and
year(server_time) = year(curdate() - interval 1 month)
However, I recommend a slightly more complex expression:
where server_time >= date_sub(date_sub(curdate(), interval - day(curdate()) + 1 day), interval 1 month) and
server_time < date_sub(curdate(), interval - day(curdate()) + 1 day)
The advantage is that there are no functions on server_time, so the database engine can use an index, if appropriate.
As a note: the expression date_sub(curdate(), interval - day(curdate()) + 1 day) gets midnight on the first day of the month.
Try using "WHERE" with MONTH(date).
Like this:
SELECT * FROM Table
WHERE MONTH(date) = 1