SQL Query between a date range and a time range in MariaDB - mysql

I'm having trouble writing this query to give me any results. I'm using MariaDB as well.
SELECT CallDate AS Week_Of, AgentName,
COUNT(*) AS TOTAL_Calls,
SUM(case when Accepted = 'ANSWERED' then 1 ELSE 0 END) AS Answered,
SUM(case when Accepted = 'NO ANSWER' then 1 ELSE 0 end) AS NoAnswer
FROM jshou_custom.afterhours
WHERE CallDate >= DATE_ADD(NOW(), INTERVAL -1 WEEK)
AND TIME(CallDate) BETWEEN '17:00:00' AND '08:00:00'
GROUP BY AgentName
The DATE_ADD clause works just fine and gives results within that interval, but as soon as I add in the TIME function nothing is returned in the results. The CallDate format is 2021-09-21 HH:MM:SS I have tried using HOUR as well in place of TIME, but it also returns nothing.
I'm trying to pull calls from any day within the range specified in the DATE_ADD clause. As long as it's between 1700 and 0800 (after hours calls).

I think you need to check both dates something like this and adjust the times used on each date as well
WHERE
(CallDate > DATE_ADD(CURDATE(), INTERVAL -7 DAY) AND TIME(CallDate) > '17:00:00')
OR
(CallDate > DATE_ADD(CURDATE(), INTERVAL -6 DAY) AND TIME(CallDate) < '08:00:00')

Related

how to get weeklytotal and yesterday record in mysql in one table

Hi Everyone i am trying to implement query to get weekly and yesterday data in same table,
dummy output i have shared below, if yesterday not exist as per employee_id it should we showing 0 also as per my table week start from monday and end at sunday.please help me out how to query this get weekly_total and yesterday record and one table.
Table name-dailydata-
Sample data
employee_id
date
total
20
2022-04-25
10
20
2022-04-26
20
20
2022-04-27
20
20
2022-04-28
10
20
2022-04-29
20
20
2022-04-30
30
20
2022-04-31
40
20
2022-05-01
50
40
2022-04-26
20
expected output
employee_id
weekly_total
yesterday_record
20
200
40
40
20
0
mysql query to get weekly data
select employee_id,sum(total) as week_total from dailydata where date between '2022-04-25' and '2022-05-01'
You can try to use the condition aggregate function to make it.
We might add non-aggregate columns in the group by when we are using aggregate functions.
select employee_id,
SUM(total) as week_total,
SUM(CASE WHEN DATEDIFF('2022-05-01',date) = 1 THEN total ELSE 0 END) yesterday_record
from dailydata t1
where date between '2022-04-25' and '2022-05-01'
GROUP BY employee_id
You can use a case in the query to get yesterdays data, as long as the where does not exclude it, which is the case in the second query.
Once you have understood the principal you can define the date range so that it is calculated dynamically when you run the script if what you want is to see yesterday's figure and the last 7 days total.
You can also get yesterday using SUBDATE(NOW(),1) which is shorter.
select
employee_id,
sum(total) as week_total ,
sum(case when date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
then total else 0 end as yesterday
from dailydata
where date between
DATE_SUB(CURDATE(), INTERVAL 1 WEEK)
and DATE_SUB(CURDATE(), INTERVAL 1 DAY) ;
select
employee_id,
sum(total) as week_total ,
sum(case when date = DATE_SUB(CURDATE(), INTERVAL 1 DAY)
then total else 0 end as yesterday
from dailydata
where date between '2022-04-25' and '2022-05-01';
Hope this may help you, You just need to use the aggregate function in the case of IFNULL.
DBFiddle URL: Click Here
For the start of the week
SELECT SUBDATE(CURDATE(), weekday(CURDATE())); --Start of week
For the end of the week
SELECT DATE(CURDATE() + INTERVAL (6 - WEEKDAY(CURDATE())) DAY); --End of week
Hereby SQL query for getting employe wise total and yesterday total. If yesterday's total doesn't exist so for that Have used IFNULL. Just used SUBDATE for getting the start and end of the week date by passing current date.
SELECT employee_id,
IFNULL(SUM(total),0) AS total,
IFNULL(SUM(CASE date WHEN subdate(CURDATE(), 1) THEN total ELSE 0 END),0) AS yesterday_total
FROM dailydata
WHERE date BETWEEN
SUBDATE(CURDATE(), weekday(CURDATE())) AND (CURDATE() + INTERVAL (6 - WEEKDAY(CURDATE())) DAY)
GROUP BY employee_id
Start of this week:
SELECT DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0)
End of this week:
SELECT DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 6)
Yesterday:
select GETDATE() -1
Your query:
select
employee_id,
sum(total) as week_total,
(select sum(total) as week_total
from dailydata b
where [date] = convert(date, getdate() -1 )
and a.employee_id = b.employee_id) as yesterday_record
from
dailydata a
where
[date] between dateadd(wk, datediff(wk, 0, getdate()), 0) and dateadd(wk, datediff(wk, 0, getdate()), 6)
group by
employee_id

MySQL query that returns all records from "first day" of the current month & year?

Need to return all records from "first day" of the current month & year? (ex.. need all 11/01 records)
Something like this:
(YEAR(INVOICE_DATE) = YEAR(NOW())
AND
(DAY(INVOICE_DATE) = “Current Month 11/01”
PS: I need the Year & Day values to be dynamic in the query.
INVOICE_DATE is a Date/Time type
Something like this would work:
SELECT *
FROM table
WHERE CONCAT(
YEAR(dateColumn),
MONTH(dateColumn),
'01'
) = CONCAT(
YEAR(NOW()),
MONTH(NOW()),
'01'
)
My preference would be to reference the bare column, which will allow MySQL to make use of a range scan operation with a suitable index
FROM t
WHERE t.invoice_date >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 DAY
AND t.invoice_date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 DAY
We can test the expressions (on the right side of the comparison operators), in a SELECT statement
SELECT DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 DAY AS bdt
, DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 DAY AS edt
return:
bdt edt
---------- ----------
2019-11-01 2019-11-02
and see that the net effect is the same as if we had written:
FROM t
WHERE t.invoice_date >= '2019-11-01 00:00:00'
AND t.invoice_date < '2019-11-02 00:00:00'
FOLLOWUP
Q: When I tried it, it returned 0 records? It might be the "TIME" portion of my DATE/TIME field that is causing it not to match/return any records?
A: Doing the comparisons as shown in the query above, with datetime greater than or equal to midnight of the first, and datetime less than midnight of the second, that should return datetime values anytime on the first.
datetime values like this would satisfy the condition: '2019-11-01 08:15', '2019-11-01 16:20', etc.
We can verify with simple test. We expect two of these datatime values to be returned, and the third to be excluded:
demonstration:
SELECT t.*
FROM ( SELECT '2019-11-01 08:15' + INTERVAL 0 DAY AS invoice_date
UNION ALL SELECT '2019-11-01 16:20' + INTERVAL 0 DAY
UNION ALL SELECT '2019-11-02 00:00' + INTERVAL 0 DAY
) t
WHERE t.invoice_date >= DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 0 DAY
AND t.invoice_date < DATE_FORMAT(NOW(),'%Y-%m-01') + INTERVAL 1 DAY
returns:
invoice_date
-------------------
2019-11-01 08:15:00
2019-11-01 16:20:00
Before we muck with expressions to generate the date boundary values, we should test with literals, e.g. '2019-11-02'.
FROM t
WHERE t.invoice_date >= '2019-11-01' + INTERVAL 0 DAY
AND t.invoice_date < '2019-11-02' + INTERVAL 0 DAY
Once we get that working, then we can work on developing expressions to replace the literals.

MySQL 5.6 Selecting months and days

I am struggling to understand the date functions of MySQL.
For example, I want to get all records of this month and the previous month.
From what I understand I'm supposed to use MONTH(NOW()) which returns the integer of the current month and MONTH(NOW())-1 for the previous month. Except when asking for a date in January, this will obviously will not work as it's performed on the result of the function instead of wrapping around and going to December of the previous year.
How would I go about writing a generic function that would work on January too? Since months have varying lengths it wouldn't be possible to subtract a month in milliseconds from NOW() I recon.
For example, this query works fine except on January:
SELECT
SUM(CASE WHEN MONTH(table_date) = MONTH(NOW())-1 THEN 1 ELSE 0 END) AS LAST_MONTH,
SUM(CASE WHEN MONTH(table_date) = MONTH(NOW()) THEN 1 ELSE 0 END) AS THIS_MONTH
FROM table
WHERE table_date BETWEEN Date_add(NOW(), interval - 1 month) AND NOW()
A similar issue arises with DAY() function since months have varying lengths and writing statements for each and every day doesn't seem very efficient.
What is a more efficient way of selecting the records for each day of any month of interest, regardless of whether that specific day actually has records?
You are vulnerable to pulling records from all years not only the current one stored within table_date. To get rid of it you need to operate on the year as well which can be done by always calculating on the proper date format YYYY-MM-DD not to lose precision.
Here are some calculations used to build up final query.
First day of month:
SELECT DATE_FORMAT(table_date, '%Y-%m-01') FROM table
First day of previous month:
SELECT DATE_FORMAT(DATE_SUB(table_date, INTERVAL 1 MONTH), '%Y-%m-01') FROM table
Last day of month:
SELECT LAST_DAY(table_date) FROM table
Last day of previous month:
SELECT LAST_DAY(DATE_SUB(table_date, INTERVAL 1 MONTH)) FROM table
Your final query:
SELECT
SUM(CASE WHEN table_date BETWEEN DATE_FORMAT(table_date, '%Y-%m-01') AND LAST_DAY(table_date) THEN 1 END) AS this_month,
SUM(CASE WHEN table_date BETWEEN DATE_FORMAT(DATE_SUB(table_date, INTERVAL 1 MONTH), '%Y-%m-01') AND LAST_DAY(DATE_SUB(table_date, INTERVAL 1 MONTH)) THEN 1 END) AS last_month
FROM table
WHERE
table_date BETWEEN
DATE_FORMAT(DATE_SUB(table_date, INTERVAL 1 MONTH), '%Y-%m-01')
AND LAST_DAY(table_date)
Note: In the case expression I've omitted ELSE 0 since default statement for ELSE in CASE is null and SUM() ignores null values :-)
Your logic is not safe also for dates from other years.
The way to achieve what you want might be to truncate the dates to the first of the month, e.g. (for replaced NOW with 2013-01-20)
select table_date,
case when date_format(table_date, '%Y-%m-01')
= date_format('2013-01-20', '%Y-%m-01') then 1 end AS THIS_MONTH,
case when date_format(table_date, '%Y-%m-01')
= date_add(date_format('2013-01-20', '%Y-%m-01'), interval -1 month) then 1 end AS LAST_MONTH
from x;
See this SqlFiddle
Your logic converts the date into integer then subtracts 1 from it. For days and month like January, the value becomes 1. From which if you subtract 1, it becomes zero, which is not a valid date or month.
For month try this: sum(case when month(table_date) = month(date_sub(curdate(), interval 1 month)) then 1 else 0 end) as last_month.
You can use similar logic for days
Can you please try with this :
SELECT table_date,
SUM(CASE WHEN (LEFT(table_date, 7) = LEFT(NOW(),7)) THEN
1
ELSE 0 END) AS THIS_MONTH,
SUM(CASE WHEN
(LEFT(table_date, 7) = LEFT(DATE_SUB(NOW(), INTERVAL 1 MONTH),7)) THEN
1 ELSE 0 END) AS LAST_MONTH
FROM table
WHERE LEFT(table_date, 7) BETWEEN LEFT(DATE_SUB(NOW(), INTERVAL 1 MONTH),7)
AND LEFT(NOW(),7)

MySQL: search orders made since yesterday 3pm till today 4pm

I have table ORDERS where is stored data about orders with their status and the date of order. I would like to search all orders with specified status and which was made yesterday after 3pm untill today 4pm. The query will run in different times (10am, 3pm, 5 pm... regardless).
So on example: if I run the query today (13.05.2014) I would like to get all orders made from 2014-12-05 15:00:00 untill 13-05-2015 16:00:00
The date is stored in format: YYYY-MM-DD HH:MM:SS
What I got is:
select *
from orders
where status = 'new'
and (
(
date_add(created_at, INTERVAL 1 day) = CURRENT_DATE()
and hour(created_at) >= 15
) /*1*/
or (
date(created_at) = CURRENT_DATE()
and hour(created_at) <= 16
) /*2*/
)
And I get only orders made today - like only the 2nd condition was taken into account.
I prefer not to use created >= '2014-05-12 16:00:00' (I will not use this query, someone else will).
When you add an interval of 1 day to the date/time, you still keep the time component. Use date() for the first condition:
where status = 'new' and
((date(date_add(created_at, INTERVAL 1 day)) = CURRENT_DATE() and
hour(created_at) >= 15
) /*1*/ or
(date(created_at) = CURRENT_DATE() and
hour(created_at) <= 16
) /*2*/
)
And alternative method is:
where status = 'new' and
(created_at >= date_add(CURRENT_DATE(), interval 15-24 hour) and
created_at <= date_add(CURRENT_DATE(), interval 16 hour)
)
The advantage of this approach is that all functions are moved to CURRENT_DATE(). This would allow MYSQL to take advantage of an index on created_at.

How do I select between the 1st day of the current month and current day in MySQL?

I need to select data from MySQL database between the 1st day of the current month and current day.
select*from table_name
where date between "1st day of current month" and "current day"
Can someone provide working example of this query?
select * from table_name
where (date between DATE_ADD(LAST_DAY(DATE_SUB(CURDATE(), interval 30 day), interval 1 day) AND CURDATE() )
Or better :
select * from table_name
where (date between DATE_FORMAT(NOW() ,'%Y-%m-01') AND NOW() )
I was looking for a similar query where I needed to use the first day of a month in my query.
The last_day function didn't work for me but DAYOFMONTH came in handy.
So if anyone is looking for the same issue, the following code returns the date for first day of the current month.
SELECT DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY);
Comparing a date column with the first day of the month :
select * from table_name where date between
DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY) and CURRENT_DATE
select * from table_name
where `date` between curdate() - dayofmonth(curdate()) + 1
and curdate()
SQLFiddle example
I have used the following query. It has worked great for me in the past.
select date(now()) - interval day(now()) day + interval 1 day
try this :
SET #StartDate = DATE_SUB(DATE(NOW()),INTERVAL (DAY(NOW())-1) DAY);
SET #EndDate = ADDDATE(CURDATE(),1);
select * from table where (date >= #StartDate and date < #EndDate);
Complete solution for mysql current month and current year, which makes use of indexing properly as well :)
-- Current month
SELECT id, timestampfield
FROM table1
WHERE timestampfield >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFMONTH(CURRENT_DATE)-1 DAY)
AND timestampfield <= LAST_DAY(CURRENT_DATE);
-- Current year
SELECT id, timestampfield
FROM table1
WHERE timestampfield >= DATE_SUB(CURRENT_DATE, INTERVAL DAYOFYEAR(CURRENT_DATE)-1 DAY)
AND timestampfield <= LAST_DAY(CURRENT_DATE);
select * from table
where date between
(date_add (CURRENT_DATE, INTERVAL(1 - DAYOFMonth(CURRENT_DATE)) day)) and current_date;
select * from <table>
where <dateValue> between last_day(curdate() - interval 1 month + interval 1 day)
and curdate();
I found myself here after needing this same query for some Business Intelligence Queries I'm running on an e-commerce store. I wanted to add my solution as it may be helpful to others.
set #firstOfLastLastMonth = DATE_SUB(LAST_DAY(DATE_ADD(NOW(), INTERVAL -2 MONTH)),INTERVAL DAY(LAST_DAY(DATE_ADD(NOW(), INTERVAL -2 MONTH)))-1 DAY);
set #lastOfLastLastMonth = LAST_DAY(DATE_ADD(NOW(), INTERVAL -2 MONTH));
set #firstOfLastMonth = DATE_SUB(LAST_DAY(DATE_ADD(NOW(), INTERVAL -1 MONTH)),INTERVAL DAY(LAST_DAY(DATE_ADD(NOW(), INTERVAL -1 MONTH)))-1 DAY);
set #lastOfLastMonth = LAST_DAY(DATE_ADD(NOW(), INTERVAL -1 MONTH));
set #firstOfMonth = DATE_ADD(#lastOfLastMonth, INTERVAL 1 DAY);
set #today = CURRENT_DATE;
Today is 2019-10-08 so the output looks like
#firstOfLastLastMonth = '2019-08-01'
#lastOfLastLastMonth = '2019-08-31'
#firstOfLastMonth = '2019-09-01'
#lastOfLastMonth = '2019-09-30'
#firstOfMonth = '2019-10-01'
#today = '2019-10-08'
A less orthodox approach might be
SELECT * FROM table_name
WHERE LEFT(table_name.date, 7) = LEFT(CURDATE(), 7)
AND table_name.date <= CURDATE();
as a date being between the first of a month and now is equivalent to a date being in this month, and before now. I do feel that this is a bit easier on the eyes than some other approaches, though.
SELECT date_sub(current_date(),interval dayofmonth(current_date())-1 day) as first_day_of_month;
I had some what similar requirement - to find first day of the month but based on year end month selected by user in their profile page.
Problem statement - find all the txns done by the user in his/her financial year. Financial year is determined using year end month value where month can be any valid month - 1 for Jan, 2 for Feb, 3 for Mar,....12 for Dec.
For some clients financial year ends on March and some observe it on December.
Scenarios - (Today is `08 Aug, 2018`)
1. If `financial year` ends on `July` then query should return `01 Aug 2018`.
2. If `financial year` ends on `December` then query should return `01 January 2018`.
3. If `financial year` ends on `March` then query should return `01 April 2018`.
4. If `financial year` ends on `September` then query should return `01 October 2017`.
And, finally below is the query. -
select #date := (case when ? >= month(now())
then date_format((subdate(subdate(now(), interval (12 - ? + month(now()) - 1) month), interval day(now()) - 2 day)) ,'%Y-%m-01')
else date_format((subdate(now(), interval month(now()) - ? - 1 month)), '%Y-%m-01') end)
where ? is year end month (values from 1 to 12).
The key here is to get the first day of the month. For that, there are several options. In terms of performance, our tests show that there isn't a significant difference between them - we wrote a whole blog article on the topic. Our findings show that what really matters is whether you need the result to be VARCHAR, DATETIME, or DATE.
The fastest solution to the real problem of getting the first day of the month returns VARCHAR:
SELECT CONCAT(LEFT(CURRENT_DATE, 7), '-01') AS first_day_of_month;
The second fastest solution gives a DATETIME result - this runs about 3x slower than the previous:
SELECT TIMESTAMP(CONCAT(LEFT(CURRENT_DATE, 7), '-01')) AS first_day_of_month;
The slowest solutions return DATE objects. Don't believe me? Run this SQL Fiddle and see for yourself 😊
In your case, since you need to compare the value with other DATE values in your table, it doesn't really matter what methodology you use because MySQL will do the conversion implicitly even if your formula doesn't return a DATE object.
So really, take your pick. Which is most readable for you? I'd pick the first since it's the shortest and arguably the simplest:
SELECT * FROM table_name
WHERE date BETWEEN CONCAT(LEFT(CURRENT_DATE, 7), '-01') AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN DATE(CONCAT(LEFT(CURRENT_DATE, 7), '-01')) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN (LAST_DAY(CURRENT_DATE) + INTERVAL 1 DAY - INTERVAL 1 MONTH) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN (DATE(CURRENT_DATE) - INTERVAL (DAYOFMONTH(CURRENT_DATE) - 1) DAY) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN (DATE(CURRENT_DATE) - INTERVAL (DAYOFMONTH(CURRENT_DATE)) DAY + INTERVAL 1 DAY) AND CURDATE;
SELECT * FROM table_name
WHERE date BETWEEN DATE_FORMAT(CURRENT_DATE,'%Y-%m-01') AND CURDATE;
I used this one
select DATE_ADD(DATE_SUB(LAST_DAY(now()), INTERVAL 1 MONTH),INTERVAL 1 day) first_day
,LAST_DAY(now()) last_day, date(now()) today_day
All the responses here have been way too complex. You know that the first of the current month is the current date but with 01 as the date. You can just use YEAR() and MONTH() to build the month date by inputting the NOW() method.
Here's the solution:
select * from table_name
where date between CONCAT_WS('-', YEAR( NOW() ), MONTH( NOW() ), '01') and DATE( NOW() )
CONCAT_WS() joins a series of strings with a separator (a dash in this case).
So if today is 2020-08-28, YEAR( NOW() ) = '2020' and MONTH( NOW() ) = '08' and then you just need to append '01' at the end.
Voila!
Get first date and last date from month and year.
select LAST_DAY(CONCAT(year,'.',month,'.','01')) as registerDate from user;
select date_add(date_add(LAST_DAY(end_date),interval 1 DAY),interval -1 MONTH) AS closingDate from user;
SET #date:='2012-07-11';
SELECT date_add(date_add(LAST_DAY(#date),interval 1 DAY),
interval -1 MONTH) AS first_day