MySQL results yesterday, last week, last month and last year - mysql

my datefield (artists.onlineDate) is yyy-mm-dd hh:mm:ss
right now I got:
-- Today
SELECT * FROM artists WHERE DATE(artists.onlineDate) = CURDATE()
-- Current Week
SELECT * FROM artists WHERE WEEK(artists.onlineDate, 3) = WEEK(CURDATE(), 3)
-- Current Month
SELECT * FROM artists WHERE MONTH(artists.onlineDate) = MONTH(CURDATE())
-- Current Year
SELECT * FROM artists WHERE YEAR(artists.onlineDate) = YEAR(CURDATE())
But what I need is exact: Yesterday, Last Week, Last Month, Last Year
I try to explain. if we got wednesday, and I use SELECT * FROM artists WHERE DATE(artists.onlineDate) = CURDATE(), then I get monday to wednesday.
I would like to have the monday to sunday of the last week. the calendar week before.
And the same for the month and year.
I thins SUB_DATE is not the right way.
Any suggestions?

OK I found what I was looking for at:
MySQL Query to select data from last week?
SELECT * FROM testwoche
WHERE WEEK (datum, 3) = WEEK(current_date, 3) - 1
AND YEAR(datum) = YEAR(current_date) ORDER BY datum DESC
same for month
SELECT * FROM testwoche
WHERE month (datum) = month(current_date) - 1
AND YEAR(datum) = YEAR(current_date)
ORDER BY datum DESC
This gives back the last week from monday to sunday and the last month
Thanks everybody for helping!

I think you can use the SUBTIME function: https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_subtime
I haven't had time to really test it, but I think you get the idea:
Yesterday:
SELECT * FROM artists WHERE DATE(artists.onlineDate) = SUBTIME(CURDATE(),'1 0:0:0');
Last Week
SELECT * FROM artists WHERE WEEK(artists.onlineDate, 3) = WEEK(SUBTIME(CURDATE(),'7 0:0:0'), 3)
Last Month
SELECT * FROM artists WHERE MONTH(artists.onlineDate) = MONTH(SUBTIME(CURDATE(),'31 0:0:0'))
Last Year
SELECT * FROM artists WHERE YEAR(artists.onlineDate) = YEAR(SUBTIME(CURDATE(),'365 0:0:0'))

To get a specific week/month/year (which still works when your db contains several years worth of data and when your current time is the start of a new year), this should work:
SELECT * FROM testwoche WHERE
((YEAR(CURDATE())-YEAR(datum)))*52-WEEK(datum,3)+WEEK(CURDATE(),3) = 1;
If you want two weeks ago, you could change it to =2 (if you want current week, from Monday to current day: =0). If you want last month, you change the WEEK function to MONTH.

Related

Getting Data from current Year till date

I have the query where i am getting the data but one year back till now,
select * from tblorders
where CreatedDateTime >= DATE_SUB(NOW(),INTERVAL 1 YEAR);
how can i get the data from the start of the current year till date data
start of the current year like 01/01/2021
select * from tblorders
where ( CreatedDateTime between DATE_FORMAT(NOW() ,'%Y-01-01') AND NOW() )
This would return from the beginning of the current year till current date
How about
select * from tblorders
where YEAR(CreatedDateTime) = YEAR(NOW());
DBFiddle: https://www.db-fiddle.com/f/d7h2raMmvxngn1uigPjoB5/0

SQL condition date

From this database, I want to select those data which payment_date is current month but the service_date is any month except this month.
Database sample
One way to check if 2 dates are in the same month is with the use of the function last_day(), because if for 2 dates the last day of their month is the same then they are in the same month:
select *
from tablename
where last_day(payment_date) = last_day(curdate())
and last_day(service_date) <> last_day(curdate())
If you want the results for any month and not for the current month only:
select *
from tablename
where last_day(payment_date) <> last_day(service_date)

How to group mysql results in weeks

I have a table like this:
I need to sum how many messages were delivered per msisdn in last 8 weeks(but for each week) from date entered. Here is what I came up with:
SELECT count(*) as ukupan_broj, SUM(IF (sent_messages.delivered = 1,1,0 )) as broj_dostavljenih,
count(*) - SUM(IF (sent_messages.delivered = 1,1,0 )) as non_billed,
SUM(IF (sent_messages.delivered = 1,1,0 )) / count(*) as ratio,
`sent_messages`.`msisdn`,
MONTH(`sent_messages`.`datetime`) AS MONTH, WEEK(`sent_messages`.`datetime`) AS WEEK,
DATE_FORMAT(`sent_messages`.`datetime`, '%Y-%m-%d') AS DATE
FROM `sent_messages`
INNER JOIN `received_messages` on `received_messages`.`uniqueid`=`sent_messages`.`originalID`
and `received_messages`.`msisdn`=`sent_messages`.`msisdn`
WHERE `sent_messages`.`datetime` >= '2016-12-12'
AND `sent_messages`.`originalID` = `received_messages`.`uniqueid`
AND `sent_messages`.`datetime` <= '2017-12-30'
AND `sent_messages`.`datetime` >= `received_messages`.`datetime`
AND `sent_messages`.`datetime` <= ( `received_messages`.`datetime` + INTERVAL 2 HOUR )
AND `sent_messages`.`type` = 'PAID'
GROUP BY WEEK
ORDER BY DATE ASC
And because I'm grouping it by WEEK, my result is showing sum of all delivered, undelivered etc. but not per msisdn. Here is how result looks like:
And when I add msisdn in GROUP BY clause I don't get the result the way I need it.
And I need it like this:
Please help me to write optimized query to fetch these results for each msisdn per last 8 weeks, because I'm stuck.
WEEK(...) has a problem near the first of the year. Instead, you could use TO_DAYS:
WHERE datetime > CURDATE() - INTERVAL 8 WEEK -- for the last 8 weeks
GROUP BY MOD(TO_DAYS(datetime), 7) -- group by week
That is quite simple, but there is a bug in it. It only works if today is the last day of a "week". And if date%7 lands on the desired day of week.
WHERE datetime > CURDATE() - INTERVAL 9 WEEK -- for the last 8 weeks
GROUP BY MOD(TO_DAYS(datetime) - 3, 7) -- group by week
Is the first cut at fixing the bugs -- 9-week interval will include the current partial week and the partial week 8 weeks ago. The "- 3" (or whatever number works) will align your "week" to start on Monday or Sunday or whatever.
SUM(IF (sent_messages.delivered = 1,1,0 )) can be shortened to SUM(delivered = 1) or even SUM(delivered) if that column only has 0 or 1 values.

Query that displays rows in a range of date with day, month and year

I have the following columns in my table Log:
year, month, day, info
I need a query that selects the rows in a range of date determined by the user. The user will select the initial day, month and year and also the final day, month and year. At the moment, my query is:
SELECT
CONCAT(LPAD(`day`,2, 0),'/',LPAD(`month`,2, 0),'/',`year`) AS data,
info
FROM
Log
WHERE
(year > :initial_year OR (year = :initial_year AND month >= :initial_moth AND day >= :initial_day))
AND (year < :final_year OR (year = :final_year AND month <= :final_month AND day <= :final_day))
GROUP BY
year, month, day
ORDER BY
year DESC, month DESC, day DESC
But this query doesn't display any results, even that they are in the database! What is wrong and how can I fix it?
Your logic is wrong:
WHERE (
year > :initial_year OR (
year = :initial_year AND month >= :initial_moth AND day >= :initial_day
)
)
Will exclude any dates in your initial year where the day portion is greater than the initial day portion. e.g. yyyy-01-31 as the initial day will exclude all results for yyyy where the day portion is not 31.
Similar problems exist with the final date.
As suggested in the comments, use one DATE field in your database and do the other fiddling in your application code; it will save a lot of drama.
If you can't change the database, find and berate the person who designed it until they change it. If you can't do that then:
WHERE (year>:initial_year OR (year=:initial_year AND (month>:initial_month OR (month=:initial_month AND day>=:initial_day))))
and similar for the final date
What about:
select
concat(year,month,day) as thedate, info
from
log
where
thedate >= :startdate and thedate <= :enddate
order by
thedate desc;

How to get last year's date range?

I would like to get a date range between LastYear/1/1 until LastYear/12/31
I know I could do this
date_sub(now(), interval 1 year). But this would get me 2013/03/08. Not sure how to change the day and the month.
SELECT *
FROM orders
WHERE dispatch_date between `LastYear/1/1` AND `LastYear/12/31`
You can easy to create the required dates:
SELECT *
FROM orders
WHERE dispatch_date >= MAKEDATE(YEAR(NOW()) - 1, 1) -- first day of previous year
AND dispatch_date < MAKEDATE(YEAR(NOW()), 1) -- first day of current year
I would suggest you to use YEAR().
SET #LastYear = YEAR(DATE_SUB(NOW(),INTERVAL 1 YEAR));
SELECT *
FROM orders
WHERE dispatch_date
BETWEEN CONCAT(#LastYear,'-01-01') AND CONCAT(#LastYear,'-12-31')