I'm trying to generate a SQL query to extract an average montly powerusage (of a year) for an ID.
+----+------------+------------+
| id | powerusage | date |
+----+------------+------------+
| 1 | 750 | 2011-12-2 |
| 1 | 1000 | 2011-12-1 |
| 1 | 1500 | 2011-11-15 |
| 1 | 100 | 2011-11-13 |
| 1 | 50 | 2011-11-10 |
| 2 | 500 | 2011-11-15 |
| 2 | 200 | 2011-11-13 |
+----+------------+------------+
So if ID = 1 I want (avg november + avg december) / 2 = (1750/2 + 1650/3) / 2 = 712.5
select AVG(powerusage) as avgMontlyPowerUsage
from usagetable
where id = 1 and YEAR(date) = 2011
But this will give me 680.
How do I do a average on a group?
Many thanks for all the answers! But I see my question is incorrect. See updated question
Something like
select AVG(montlyPowerUsage) from (
SELECT MONTH(date) as mnth,sum(powerusage) as montlyPowerUsage
from usagetable
where id = 1 and YEAR(date) = 2011 group by MONTH(date)
) t1
For Edited question
select AVG(montlyPowerUsage) from (
SELECT MONTH(date) as mnth,AVG(powerusage) as montlyPowerUsage
from usagetable
where id = 1 and YEAR(date) = 2011 group by MONTH(date)
) t1
mysql> select avg(powerusage)
from
(select monthname(date), sum(powerusage) as powerusage
from usagetable
where id=1 and year(date)=2011
group by monthname(date)) as avg_usage;
+-----------------+
| avg(powerusage) |
+-----------------+
| 1700.0000 |
+-----------------+
select avg(total_powerusage)
from
(select monthname(date), sum(powerusage) as total_powerusage
from usagetable
where id=1 and year(date)=2011
group by monthname(date)
) as avg_usage;
/* the use of subquery
is to return total of unique occurrences,
and sum powerusage of each occurrence,
which mean, you just need to apply AVG into the subquery */
This should give you monthly averages for every year and user. Some of the syntax may be MS SQL specific, but the logic should be good.
SELECT id, AVG(usage), year FROM
(SELECT id, SUM(powerusage) as usage, YEAR(date) as Year, MONTH(date) as Month
FROM usagetable
GROUP BY id, YEAR(date), MONTH(date)) as InnerTable
GROUP BY id, year
Try adding a group by on the id
GROUP BY id
Or the date, whichever suits.
SELECT SUM(powerusage) / (MONTH(MAX(`date`)) - MONTH(MIN(`date`)) + 1)
AS avgMontlyPowerUsage
FROM usagetable
WHERE id = 1
AND YEAR(`date`) = 2011
or (depending on what you need when data is sparse):
SELECT SUM(powerusage) / COUNT( DISTINCT MONTH(`date`) )
AS avgMontlyPowerUsage
FROM usagetable
WHERE id = 1
AND YEAR(`date`) = 2011
Warning: Neither of the above is optimized for performance.
Related
I want to calculate the division of each row per the sum of all rows that have the same Dateadded and fundid, but it seems my query is wrong due the results is not what I was expecting.
My table schema looks like this, I avoided mine because it has many more columns:
+----+--------+------------+--------+
| id | fundid | Dateadded | amount |
+====+========+============+========+
| 1 | 45 | 21-02-2018 | 5412 |
| 2 | 45 | 21-02-2018 | 5414 |
| 3 | 45 | 21-02-2018 | 1412 |
| 4 | 45 | 22-02-2018 | 5756 |
| 5 | 45 | 22-02-2018 | 4412 |
| 6 | 45 | 25-02-2018 | 2532 |
| 7 | 45 | 26-02-2018 | 7892 |
| 8 | 45 | 26-02-2018 | 8143 |
+----+-------+-------------+--------+
Rows with id's: 1,2,3 should be calculated together because they have
the same fundid and date.
Rows with id's: 4,5 same thing.
Rows with id's: 6 it is just one.
Rows with id's: 7,8 same thing.
My SQL query:
SELECT fundid
, Dateadded
, ( amount / SUM(amount) ) AS AvgRow
FROM stock2
GROUP
BY fundid
, Dateadded
ORDER
BY DateAdded ASC
Is this what you want?
select t.*, t.amount / tt.total_amount
from stock2 t join
(select fundid, dateadded, sum(amount) as total_amount
from stock2 t
group by fundid, dateadded
) tt
using (fundid, dateadded);
Or is this?
select fundid, dateadded, sum(t.amount) / tt.total_amount
from stock2 t cross join
(select sum(amount) as total_amount
from stock2 t
) tt
group by fundid, dateadded, tt.total_amount;
Check out a very well explained response to a similar issue related to usage of Group by here).
Similarly to the situation described there, for your query is ambiguous re: what "amount" should be used for each row. I.e. if you try:
SELECT fundid, Dateadded, ( AVG(amount) / SUM(amount) ) AS AvgRow FROM stock2 GROUP BY fundid, Dateadded ORDER BY DateAdded ASC
it will work because AVG(amount) is non-ambiguous for each (fundid, Dateadded) pair that should be calculated together.
It seems you are looking for something like:
SELECT st.fundid, st.Dateadded, ( amount / st2.total) ) AS AvgRow
FROM stock2 st
inner join
(select fundid, Dateadded, sum(amount) as total
from stock2
GROUP BY fundid, Dateadded) st2
on st.fundid = st2.fundid and st.Dateadded = st2.Dateadded
order by st.Dateadded
I have an SQL query I am using to pull data from an orders database. I am querying 2 tables and combining the results using UNION ALL. However, the UNION ALL does not seem to work as expected. Here is the query I am using:
SELECT year(oc_order.date_added) AS year, COUNT(oc_order.order_id) as cnt, SUM( ifnull(oc_order.new_total,oc_order.total) ) as total
FROM oc_order
WHERE oc_order.order_status_id IN (1,3,5)
AND MONTH(oc_order.date_added) BETWEEN '01' AND '02'
AND DAY(oc_order.date_added) BETWEEN '01' AND '31'
GROUP BY year(oc_order.date_added)
UNION ALL
SELECT ifnull(year(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),year(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) ) AS year, COUNT(oc_return_custom.return_id) as cnt, SUM( oc_return_custom.total ) as total
FROM oc_return_custom
WHERE ifnull(MONTH(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),MONTH(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) ) BETWEEN '01' AND '02'
AND ifnull(DAY(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),DAY(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) ) BETWEEN '01' AND '31'
GROUP BY ifnull(year(str_to_date(oc_return_custom.date_added,'%d-%m-%Y %H:%i:%s')),year(str_to_date(oc_return_custom.date_added,'%Y-%m-%d %H:%i:%s')) )
ORDER BY year DESC
This is what I get from the query:
+=======+========+=======+
| year | cnt | total |
+=======+========+=======+
| 2016 | 200 | 1000 |
| 2016 | 50 | 200 |
| 2015 | 100 | 800 |
| 2015 | 10 | 50 |
+=======+========+=======+
But this is what I wanted to get:
+=======+========+=======+
| year | cnt | total |
+=======+========+=======+
| 2016 | 250 | 1200 |
| 2015 | 110 | 850 |
+=======+========+=======+
Can someone tell me what I am doing wrong???
Notes:
The oc_order table's date_added column is datetime whereas oc_return_custom 's date_added column is just text.
UNION ALL simply puts together two data sets produced by separate GROUP BY operations.
To get the expected result set you have to wrap the query in a subquery and apply an additional GROUP BY:
SELECT year, SUM(cnt) AS cnt, SUM(total) AS total
FROM ( ... your query here ...) AS t
GROUP BY year
This is my bill table:
shop_id | billing_date | total
------------------------------
ABC | 2016-03-07 | 100
ABC | 2016-03-14 | 200
DEF | 2016-03-07 | 300
DEF | 2016-03-14 | 100
GHI | 2016-03-07 | 30
I want to get one line per shop, with average total per week, the current month total, and the average total per month. This final data must look like this:
shop | weekly avg. | current month total | monthly avg.
-------------------------------------------------------
ABC | 150 | 300 | 300
DEF | 200 | 500 | 500
GHI | 30 | 30 | 30
My question is: Is it possible to get this informations directly from an SQL query?
Hey you can try this way for current year using WEEK and MONTH of mysql. as per your data entries in table is week wise:
SQLFIDDLE
select shop_id,(sum(total)/(WEEK(MAX(bdate)) - WEEK(MIN(bdate))+1)) as weekly_avg,(sum(total)/(MONTH(MAX(bdate))-MONTH(MIN(bdate))+1)) as mothly_avg, sum( case when MONTH(bdate) = MONTH(NOW()) then total else 0 end) as current_month_total from bill group by shop_id WHERE YEAR(bdate) = 2016
For number of year greater than one
SQL FIDDLE
select shop_id,
sum(total)/(12 * (YEAR(MAX(bdate)) - YEAR(MIN(bdate))) + (MONTH(MAX(bdate)) - MONTH(MIN(bdate)))+1) as month_avg,
sum(total)/(7 * (YEAR(MAX(bdate)) - YEAR(MIN(bdate))) + (WEEK(MAX(bdate)) - WEEK(MIN(bdate)))+1) as weekly_avg,
sum( case when YEAR(bdate) = YEAR(bdate) and MONTH(bdate) = MONTH(NOW()) then total else 0 end) as current_month_total from bill group by shop_id
Is this the sort of thing you are after??:
SELECT DISTINCT(bill.shop_id),wk as WeeklyTotal,mt as MonthlyTotal,ma as MonthlyAverage
FROM bill
JOIN (SELECT AVG(total) wk,shop_id
FROM bill
WHERE YEAR(billing_date) = 2016 AND MONTH(billing_date) = 1
GROUP BY shop_id) as weekly ON bill.shop_id = weekly.shop_id
JOIN (SELECT SUM(total) mt,shop_id
FROM bill
WHERE YEAR(billing_date) = 2016 AND MONTH(billing_date) = 1
GROUP BY CONCAT(shop_id,MONTH(billing_date))
) month_total ON month_total.shop_id = bill.shop_id
JOIN (SELECT AVG(total) ma,shop_id
FROM bill
WHERE YEAR(billing_date) = 2016 AND MONTH(billing_date) = 1
GROUP BY CONCAT(shop_id,MONTH(billing_date))
) month_avg ON month_avg.shop_id = bill.shop_id
You can do this using conditional aggregation and conditional logic:
select shop_id,
sum(total) / (7 * datediff(max(billing_date), min(billing_date)) + 1) as avg_weekly,
sum(case when year(billing_date) = year(now()) and month(billing_date) = month(now()) then total else 0 end) as curr_Month,
(sum(total) /
(year(max(billing_date)) * 12 + month(max(billing_date)) -
year(min(billing_date)) * 12 + month(min(billing_date))
) + 1
)
) as avg_month
total else 0 end) as week_total
from bill
gropu by shop_id;
I have a table with :
user_id | order_date
---------+------------
12 | 2014-03-23
12 | 2014-01-24
14 | 2014-01-26
16 | 2014-01-23
15 | 2014-03-21
20 | 2013-10-23
13 | 2014-01-25
16 | 2014-03-23
13 | 2014-01-25
14 | 2014-03-22
A Active user is someone who has logged in last 12 months.
Need output as
Period | count of Active user
----------------------------
Oct-2013 - 1
Jan-2014 - 5
Mar-2014 - 10
The Jan 2014 value - includes Oct -2013 1 record and 4 non duplicate record for Jan 2014)
You can use a variable to calculate the running total of active users:
SELECT Period,
#total:=#total+cnt AS `Count of Active Users`
FROM (
SELECT CONCAT(MONTHNAME(order_date), '-', YEAR(order_date)) AS Period,
COUNT(DISTINCT user_id) AS cnt
FROM mytable
GROUP BY Period
ORDER BY YEAR(order_date), MONTH(order_date) ) t,
(SELECT #total:=0) AS var
The subquery returns the number of distinct active users per Month/Year. The outer query uses #total variable in order to calculate the running total of active users' count.
Fiddle Demo here
I've got two queries that do the thing. I am not sure which one's the fastest. Check them aginst your database:
SQL Fiddle
Query 1:
select per.yyyymm,
(select count(DISTINCT o.user_id) from orders o where o.order_date >=
(per.yyyymm - INTERVAL 1 YEAR) and o.order_date < per.yyyymm + INTERVAL 1 MONTH) as `count`
from
(select DISTINCT LAST_DAY(order_date) + INTERVAL 1 DAY - INTERVAL 1 MONTH as yyyymm
from orders) per
order by per.yyyymm
Results:
| yyyymm | count |
|---------------------------|-------|
| October, 01 2013 00:00:00 | 1 |
| January, 01 2014 00:00:00 | 5 |
| March, 01 2014 00:00:00 | 6 |
Query 2:
select DATE_FORMAT(order_date, '%Y-%m'),
(select count(DISTINCT o.user_id) from orders o where o.order_date >=
(LAST_DAY(o1.order_date) + INTERVAL 1 DAY - INTERVAL 13 MONTH) and
o.order_date <= LAST_DAY(o1.order_date)) as `count`
from orders o1
group by DATE_FORMAT(order_date, '%Y-%m')
Results:
| DATE_FORMAT(order_date, '%Y-%m') | count |
|----------------------------------|-------|
| 2013-10 | 1 |
| 2014-01 | 5 |
| 2014-03 | 6 |
The best thing I could do is this:
SELECT Date, COUNT(*) as ActiveUsers
FROM
(
SELECT DISTINCT userId, CONCAT(YEAR(order_date), "-", MONTH(order_date)) as Date
FROM `a`
ORDER BY Date
)
AS `b`
GROUP BY Date
The output is the following:
| Date | ActiveUsers |
|---------|-------------|
| 2013-10 | 1 |
| 2014-1 | 4 |
| 2014-3 | 4 |
Now, for every row you need to sum up the number of active users in previous rows.
For example, here is the code in C#.
int total = 0;
while (reader.Read())
{
total += (int)reader['ActiveUsers'];
Console.WriteLine("{0} - {1} active users", reader['Date'].ToString(), reader['ActiveUsers'].ToString());
}
By the way, for the March of 2014 the answer is 9 because one row is duplicated.
Try this, but thise doesn't handle the last part: The Jan 2014 value - includes Oct -2013
select TO_CHAR(order_dt,'MON-YYYY'), count(distinct User_ID ) cnt from [orders]
where User_ID in
(select User_ID from
(select a.User_ID from [orders] a,
(select a.User_ID,count (a.order_dt) from [orders] a
where a.order_dt > (select max(b.order_dt)-365 from [orders] b where a.User_ID=b.User_ID)
group by a.User_ID
having count(order_dt)>1) b
where a.User_ID=b.User_ID) a
)
group by TO_CHAR(order_dt,'MON-YYYY');
This is what I think you are looking for
SET #cnt = 0;
SELECT Period, #cnt := #cnt + total_active_users AS total_active_users
FROM (
SELECT DATE_FORMAT(order_date, '%b-%Y') AS Period , COUNT( id) AS total_active_users
FROM t
GROUP BY DATE_FORMAT(order_date, '%b-%Y')
ORDER BY order_date
) AS t
This is the output that I get
Period total_active_users
Oct-2013 1
Jan-2014 6
Mar-2014 10
You can also do COUNT(DISTINCT id) to get the unique Ids only
Here is a SQL Fiddle
Been searching for an answer to this for the better part of an hour without much luck. I have two regional tables laid out with the same column names and I can put out a result list for either table based on the following query (swap Table2 for Table1):
SELECT Table1.YEAR, FORMAT(COUNT(Table1.id),0) AS Total
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
Ideally I'd like to get a result that gives me a total sum of the counts by year, so instead of:
| REGION 1 | | REGION 2 |
| YEAR | Total | | YEAR | Total |
| 2010 | 5 | | 2010 | 1 |
| 2009 | 2 | | 2009 | 3 |
| | | | 2008 | 4 |
I'd have:
| MERGED |
| YEAR | Total |
| 2010 | 6 |
| 2009 | 5 |
| 2008 | 4 |
I've tried a variety of JOINs and other ideas but I think I'm caught up on the SUM and COUNT issue. Any help would be appreciated, thanks!
SELECT `YEAR`, FORMAT(SUM(`count`), 0) AS `Total`
FROM (
SELECT `Table1`.`YEAR`, COUNT(*) AS `count`
WHERE `Table1`.`variable` = 'Y'
GROUP BY `Table1`.`YEAR`
UNION ALL
SELECT `Table2`.`YEAR`, COUNT(*) AS `count`
WHERE `Table2`.`variable` = 'Y'
GROUP BY `Table2`.`YEAR`
) AS `union`
GROUP BY `YEAR`
You should use an UNION:
SELECT
t.YEAR,
COUNT(*) as TOTAL
FROM (
SELECT *
FROM Table1
UNION ALL
SELECT *
FROM Table2
) t
WHERE t.variable='Y'
GROUP BY t.YEAR;
Select year, sum(counts) from (
SELECT Table1.YEAR, FORMAT(COUNT(Table1.id),0) AS Total
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
UNION ALL
SELECT Table2.YEAR, FORMAT(COUNT(Table2.id),0) AS Total
FROM Table2
WHERE Table2.variable='Y'
GROUP BY Table2.YEAR ) GROUP BY year
To improve upon Shehzad's answer:
SELECT YEAR, FORMAT(SUM(counts),0) AS total FROM (
SELECT Table1.YEAR, COUNT(Table1.id) AS counts
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
UNION ALL
SELECT Table2.YEAR, COUNT(Table2.id) AS counts
FROM Table2
WHERE Table2.variable='Y'
GROUP BY Table2.YEAR ) AS newTable GROUP BY YEAR