Mysql query specific output [duplicate] - mysql

This question already has answers here:
mySQL Query for summing amount in columns (months)
(3 answers)
Closed 2 years ago.
I'm trying to get an output such as:
Year | January | February | March | April | May | June | July | August | September | October | November | December
Year | January | February | March | April | May | June | July | August | September | October | November | December
..and so on.
Each month column should have its own SUM(price) for that Month and the Year in question. Wherever comes blank (for example, maybe 2020 March is empty) should be blank/zero.
Query so far:
SELECT Year(date) AS y, monthname(date) AS m, SUM(price) AS p
FROM orders GROUP BY monthname(date), Year(date) ORDER BY date
Its returning as this:
2020 January someSum
2020 February anotherSum
...etc
Any way to make it return the results as above left to right rather than up-down or am I just that tired and need to go to sleep? I feel I'm confusing something horribly. Someone clarify it for me or chastise me mightly.

You can use conditional aggregation:
select
year(date) year_date,
sum(case when month(date) = 1 then price end) January,
sum(case when month(date) = 2 then price end) February,
sum(case when month(date) = 3 then price end) March,
...
from orders
group by year(date)
order by year_date

Related

How to find difference in same column applying `group by` in SQL?

I need to find the difference between the points grouping by Id column.
Id | Year | Points
---+------+-------
1 | 2017 | 10
1 | 2018 | 20
2 | 2017 | 13
2 | 2018 | 16
3 | 2017 | 25
3 | 2018 | 20
Expected result:
Id | Points
---+-------
1 | 10
2 | 3
3 | -5
do aggregation
select
id,sum(case when year = 2018 then points end) -sum(case when year = 2017 then points end) as diff
from tablename group by id
If you want the difference between the years, you don't need group by:
select t2017.id, t2017.points as points_2017,
t2018.points as points_2018,
(t2018.points - t2017.points) as diff
from t t2017 join
t t2018
on t2017.id = t2018.id and
t2017.year = 2017 and
t2018.year = 2018;
You can do something very similar with conditional aggregation:
select id,
sum(case when year = 2017 then points end) as points_2017,
sum(case when year = 2018 then points end) as points_2018,
(sum(case when year = 2018 then points end) -
sum(case when year = 2017 then points end)
) as diff
from t
group by id;
SELECT *,
points - LAG(points) OVER ( PARTITION BY id
ORDER BY year ) delta_to_prev
FROM sourcetable
PS. Needs MySQL 8+.

Select multiple years in separate columns

I have a table that stores the date and price of purchases.
For example
date | price
---------------------
2014-1-12 | 6.50
2014-2-34 | 10.99
2015-1-01 | 3.22
2015-2-14 | 4.12
And so on.
What I want to achieve: A query that outputs the SUM of the purchases grouped per month of the year.
The IMPORTANT thing is, though, that I need to have the different years in COLUMNS to be able to make a graph with a separate line for each year. So the output I need is this:
MONTH | 2014 | 2015
JAN | 123.23 | 99.1
FEB | 457.00 | 122.00
MAR | 299.99 | 789.12
... |
NOV | 333.33 | 10.99
DEC | 100.00 | 20.10
Is this even possible? I searched quite a long time for things like "year on year" query etc. But I could not find anything.
Any help is greatly appreciated!
Just use conditional aggregation:
select monthname(date) as mon,
sum(case when year(date) = 2014 then price else 0 end) as price_2014,
sum(case when year(date) = 2015 then price else 0 end) as price_2015
from table t
group by monthname(date)
order by max(month(date));

Group and sum data based on a day of the month

I have a reoccurring payment day of 14th of each month and want to group a subset of data by month/year and sum the sent column. For example for the given data:-
Table `Counter`
Id Date Sent
1 10/04/2013 2
2 11/04/2013 4
3 15/04/2013 7
4 10/05/2013 3
5 14/05/2013 5
6 15/05/2013 3
7 16/05/2013 4
The output I want is something like:
From Count
14/03/2013 6
14/04/2013 10
14/05/2013 12
I am not worried how the from column is formatted or if its easier to split into month/year as I can recreated a date from multiple columns in the GUI. So the output could easily just be:
FromMth FromYr Count
03 2013 6
04 2013 10
05 2013 12
or even
toMth toYr Count
04 2013 6
05 2013 10
06 2013 12
If the payment date is for example the 31st then the date comparison would need to be the last date of each month. I am also not worried about missing months in the result-set.
I will also turn this into a Stored procedure so that I can push in the the payment date and other filtered criteria. It is also worth mentioning that we can go across years.
Try this query
select
if(day(STR_TO_DATE(date, "%Y-%d-%m")) >= 14,
concat('14/', month(STR_TO_DATE(date, "%Y-%d-%m")), '/', year(STR_TO_DATE(date, "%Y-%d-%m"))) ,
concat('14/', if ((month(STR_TO_DATE(date, "%Y-%d-%m")) - 1) = 0,
concat('12/', year(STR_TO_DATE(date, "%Y-%d-%m")) - 1),
concat(month(STR_TO_DATE(date, "%Y-%d-%m"))-1,'/',year(STR_TO_DATE(date, "%Y-%d-%m")))
)
)
) as fromDate,
sum(sent)
from tbl
group by fromDate
FIDDLE
| FROMDATE | SUM(SENT) |
--------------------------
| 14/10/2013 | 3 |
| 14/12/2012 | 1 |
| 14/3/2013 | 6 |
| 14/4/2013 | 10 |
| 14/5/2013 | 12 |
| 14/9/2013 | 1 |
Pay date could be grouped by months and year separatedly
select Sum(Sent) as "Count",
Extract(Month from Date - 13) as FromMth,
Extract(Year from Date - 13) as FromYr
from Counter
group by Extract(Year from Date - 13),
Extract(Month from Date - 13)
Be careful, since field's name "Date" coninsides with the keyword "date" in ANSISQL
I think the simplest way to do what you want is to just subtract 14 days rom the date and group by that month:
select date_format(date - 14, '%Y-%m'), sum(sent)
from counter
group by date_format(date - 14, '%Y-%m')

STR_TO_DATE() returns invalid date

I was given a job to create a new table in the database with correct data type. Here are sample records:
RegisteredMonthYear
------------------------
May 2011
March 1998
January 2000
Before I will insert the converted value I tried to convert it using STR_TO_DATE() to check if the values are correct and the result were exactly not I want. This is my query:
SELECT RegisteredMonthYear,
STR_TO_DATE(RegisteredMonthYear, '%M %Y') NewDate,
STR_TO_DATE(CONCAT(RegisteredMonthYear, ' 01'), '%M %Y %d') newDate2,
STR_TO_DATE(RegisteredMonthYear, '%M %Y') + INTERVAL 1 DAY newDate3
FROM TableName
+---------------------+---------------------------------+--------------------------------+----------+
| REGISTEREDMONTHYEAR | NEWDATE | NEWDATE2 | NEWDATE3 |
+---------------------+---------------------------------+--------------------------------+----------+
| May 2011 | April, 30 2011 00:00:00+0000 | May, 01 2011 00:00:00+0000 | (null) |
| March 1998 | February, 28 1998 00:00:00+0000 | March, 01 1998 00:00:00+0000 | (null) |
| January 2000 | December, 31 1999 00:00:00+0000 | January, 01 2000 00:00:00+0000 | (null) |
+---------------------+---------------------------------+--------------------------------+----------+
see here for demo: http://www.sqlfiddle.com/#!2/89a67/7
As you can see, column NEWDATE is one day behind. Why are the result like this?
When I tried to concatenate 01 in the string in column NEWDATE2 the result is as expected. Going back on NEWDATE column, I tried to add one day thinking that it will give exact value in column NEWDATE3 but the result is NULL.
Any idea about this?
You can use following formula (SQLFiddle):
SELECT date(str_to_date(RegisteredMonthYear, '%M %Y'))
+ interval 1 day
FROM tablename
I have added extra DATE() call on top of STR_TO_DATE() - but it makes all the difference.
But in general I agree that this is one more really weird MySQL gotcha.
For example, in PostgreSQL, you don't need to add 1 day and you don't need extra casts, simple to_timestamp is enough:
SELECT to_timestamp('May 2011', 'Mon YYYY');
2013-05-01 00:00:00-07

Group dates by only month and year

Assuming I have a table like the following:
id | assignment | duedate
1 | Math | 2012-01-01
2 | History | 2012-02-02
3 | Science | 2012-01-01
4 | Government | 2012-02-01
5 | Government | 2013-01-13
6 | History | 2013-03-13
Is it possible to make some sql query such that I get a grouping of all the dates by month and year? Is there some possibility that I could get a sorted result of:
duedatemonth | count
January 2012 | 2
Feburary 2012 | 2
January 2013 | 1
March 2013 | 1
I know you can GROUP BY duedate, but that only groups those with the same month, day, and year instead of just month and year.
Would it be then possible to even further group it such that it factors in "assignment" to obtain a resulting table of
id | duedatemonth | count
1 | January 2012 | 2
3 | January 2012 | 2
2 | Feburary 2012 | 2
4 | Feburary 2012 | 2
5 | January 2013 | 1
6 | March 2013 | 1
try this
SELECT DATE_FORMAT(duedate,'%M %Y') duedatemonth, COUNT(*) count
FROM Table1
GROUP BY year(duedate), MONTH(duedate)
DEMO HERE
will output this:
DUEDATEMONTH COUNT
January 2012 2
February 2012 2
January 2013 1
March 2013 1
Use the string functions YEAR and MONTH.
SELECT YEAR(duedate), MONTH(duedate), COUNT(*)
FROM sparkles
GROUP BY YEAR(duedate), MONTH(duedate)
Use MONTHNAME or DATE_FORMAT to get the name of the month.
You can use this query.
SELECT DATE_FORMAT(duedate, '%M %Y') duedatemonth, COUNT(1) `count`
FROM Tbl
GROUP BY DATE_FORMAT(duedate, '%M %Y')