Pivot table with dynamic month column in mysql - mysql

I want to achieve output using mysql query as described in the screen shot.
in the screen shot, its showing amounts for last 12 months.
if I am running it in Jan 2016, it should show column names from Feb-15 to Jan-16.
Any ideas, how can this be achieved?

CREATE TABLE Months (
mo INT );
INSERT INTO Months VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
SELECT DATE_FORMAT(DATE(CONCAT(LEFT(NOW(), 7), '-15')
- INTERVAL mo MONTH),
"%b-%y") AS MmmYY
FROM Months ORDER BY mo DESC;
That should give you the headings you want. Then to do the pivoting, see
http://mysql.rjweb.org/doc.php/pivot

Related

Getting average value based on grouped data

I'm trying to find the average of net total for a given month, based on previous years to help show things like seasonal trends in sales.
I have a table called "Invoice" which looks similar to the below (slimmed down for the purpose of this post):
ID - int
IssueDate - DATE
NetTotal - Decimal
Status - Enum
The data I'm trying to get, for example would be similar to this:
(sum of invoices in June 2018 + sum of invoices in June 2019 + sum of invoices in June 2020) divided by number of years covered (3) = Overall average for June
But, doing this for the full 12 months of the year based on all the data (not just 2018 through to 2020).
I'm a bit stumped on how to pull this data. I've tried subqueries and even tried using a SUM within an AVG select, but the query either fails or returns incorrect data.
An example of what I've tried:
SELECT MONTHNAME(`Invoice`.`IssueDate`) AS `CalendarMonth`, AVG(`subtotal`)
FROM (SELECT SUM(`Invoice`.`NetTotal`) AS `subtotal`
FROM `Invoice`
GROUP BY EXTRACT(YEAR_MONTH FROM `Invoice`.`IssueDate`)) AS `sub`, `Invoice`
GROUP BY MONTH(`Invoice`.`IssueDate`)
which returns:
I see two parts to this query, but unsure how to structure it:
A sum and count of all data based on the month
An average based on the number of years
I'm not sure where to go from here and would appreciate any pointers.
Ideally, I'd want to get the totals from rows where "Status" = "Paid", but trying to crack the first part first. Walk before running as they say!
Any guidance greatly appreciated!
Basically you want two levels of aggregation:
SELECT mm, AVG(month_total)
FROM (SELECT YEAR(i.IssueDate) as yyyy, MONTH(i.issueDate) as mm,
SUM(i.`NetTotal`) as month_total
FROM Invoice i
GROUP BY yyyy, mm
) ym
GROUP BY mm;
Just for the Average Amount Part You Could use a query like
Select Date From Your_Table Where Date Like '20__-06-%'
You can arrange it into asc desc order.

Grouping months by quarter over multiple years depending on a dynamic start month

Using MySQL and PHP I am building a JSON array to populate a data table.
For the purposed of my question suppose the data table has the following columns:
Year: 2010,2011,2012,2013...<br/>
Month: 1,2,3,4,5...<br/>
Value: 100, 150, 200 etc...<br/>
The table structure cannot be altered and my solution needs come into the MySQL query
The data can be viewed either monthly, quarterly or yearly. Monthly and yearly is achieved easily through grouping by year and month.
Quarterly data can be grouped by calendar quarter (Jan-Mar, Apr-Jun, Jul-Sep, Oct-Dec) by this group statement:
GROUP BY year, round((month/3)+0.3,0)
So where Jan, Feb and March might all have 100 for their value the summed result is 300, same for other months.
Now my problem comes when I want to group values by a financial quarter, for example a quarter that starts in Feb, or any other quarters.
I have a statement that works for the quarter grouping using two variables that can be accessed via the SQL query, start_year (i.e. 2014) and start_month (i.e. 2)
GROUP BY year, (((round(((((month-(start_month-1))+((year-start_year)*12))-((year-start_year)*12))/3)+0.33,0)/4)+4)-floor(((round(((((month-(start_month, '%m')-1))+((year-start_year)*12))-((year-start_year*12))/3)+0.33,0)/4)+4)))*12
which basically will assign a 0,3,6,9 value to each calendar month for the purposes of grouping.
In the financial year starting February this works fine for quarters 1-3, however breaks for the final quarter as it includes Nov and Dec 2014 data and Jan from 2015.
As a result I get 5 rows of data instead of 4.
This is because of the preceding GROUP by year clause, an important addition as we might want to generate a table that views sequential quarters for multiple years.
So what I am looking for is a way of grouping the years together by offsetting the start month.
So when the year starts in Jan it will group Jan-Dec but if we change that to starting Feb it will group Feb-Jan.
Any ideas, suggestions most welcome!
Regards,
Carl
I solved a similar problem just now (a Moodle report aggregating assignment scores by year and quarter) with something like this:
select year(from_unixtime(s.timemarked)) as year, quarter(from_unixtime(s.timemarked)) % 4 + 1 as quarter, count(distinct data1) as "tickets graded" from mdlassignment_submissions s where grade >= 0 group by year, quarter order by year, quarter;
The relevant part for what you're doing is quarter(from_unixtime(s.timemarked)) % 4 + 1 as quarter
As another commenter pointed out, MySQL has a quarter() function, but it doesn't do financial quarters. However, since (as I understand it, at least, based on consulting the relevant wikipedia page) financial quarters are just offset by 1, the % 4 + 1 at the end should convert it.

Get sum of values based on the value of 2 other date related columns

Given the sample data in the screenshot below, would it be possible in mysql to return a sum of values from monthly_amount only where the values are before this month. I used a join to pull this data. The 5 left columns are from one table, and the rest are from another.
The issue I'm running into is, lets say its April of 2015, I can't just do a sum WHERE goal_year <= 2015 AND month_id_FK <= 4, or else I'll get only those 4 months from both years, when in that scenario, I really want all the months from 2014, plus the 4 months from 2015.
I could handle this in PHP, but I wanted to first see if there would be a way to do this in mysql?
try
WHERE Goal_Year*100+month_id_FK <= 201504
alternatively:
WHERE
GOAL_YEAR < 2015 OR
(GOAL_YEAR = 2015 and month_id_FK <= 4)
select sum(monthly_amount) from table where goaldate<(SELECT CURDATE())
this is not the actual query for your table..but if you do like this you will get the answer
you need the sum of monthly amount where the date is before current-date means today.
then you can just compare the currentdate with goal date

Range query from month and year

I have a table like this:
ID month year content
1 4 2013 xxxxx
2 5 2013 yyyyy
3 6 2013 zzzzz
4 8 2014 fffff
I want to query it based on a year and month range.
I have query like this:
SELECT * FROM UPP
WHERE ( month = '4' AND year = '2013' )
AND ( month = '6' AND year = '2013' )
That query runs but returns no result. Can anyone help me for fix this query?
NB: The month and year columns are integers.
Why not use the correct data type?
Failing that:
SELECT * FROM UPP WHERE (year=2013) AND (month BETWEEN 4 AND 6);
Would be the easiest path to this particular answer.
EDIT
SQL Fiddle for reference.
There will never be any rows where both month=4 and month=6 which is what your query is asking for. Adding brackets like that will not alter the AND behaviour as you seem to want them to so you are asking for WHERE year=2013 AND month=4 AND month=6.
There are a number of ways you could ask for what you seem to be wanting, for instance:
WHERE (year=2013 AND month=4) OR (year=2013 AND month=6)
or
WHERE year=2013 AND (month=4 OR month=6)
or
WHERE year=2013 AND month IN (4,6)
If you want the full range (the full quarter, months 4, 5, and 6 not just months 4 and 6 then swasheck's suggestion is probably the clearest way to go, though this will fall down if the date range straddles a boundary between years. If you need to do fully flexible ranged queries ("the six months to February 2013" and so forth) then you might want to rethink the table structure to more easily/efficiently support that.

MSAccess - Design query to group by anniversary date

Lets say I have a table with these fields
LeaveDate
LeaveType
I want to write a query that groups by an annivesary date.
For example say 8th Feb.
So for this year any dates after 8 Feb would be "2010" and any dates before 8 Feb would show "2009".
I want this to occur for all years data.
Understand??
Malcolm
Here is how I did it
SELECT Year([tblFoo]![Leave_date])-IIf(DateDiff("d",[tblFoo]![Leave_date],DateSerial(Year([tblFoo]![Leave_date]),2,8))>0,1,0) AS Year_group, Count(tblFoo.ID) AS CountOfID
FROM tblFoo
GROUP BY Year([tblFoo]![Leave_date])-IIf(DateDiff("d",[tblFoo]![Leave_date],DateSerial(Year([tblFoo]![Leave_date]),2,8))>0,1,0);
This counts the number of records for each “Year”. We use something similar for working out birthday years which change from person to person. In that case use can just replace the fixed 2 and 8 with the month and day they were born
You could create a query with a calculated column for anniversary date, then group by that column.