MySql Group by Month - mysql

I have set of dates and it's corresponding sales and I want to go group my month with order by month.
Not it may be possible that entry of few months can not be present and if so then for corresponding months value will be 0 else what ever sum available for other month.

something like this would maybe do a trick: - but you need to take care of years, this is only month based
SELECT s1.m as mnth,IFNULL(s2.smv,0) as smv FROM
(SELECT 1 as m UNION
SELECT 2 UNION
SELECT 3 UNION
SELECT 4 UNION
SELECT 5 UNION
SELECT 6 UNION
SELECT 7 UNION
SELECT 8 UNION
SELECT 9 UNION
SELECT 10 UNION
SELECT 11 UNION
SELECT 12) s1
LEFT JOIN
(SELECT MONTH(startdatum) as mnth,
SUM(somevalue) as smv
FROM db_table GROUP BY mnth) s2
ON s1.m=s2.mnth

YOU can try:
//this will give you all entries for the required month
SELECT * FROM tbl1 WHERE date=MONTH('datecolumn_name') ORDER BY MONTH(datecolumn_name) ASC;

juz run thiz query u get idea :
(SELECT #d:=date_add(#d,interval 1 MONTH) AS month_view,date_format(#c,'%b-%Y') AS month_name,#a:= #c AS month_start,#b:=if(last_day(#a)>'2014-02-24','2014-02-24', last_day(#a)) AS month_end, #c:= CASE WHEN date_add(#b,interval 1 DAY)>'2014-02-24' THEN NULL ELSE date_add(#b , INTERVAL 1 DAY) END AS dummy_val FROM table_name,
(SELECT #c:='2013-01-01', #d:='2013-01-01') AS month_temp WHERE #c IS NOT NULL)
'table_name' give any table name from ur database
from_date=2013-01-01
to_date=2014-02-24

Related

SQL query for last 365 days report

I have a reports table with the following structure :
I want a SQL Query to get the report for the last 365 days by following conditions :
Group dates if the same date is repeated.
The days which the report is not available for the last 365 days, I need those days added to the result rows with 0 as their success and failed recipients.
I tried to get it by group by report dates
SELECT report_date, SUM(success_recipient) as success_recipient, SUM(failed_recipient) as failed_recipient FROM reports GROUP BY report_date;
and I have got the grouped result which satisfies the first condition
Now I need to append the rest of the days in the last 365 days to this result in which 0 as their success and failure recipients.
Expected result :
and so on ..
MYSQL VERSION : 5.6
One way to achieve this is using "with recursive" to generate all dates you need in you output and then outer join to the rest of your query. Note: I use the number 356 as it is in your description but it seems more appropriate to use date difference as this approach does not take into account leap years. Using the query below you will get NULL values in case you have no data. If you need the value 0 you can use coalesce(sum(...), 0).
with recursive
dates as (
select curdate()-356 dt
union all
select dt+1 from dates
where dt < curdate()
)
select
dt report_date,
sum(success_recipient) success_recipient,
sum(failed_recipient) failed_recipient
from dates
left join reports on report_date = dt
group by report_date;
From the above comments and the answer, I could write this query which gave me the expected outcome :
SELECT a.date, SUM(COALESCE(r.success_recipient, 0)), SUM(COALESCE(r.failed_recipient, 0))
FROM (
SELECT curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a) + (1000 * d.a) ) DAY AS date
FROM (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as d
) a
LEFT JOIN reports r ON a.date = r.report_date
WHERE a.date between DATE_SUB(CURDATE(), INTERVAL 1 YEAR) and now()
GROUP BY a.date;

get result of non-existent dates too

I have a MySql table containing events having a DATETIME timestamp. I want to count each day's events. On some days, e.g. on Sundays, events are missing. The result should contain these days too with a count of zero.
My query is the following:
SELECT
COUNT(1) AS mycount,
DATE_FORMAT(DATE(evaluations.timestamp),"%a, %d.%m.%Y") AS date
FROM Events
GROUP BY DATE(timestamp)
ORDER BY DATE(timestamp) DESC
Can I modify the query without using a helper table containing all dates?
A single query (no procedere, no function) would be fine.
The query would somehow look like this if you don't have any calendar table:
SELECT
dateTable.day,
COALESCE(t.mycount,0) AS cnt
FROM
(
SELECT ADDDATE((SELECT MIN(DATE(timestamp)) FROM Events), INTERVAL #i:=#i+1 DAY) AS DAY
FROM (
SELECT a.a
FROM (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS a
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS b
CROSS JOIN (SELECT 0 AS a UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS c
) a
JOIN (SELECT #i := -1) r1
WHERE
#i < DATEDIFF((SELECT MAX(DATE(timestamp)) FROM Events), (SELECT MIN(DATE(timestamp)) FROM Events))
) AS dateTable
LEFT JOIN
(
SELECT
COUNT(1) AS mycount,
DATE_FORMAT(DATE(evaluations.timestamp),"%a, %d.%m.%Y") AS date
FROM Events
GROUP BY DATE(timestamp)
ORDER BY DATE(timestamp) DESC
) AS t
ON dateTable.day = t.date
ORDER BY dateTable.day DESC;
Note:
If you think you will need this kind of query too often then you can create a table where all the dates would reside. Newer dates can be added through mysql event periodically .
Then the work is simple. Just need to make a LEFT JOIN between the calendar table and the result of your query.

mysql show count as 0 for non-existing records

Although I have researched similar other questions, however could not reach the solution by following those, hence posting my following question, and apologies for a long question in an attempt to make my question more clear.
The image shows my table structure.
I want to run such a query to extract the 3 information,i.e
userId, count(), Date(viewTime)
i.e the no of counts of id that a user has viewed on daily basis in a interval of last 14 days,
also show count as 0 if there are no records for a user on a particular day
select userId, count(userId), Date(viewTime) from user_views
where DATE(viewTime) between DATE_SUB(DATE(NOW()), INTERVAL 90 DAY) AND now()
group by userId, date(viewTime);
By using the above query I am getting only the non-zero records, see in the following image:
However I want to show count as 0 for those days when there are no transaction of users. How do I achieve this?
You need to generate the dates dynamically for this and then use left join. Also note that since you are displaying the user_id it might be needed a cross join of distinct user_id with the dynamically generated dates.
From my previous answers related to showing missing dates MySql Single Table, Select last 7 days and include empty rows
Here is one for your case
select
t1.user_id,
coalesce(t2.cnt,0) as cnt,
t1.view_date
from
(
select DATE_FORMAT(a.Date,'%Y-%m-%d') as view_date,
x.user_id
from (
select curdate() - INTERVAL (a.a + (10 * b.a) + (100 * c.a)) DAY as Date
from (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as a
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as b
cross join (select 0 as a union all select 1 union all select 2 union all select 3 union all select 4 union all select 5 union all select 6 union all select 7 union all select 8 union all select 9) as c
) a,(select distinct user_id from user_views)x
where a.Date between DATE_SUB(DATE(NOW()), INTERVAL 90 DAY) AND now()
)t1
left join
(
select user_id, count(user_id) as cnt, Date(view_time) as view_time from user_views
where DATE(view_time) between DATE_SUB(DATE(NOW()), INTERVAL 90 DAY) AND now()
group by user_id, date(view_time)
)t2
on t2.view_time = t1.view_date
and t1.user_id = t2.user_id
order by t1.view_date,t1.user_id
http://sqlfiddle.com/#!2/4136e/5

Select records of previous month and show 0 if no records are there in specific time-window

Hello I have this query to get a list of drives that occurred for a specific month in a time window of 1 year back.
SELECT COUNT( drives.id ) AS drives, DATE_FORMAT( drives.timestamp, '%d-%m-%Y' ) AS mdate
FROM drives, users
WHERE drives.user = '146'
AND DATE_FORMAT( drives.timestamp, '%b' ) = 'Feb'
AND drives.timestamp > DATE_SUB(now(), INTERVAL 12 MONTH)
GROUP BY DATE(drives.timestamp) ORDER BY drives.timestamp ASC
I get the following result:
drives mdate
1 14-02-2013
2 17-02-2013
However I would like a result with every date of the month even if no records are found for that date, and display 0 next to the date that no drives took place.The tricky part for me is how to get the exact dates of the specific month in 1 year back timewindow.
I could implement this with php but I would prefer a cleaner solution.
Not sure where the users table comes into this (you are cross joining it, but not actually using it anywhere), but something like this should do what you require (not tested).
SELECT Sub1.aDay, COUNT( drives.id ) AS drives
FROM
(
SELECT DATE_ADD('2013-02-01', INTERVAL units.i + tens.i * 10 DAY) AS aDay
FROM
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units
CROSS JOIN
(SELECT 0 AS i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens
HAVING MONTH(aDay) = 2
) Sub1
LEFT OUTER JOIN drives
ON Sub1.aDay = DATE(drives.timestamp)
WHERE drives.user = '146'
GROUP BY DATE(drives.timestamp)
ORDER BY drives.timestamp ASC

Sort data from MYSQL database by hour

I have users in db that I want to sort by hour and display count of users registered at that hour.
select
date_format(create_time, '%Y-%m-%d %h%p') as date,
count(id) as 'Number of registrations'
from users
group by 1
order by 1 desc
;
The above code will work; however, what I am trying to do is display 0's for the hours that have no user registrations. For example, if there were no registrations at 5pm, this will skip row for 5pm, which is logical. Is there a way to achieve what I am trying?
You could use a query like this:
select
date_format(t.d + INTERVAL t.h HOUR, '%Y-%m-%d %h%p') as date,
count(id) as 'Number of registrations'
from (
SELECT *
FROM
(SELECT DISTINCT DATE(create_time) d FROM users) dates,
(SELECT 0 h UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7
UNION ALL SELECT 8 UNION ALL SELECT 9 UNION ALL SELECT 10 UNION ALL SELECT 11
UNION ALL SELECT 12 UNION ALL SELECT 13 UNION ALL SELECT 14 UNION ALL SELECT 15
UNION ALL SELECT 16 UNION ALL SELECT 17 UNION ALL SELECT 18 UNION ALL SELECT 19
UNION ALL SELECT 20 UNION ALL SELECT 21 UNION ALL SELECT 22 UNION ALL SELECT 23) hours
) t LEFT JOIN users
ON DATE(users.create_time)=t.d AND HOUR(users.create_time)=t.h
group by t.d, t.h
order by t.d, t.h
Please see fiddle here.
You need to generate all possible day and hour combinations.
Assuming that you have at least one record on each day and one record for each hour, you can do:
select concat(d.theday, ' ', h.thehour) as date,
count(id) as 'Number of registrations'
from (select distinct date_format(create_time, '%Y-%m-%d') as theday from users
) d cross join
(select distinct date_format(create_time, '%h%p') as thehour from users
) h left outer join
users u
on date_format(u.create_time, '%Y-%m-%d %h%p) = concat(d.theday, ' ', h.thehour)
group by concat(d.theday, ' ', h.thehour)
order by 1 desc;