Given the following sample data:
tblData
Date Sales
----------------------
2011-12-01 122
2011-12-02 433
2011-12-03 213
...
2011-12-31 235
2011-11-01 122
2011-11-02 433
2011-11-03 213
...
2011-11-30 235
2011-10-10 122
2011-10-11 433
2011-10-12 213
...
2011-10-31 235
Notice that October data begins at 10 October, whereas subsequent months have complete data.
I need to get the average monthly sales over all complete months, which in this case would be November and December 2011.
How would I do this?
SELECT `date`, AVG(`sales`)
FROM sales
GROUP BY YEAR(`date`), MONTH(`date`)
HAVING COUNT(`date`) = DAY(LAST_DAY(`date`));
Example
If you want to limit the result, either
HAVING ...
ORDER BY `date` DESC LIMIT 3
which should always return data for the 3 most recent months, or something like
FROM ...
WHERE DATE_FORMAT(CURDATE() - INTERVAL 3 MONTH, '%Y-%m')
<= DATE_FORMAT(`date`, '%Y-%m')
GROUP BY ...
which should return data for the 3 previous months, if there is any. I'm not sure which is better but I don't believe WHERE gets to use any index on date, and if you're using DATETIME and don't format it you'll also be comparing the days and you don't want that,
Can't test it right now, but please have a try with this one:
SELECT
DATE_FORMAT(`Date`, '%Y-%m') AS yearMonth,
SUM(Sales)
FROM
yourTable
GROUP BY
yearMonth
HAVING
COUNT(*) = DAY(LAST_DAY(`Date`)
Related
I have the query
SELECT DATE_FORMAT(sys_date, '%Y-%c') as month, COUNT(DATE_FORMAT(sys_date, '%Y-%c'))
FROM sale
GROUP BY month
ORDER BY month ASC
That returns the following result,
month COUNT(DATE_FORMAT(sys_date, '%Y-%c'))
2017-10 204
2017-11 178
2017-12 88
2017-7 3
2017-8 1
2017-9 153
2018-1 91
2018-2 86
2018-3 67
2018-4 109
2018-5 131
2018-6 47
2018-7 50
2018-8 36
2018-9 39
How do I make the output in correct ascending order? Like,
month COUNT(DATE_FORMAT(sys_date, '%Y-%c'))
2017-7 3
2017-8 1
2017-9 153
2017-10 204
2017-11 178
2017-12 88
2018-1 91
2018-2 86
2018-3 67
2018-4 109
2018-5 131
2018-6 47
2018-7 50
2018-8 36
2018-9 39
I've tried using MONTH(month), YEAR(month) ASC and many other options listed on the site. But nothing seems to work.
It's because the calculated month is ordered alphabetically. But you could keep that ORDER BY month and simply change it to a format with a leading 0 for months < 10.
That way the string values will all have the same length, and the alphabetical sort will be correct.
Because when comparing strings then '10' < '9' but '09' < '10'
To do that, simply change the %c to %m. Reference
Also, the COUNT can be simplified.
SELECT DATE_FORMAT(sys_date, '%Y-%m') as month, COUNT(*) as Total
FROM sale
GROUP BY month
ORDER BY month
If you do wish to use the '%Y-%c' format?
Then you could include the year and the length of month in the ORDER BY.
SELECT DATE_FORMAT(sys_date, '%Y-%c') as month, COUNT(*) as Total
FROM sale
GROUP BY YEAR(sys_date), month
ORDER BY YEAR(sys_date), LENGTH(month), month
Sort the data based on YEAR and MONTH obtained from sys_date directly. Since, you have only_full_group_by mode enabled, you will need to get YEAR and MONTH values in the SELECT part, so that ORDER BY clause can use it for sorting. Use the following query:
SELECT YEAR(sys_date) as ysysdate,
MONTH(sys_date) as msysdate,
DATE_FORMAT(sys_date, "%Y-%c") as ymonth,
COUNT(*)
FROM sale
GROUP BY ymonth
ORDER BY ysysdate ASC, msysdate ASC
I am in big trouble and I need your help, I have two tables sales and recovery. My requirement is to get report month wise so I use date_format in query with Union All, its working fine but the issue is its shows the result in different rows of sale and recovery if the month is same.
Sale:
ID(unique) Party Amount Sale_Date
1 95 1500 01-05-2017
2 97 3500 15-05-2017
3 95 2500 05-06-2017
4 97 500 10-06-2017
5 99 1000 01-07-2017
Recovery:
ID(unique) Party Amount Recovery_Date
1 95 1000 01-06-2017
2 97 2000 20-06-2017
3 95 3500 10-07-2017
4 97 900 10-07-2017
5 99 1500 15-08-2017
I want to get result month wise so I use DATE_FORMAT in query with UNION ALL. below is the query i am using.
"SELECT SUM(amount) as sale_amount, DATE_FORMAT(Sale_Date, '%M %Y'),
null as recovery_amount FROM
`SALE` GROUP BY DATE_FORMAT(Sale_Date, '%M %Y')
UNION ALL
"SELECT null as sale_amount, DATE_FORMAT(Sale_Date, '%M %Y'),
SUM(amount) as recovery_amount FROM
`SALE` GROUP BY DATE_FORMAT(Sale_Date, '%M %Y')
Result:
S.No Month Sale Recovery Balance
1 May-2017 5000 5000
2 June-2017 3000 3000
3 June-2017 3000 -3000
4 July-2017 1000 1000
5 July-2017 4400 -4400
6 Aug-2017 1500 -1500
the above result is ok but i need the result in below format to get correct balance amount
Expected Result:
S.No Month Sale Recovery Balance
1 May-2017 5000 5000
2 June-2017 3000 3000 0
3 July-2017 1000 4400 -3300
4 Aug-2017 1500 -1500
You have to aggregate the resultsof the union by moving it into a subquery:
Select year_month, sum(sale_amount) as sale_amount, sum(recover_amount) as recovery_amount, sum(sale_amount)-sum(recovery_amount) as balance
From (
SELECT SUM(amount) as sale_amount, DATE_FORMAT(Sale_Date, '%M %Y') as year_month, null as recovery_amount
FROM `SALE` GROUP BY DATE_FORMAT(Sale_Date, '%M %Y')
UNION ALL
SELECT null as sale_amount, DATE_FORMAT(recovery_Date, '%M %Y'), SUM(amount) as recovery_amount
FROM `recovery` GROUP BY DATE_FORMAT(recovery_Date, '%M %Y')) as t
Group by year_month
Unfortunately, mysql does not support full outer join hence this beauty above.
I have bellow snippet table format.
Table name:- wp_lead_count_freevendor
id entryid start_date end_date user_id count_set entry_date cancel_set_date
70 11392 2015-12-03 2015-12-03 3185 1 2015-12-03 2015-12-04
71 11393 2015-12-03 2015-12-03 3185 1 2015-12-03 2015-12-04
72 11394 2014-10-01 2014-10-01 3185 1 2014-10-01 2014-10-01
Here i want to calculate count total count_set column. of current month & year by start_date column WHERE user_id=3185.
suppose in start_date current year is 2015 & current month is 12:-
year month count total
2015 12 2
For user id 3185 of this month of year count_set total =2
so any body will tell how do i fire the query to get count_set total for current year of current month for user_id=3185.
I have tried bellow query but its not working.
$check_per_month=mysql_query("SELECT DATE_FORMAT(end_date, '%Y') as 'year',
DATE_FORMAT(end_date, '%m') as 'month',
COUNT(id) as 'total'
FROM wp_lead_count_freevendor WHERE user_id=$wp_lead_count_user_id
GROUP BY DATE_FORMAT(end_date, '%Y%m')") OR DIE(mysql_error());
while($row = mysql_fetch_assoc($check_per_month))
{
echo $sql_chk_current_month_count=$row['total'];
}
Try to count using the where , year and month methods like this:
SELECT .... WHERE YEAR(start_date)=2015 AND MONTH(start_date)=12
Try this query:
SELECT YEAR(NOW()) as `year`,MONTH(NOW()) as `month', SUM(count_set) as `count_set`
From wp_lead_count_freevendor
WHERE YEAR(start_date)=YEAR(NOW()) AND MONTH(start_date)=MONTH(NOW()) AND user_id=3185
group by YEAR(NOW()),MONTH(NOW())
I want a query that can give result with sum of last 7 day look back.
I want output date and sum of last 7 day look back impressions for each date
e.g. I have a table tblFactImps with below data:
dateFact impressions id
2015-07-01 4022 30
2015-07-02 4021 33
2015-07-03 4011 34
2015-07-04 4029 35
2015-07-05 1023 39
2015-07-06 3023 92
2015-07-07 8027 66
2015-07-08 2024 89
I need output with 2 columns:
dateFact impressions_last_7
query I got:
select dateFact, sum(if(datediff(curdate(), dateFact)<=7, impressions,0)) impressions_last_7 from tblFactImps group by dateFact;
Thanks!
If your fact table is not too big, then a correlated subquery is a simple way to do what you want:
select i.dateFact,
(select sum(i2.impressions)
from tblFactImps i2
where i2.dateFact >= i.dateFact - interval 6 day
) as impressions_last_7
from tblFactImps i;
You can achieve this by LEFT OUTER JOINing the table with itself on a date range, and summing the impressions grouped by date, as follows:
SELECT
t1.dateFact,
SUM(t2.impressions) AS impressions_last_7
FROM
tblFactImps t1
LEFT OUTER JOIN
tblFactImps t2
ON
t2.dateFact BETWEEN
DATE_SUB(t1.dateFact, INTERVAL 6 DAY)
AND t1.dateFact
GROUP BY
t1.dateFact;
This should give you a sliding 7-day sum for each date in your table.
Assuming your dateFact column is indexed, this query should also be relatively fast.
I have a cron script that writes the total number of active users to a table every day. I'm trying to now generate a simple report that would show the "high water mark" for each month. Because some accounts expire during the month it's possible the highest number may NOT be at the end of the month.
Here's a sample of my table structure
tblUserLog
-----------
record_id INT(11) // PRIMARY KEY
run_date DATE // DATE RUN
ttl_count INT(11) // TOTAL FOR DAY
Sample data:
record_id run_date ttl_count
1 2013-06-01 500
2 2013-06-10 510
3 2013-06-20 520
4 2013-06-30 515
5 2013-07-01 525
6 2013-07-10 530
7 2013-07-20 540
8 2013-07-31 550
9 2013-08-01 560
What I would like returned is:
record_id run_date ttl_count
3 2013-06-20 520
8 2013-07-31 550
9 2013-08-01 560
I've tried two queries that are close...
// This will give me the total for the first of the month
SELECT s.record_id, s.run_date, s.ttl_count
FROM tblStatsIndividual s
JOIN (
SELECT record_id
FROM tblStatsIndividual
GROUP BY DATE_FORMAT(run_date, '%Y %m')
HAVING MAX(ttl_count)
) s2
ON s2.record_id = s.record_id
ORDER BY run_date DESC
This returns the total for the first of each month, along with the record_id and correct date for the total.
Tried this...
SELECT record_id,max(run_date), max(ttl)
FROM (
SELECT record_id,run_date, max(ttl_count) AS ttl
FROM tblStatsIndividual
GROUP BY DATE_FORMAT(run_date, '%Y %m')
) a
GROUP BY DATE_FORMAT(run_date, '%Y %m')
ORDER BY run_date DESC
This one appears to get the correct "high water mark" but it's not returning the record_id, or the run_date for the row that IS the high water mark.
How do you get the record_id and the run_date for the highest total?
Something like
Select detail.Record_ID, detail.Run_Date, detail.ttl_Count
From tblStatsIndividual detail
Inner Join
(Select Year(run_date) as Year, Month(Run_date) as Month, Max(ttl_count) as ttl
From tblStatsIndividual
Group By Year(run_date), Month(Run_date)) maximums
On maximums.Year = Year(detail.Run_date) and maximums.Month = Month(detail.Run_date)
and maximums.ttl = detail.ttl_count
Should do it. NB based on your requirement if you had two records in the same month with the same (and highest in the month) ttl_count, they would both be returned.
Based on the help from #Tony Hopkinson, This query gets me the info. The one caveat is it shows the ID and date for the first occurrence of the MAX total, so if the total is the same three days in a row on a month, the first day's ID is returned. For my purpose, the last ID would be more ideal, but I can live with this:
SELECT s.Record_ID, s.Run_Date, s.ttl_Count
FROM tblStatsIndividual s
INNER JOIN (
SELECT YEAR(run_date) AS yr, MONTH(run_date) AS mon, MAX(ttl_count) AS ttl
FROM tblStatsIndividual
GROUP BY DATE_FORMAT(run_date, '%Y %m')
) maximums
ON maximums.yr = YEAR(s.run_date)
AND maximums.mon = MONTH(s.run_date)
AND maximums.ttl = s.ttl_Count
GROUP BY ttl_count
ORDER BY run_date DESC