I need to get the total number of an item for every month.
So far, with the following code :
Select Count(mpay_collector_company.id) As `Number of Collector Companies`,
Month(mpay_collector_company.created_at) As Month,
Year(mpay_collector_company.created_at) As Year
From mpay_collector_company
Group By Month(mpay_collector_company.created_at),
Year(mpay_collector_company.created_at)
I have the following response :
#|Year|Month
------------
5|2014|11
3|2014|12
3|2015|1
7|2015|2
6|2015|3
2|2015|4
5|2015|6
1|2015|7
And instead of the number for each month I'd like to have the sum from the beginning for each month, which would be something like this :
Sum|Year|Month
--------------
5|2014|11
8|2014|12
11|2015|1
18|2015|2
24|2015|3
26|2015|4
31|2015|6
32|2015|7
Any ideas ?
EDIT : This request will be implemented as a view, so sub-requests are pretty much a no-go :x
Something like this could work:
Select Count(distinct previous_mpay_collector_company.id)+ Count(distinct mpay_collector_company.id) As `Number of Collector Companies`,
Month(mpay_collector_company.created_at) As Month,
Year(mpay_collector_company.created_at) As Year
From mpay_collector_company
Left Join mpay_collector_company previous_mpay_collector_company
On Year(mpay_collector_company.created_at) > Year(previous_mpay_collector_company.created_at)
OR (Month(mpay_collector_company.created_at) > Month(previous_mpay_collector_company.created_at)
And Year(mpay_collector_company.created_at) >= Year(previous_mpay_collector_company.created_at))
And previous_mpay_collector_company.id <> mpay_collector_company.id
Group By Month(mpay_collector_company.created_at),
Year(mpay_collector_company.created_at);
The trick would be self joining to all of the previous months and counting from the joined table.
You can first select distinct year.months and then check count for each value
select year,month ,
( SELECT count(*) FROM mpay_collector_company WHERE
Year(mpay_collector_company.created_at) <= temp1.year
AND
Month(mpay_collector_company.created_at) <= temp1.month
)
from (
Select DISTINCT
Month(mpay_collector_company.created_at) As month,
Year(mpay_collector_company.created_at) As year
From mpay_collector_company
) as temp1
ORDER BY year,month
if you want to "reset" for each year , just change comparison to EQUAL between years and thats it
select year,month ,
( SELECT count(*) FROM mpay_collector_company WHERE
Year(mpay_collector_company.created_at) = temp1.year
AND
Month(mpay_collector_company.created_at) <= temp1.month
)
from (
Select DISTINCT
Month(mpay_collector_company.created_at) As month,
Year(mpay_collector_company.created_at) As year
From mpay_collector_company
) as temp1
ORDER BY year,month
Using a correlated subquery to count the number of rows with a date before the current should work too:
Select
Count(id) As "Number of Collector Companies",
Month(created_at) As Month,
Year(created_at) As Year,
(
Select Count(*)
From mpay_collector_company
Where EXTRACT(YEAR_MONTH from created_at) <= EXTRACT(YEAR_MONTH from m.created_at)
) as running_count
From mpay_collector_company m
Group By Year(created_at), Month(created_at);
Sample SQL Fiddle showing it in action
Select
(Select Sum(Count(Z.id)) FROM mpay_collector_company z
where z.created_at <= A.created_at) as '#',
Month(A.created_at) As Month,
Year(A.created_at) As Year
From mpay_collector_company A
Group By Month(mpay_collector_company.created_at),
Year(mpay_collector_company.created_at)
This should do it for ya,
Related
I currently am trying to track the number of messages sent by month as well as the volume's percent change in comparison to one year prior.
Here is my current query:
Select
a.mo,
a.ye,
a.Messages,
((a.Messages - b.Messages) / b.Messages) as "% Change"
from(
select
MONTH(post_date) as mo,
count(*) as "Messages",
YEAR(post_date) as ye
from
pm_messages
WHERE
post_date > "2018-01-01 00:00:00"
group by
year(post_date),
month(post_date)
) a
left join (
select
MONTH(post_date) as mo,
YEAR(post_date) as ye,
count(*) as "Messages"
from
pm_messages
group by
year(post_date),
month(post_date)
) b on a.mo = b.mo
and a.ye -1 = b.ye
This works great, however, it places month and year in separate columns, which has been messing up the graphs I am working with. However, when I try to pull month and year into one columns as I've done in other queries from the same table, i.e. using:
SELECT DATE_FORMAT(`post_date`,'%M %Y')
My query does not work.
Does anyone know how I can combine my current query to still calculate the return from a year prior but have month and date come up as one column, as opposed to (Month | Year | Messages | % Change)
Thanks!!
you can use extract instead of separate year() and month() functions :
EXTRACT(YEAR_MONTH from post_date)
of course you have to group by this instead of year, month . for example :
select
EXTRACT(YEAR_MONTH from post_date) yearmonth,
count(*) as "Messages"
from
pm_messages
group by
EXTRACT(YEAR_MONTH from post_date)
If you have data for every month, you can use lag():
select year(post_date) as ye, month(post_date) as mo,
count(*) as Messages,
lag(count(*)) over (partition by month(post_date) order by year(post_date)) as prev_year
from pm_messages
where post_date >= '2018-01-01'
group by year(post_date), month(post_date)
I'm trying to do a rolling count of registration growth on a student website.
The query looks as follows:
SELECT COUNT(type) as student_count, MONTH(created_at) as month, YEAR(created_at) as year
FROM users
WHERE type = 'student'
GROUP BY MONTH(created_at), YEAR(created_at)
ORDER BY year, month
This produces the following output:
What I'm trying to achieve in the query is to keep adding up the student_counts from the previous rows.
So:
December 2014 should have 15 students
January 2015 should have 16 students
February 2015 should have 34 students
and so on...
Is this possible in SQL or is it better to do this when outputting the data in the code itself?
select *, #sum := #sum + student_count as sum
from
(
SELECT YEAR(created_at) as year,
MONTH(created_at) as month,
COUNT(type) as student_count
FROM users
WHERE type = 'student'
GROUP BY year, month
ORDER BY year, month
) tmp
CROSS JOIN (select #sum := 0) s
Try using with rollup
SELECT COUNT(type) as student_count, MONTH(created_at) as month, YEAR(created_at) as year
FROM users
WHERE type = 'student'
GROUP BY YEAR(created_at), MONTH(created_at) WITH ROLLUP
Try this:
SELECT #cumulative := 0;
SELECT #cumulative := #cumulative + student_count student_count,
month, year
FROM (
SELECT COUNT(type) as student_count,
MONTH(created_at) as month,
YEAR(created_at) as year
FROM users
WHERE type = 'student'
GROUP BY MONTH(created_at), YEAR(created_at)
) A ORDER BY year, month
One approach to handle this in MySQL uses a correlated subquery to find the running total.
SELECT DISTINCT
(SELECT COUNT(*) FROM users u2
WHERE DATE_FORMAT(u2.created_at, '%Y-%m') <=
DATE_FORMAT(u1.created_at, '%Y-%m')) AS student_count,
DATE_FORMAT(created_at, '%Y-%m') AS ym
FROM users u1
WHERE type = 'student'
ORDER BY DATE_FORMAT(created_at, '%Y-%m');
Demo
Not much to explain here, except that SELECT DISTINCT gives us each unique year-month value in the table as a single record. We then count all rows at that point in time or earlier to find the running total.
I am trying to combine the results of a Union from
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total
FROM projects
WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON'
GROUP BY MONTH(terms)
UNION
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total
FROM archive
WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON'
GROUP BY MONTH(terms)
I get the following: RESULTS FROM THE SQL STATEMENT
I am trying to make it so the total will be the combination of the multiple instances of the month.
The sql tables are exactly the same.
This Is what I would like it to look like:
A FULL OUTER JOIN would be ideal. But in your case, let's do two levels of aggregation:
SELECT month, MAX(total_projects) as total_projects, MAX(total_archive) as total_archive
FROM ((SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total_projects, 0 as total_archive
FROM projects
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
) UNION ALL
(SELECT MONTHNAME(terms) AS month, 0, COUNT(DISTINCT project_num
FROM archive
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
)
) pa
GROUP BY month
ORDER BY month;
EDIT:
Oops. You only want one column. If you want to count the number of distinct projects for each month, then do a union all and then combine the results at the next higher level:
SELECT month, COUNT(DISTINCT project_num) as total
FROM ((SELECT MONTHNAME(terms) AS month, project_num
FROM projects
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
) UNION ALL
(SELECT MONTHNAME(terms) AS month, project_num
FROM archive
WHERE terms >= '2017/01/01' AND Building_designer = 'SOMEPERSON'
)
) pa
GROUP BY month
ORDER BY month;
A quick thought would be to just do something like this. You essentially want to sum the counts from each table.
select month, sum(total) from
(
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM projects WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms)
UNION
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM archive WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms)
) group by month;
transform into a derived table, put an alias then aggregate
select
x.month,
sum(x.total) [Total]
from (
SELECT
MONTHNAME(terms) AS month,
COUNT(DISTINCT project_num) AS total
FROM projects
WHERE terms >= '2017/01/01'
AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
UNION
SELECT
MONTHNAME(terms) AS month,
COUNT(DISTINCT project_num) AS total
FROM archive
WHERE terms >= '2017/01/01'
AND Building_designer = 'SOMEPERSON'
GROUP BY MONTH(terms)
) x
group by x.month
You can try creating a sum expression on the entire query.
SELECT month, SUM (total) FROM
(SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM projects WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms)
UNION
SELECT MONTHNAME(terms) AS month, COUNT(DISTINCT project_num) as total FROM archive WHERE terms >= '2017/01/01' AND Building_designer='SOMEPERSON' GROUP BY MONTH(terms))
GROUP BY month
Hello i have a sql query like this:
SELECT
COUNT(*) AS total,
COUNT(referrer) AS referrer,
DATE_FORMAT(created_at, "%Y") AS YEAR,
DATE_FORMAT(created_at, "%m") AS MONTH,
DATE_FORMAT(created_at, "%d") AS DAY
FROM
users
GROUP BY
EXTRACT(DAY FROM created_at),
EXTRACT(MONTH FROM created_at),
EXTRACT(YEAR FROM created_at)
ORDER BY
created_at ASC
This gives me table with totals sorted by day (month and year). what i need is to add a subquery to display one more count() which has a condition. Something like:
(SELECT count(*) FROM users WHERE result = '1') as winners
the problem obviously is with the grouping of main query since i get same result without grouping the subquery for every row.
What would be the right way to execute such query?
How about
SELECT
COUNT(*) AS total,
COUNT(referrer) AS referrer,
SUM(case when result = '1' then 1 else 0 end) as winners
DATE_FORMAT(created_at, "%Y") AS YEAR,
DATE_FORMAT(created_at, "%m") AS MONTH,
DATE_FORMAT(created_at, "%d") AS DAY
FROM
users
GROUP BY
EXTRACT(DAY FROM created_at),
EXTRACT(MONTH FROM created_at),
EXTRACT(YEAR FROM created_at)
ORDER BY
created_at ASC;
Assuming created_at is a timestamp, we could re-write your query with just one field to group by as follows:
SELECT
COUNT(*) AS total,
COUNT(referrer) AS referrer,
SUM(case when result = '1' then 1 else 0 end) as winners
DATE_FORMAT(created_at, "%Y") AS YEAR,
DATE_FORMAT(created_at, "%m") AS MONTH,
DATE_FORMAT(created_at, "%d") AS DAY
FROM
users
GROUP BY date(created_at)
ORDER BY
created_at ASC;
Please note I do not have mysql to hand.
You can join both queries with UNION
SELECT
COUNT(*) AS total,
COUNT(referrer) AS referrer,
DATE_FORMAT(created_at, "%Y") AS YEAR,
DATE_FORMAT(created_at, "%m") AS MONTH,
DATE_FORMAT(created_at, "%d") AS DAY
FROM
users
GROUP BY
EXTRACT(DAY FROM created_at),
EXTRACT(MONTH FROM created_at),
EXTRACT(YEAR FROM created_at)
ORDER BY
created_at ASC
UNION
SELECT count(*) FROM users
GROUP BY
EXTRACT(DAY FROM created_at),
EXTRACT(MONTH FROM created_at),
EXTRACT(YEAR FROM created_at)
HAVING result = '1'
SELECT
Day,
month,
year,
GROUP_CONCAT(total),
GROUP_CONCAT(SP_ID)
FROM
(
SELECT
DATE_FORMAT(l.act_date, '%d') AS DAY,
DATE_FORMAT(l.act_date, '%M') AS MONTH,
EXTRACT(YEAR FROM l.act_date) AS YEAR,
COUNT(*) as total,l.sp_id
FROM lead_activity2 as l
right outer join salesperson as s on l.sp_id=s.sp_id
WHERE l.act_name='scb'
AND ((l.act_date>='2012-09-07 13:03:27' )
AND (l.act_date<= '2012-11-07 13:03:27'))
GROUP BY MONTH, YEAR, DAY, l.sp_id
ORDER BY YEAR DESC, MONTH DESC, DAY DESC, l.sp_id DESC
) t GROUP BY day, month, year
http://sqlfiddle.com/#!2/1514d/3 - you can view the scheme and the query,
what i would like to get is
18 | october | 2012 | 0,0,1,1 | 6,5,4,3
spid 6 and spid 5 have no data for 18 october but still should be shown tried doing right join and right outer join both dont seem to work...
Use GROUP_CONCAT like so:
SELECT
Day,
month,
year,
GROUP_CONCAT(total),
GROUP_CONCAT(SP_ID)
FROM
(
SELECT
DATE_FORMAT(l.act_date, '%d') AS DAY,
DATE_FORMAT(l.act_date, '%M') AS MONTH,
EXTRACT(YEAR FROM l.act_date) AS YEAR,
COUNT(*) as total,l.sp_id
FROM lead_activity2 as l
WHERE l.act_name='scb'
AND ((l.act_date>='2012-09-07 13:03:27' )
AND (l.act_date<= '2012-11-07 13:03:27'))
GROUP BY MONTH, YEAR, DAY, l.sp_id
ORDER BY YEAR DESC, MONTH DESC, DAY DESC, l.sp_id DESC
) t GROUP BY day, month, year
Updated SQL Fiddle
Update: Yes you can do this, but use LEFT JOIN to include non matching sp_id. These non matching ids will have a value of NULL use IFNULL to display it with zeros like so:
SELECT
Day,
month,
year,
GROUP_CONCAT(total) Total,
GROUP_CONCAT(SP_ID) 'List of sp_ids'
FROM
(
SELECT
DATE_FORMAT(l.act_date, '%d') AS DAY,
DATE_FORMAT(l.act_date, '%M') AS MONTH,
EXTRACT(YEAR FROM l.act_date) AS YEAR,
COUNT(*) as total,
IFNULL(s.sp_id , 0) sp_id
FROM lead_activity2 as l
LEFT JOIN salesperson s ON l.sp_id = s.sp_id
WHERE l.act_name='scb'
AND ((l.act_date>='2012-09-07 13:03:27' )
AND (l.act_date<= '2012-11-07 13:03:27'))
GROUP BY MONTH, YEAR,DAY,s.sp_id
) t
ORDER BY YEAR DESC,
MONTH DESC,
DAY DESC,
sp_id DESC
Updates SQL Fiddle Demo