Finding the difference between consecutive rows in MySQL without LAG? - mysql

For each month (except January) I would like to find the difference in quantity from the previous month.
I have a table:
Month
Qty
January
4
February
3
March
9
April
3
May
7
and I would like to return:
Month
Difference
February
-1
March
6
April
-6
May
4
I'm using an older version of MySQL, so I can't use LEAD/LAG for this.

SELECT t1.`Month`, COALESCE(t1.Qty - t2.Qty, 'Unknown') Difference
FROM table t1
LEFT JOIN table t2
ON STR_TO_DATE(CONCAT(t1.`Month`, ' 01 2021'), '%M %d %Y')
= STR_TO_DATE(CONCAT(t2.`Month`, ' 01 2021'), '%M %d %Y') + INTERVAL 1 MONTH

You can use a correlated subquery to get the previous value. If the first column is really ordered, then you can use:
select t.*, (qty - prev_qty) as difference
from (select t.*,
(select t2.qty
from t t2
where t2.month < t.month
order by t2.month desc
limit 1
) as prev_qty
from t
) t
where prev_qty is not null;
If you are really storing months as a string name, then you need to convert to something orderable:
select t.*, (qty - prev_qty) as difference
from (select t.*,
(select t2.qty
from t t2
where str_to_date(concat(t2.month, ' 1 2000', '%M %d %Y') < str_to_date(concat(t.month, ' 1 2000', '%M %d %Y')
order by str_to_date(concat(t2.month, ' 1 2000', '%M %d %Y') desc
limit 1
) as prev_qty
from t
) t
where prev_qty is not null;

Related

Get name of last two months in SQL

I have a query that compares this month's numbers to last month and upper month. The only issue is that colleagues complain about the labelling.
I have used M1 = last month and M2 = upper month, but some people still get it mixed up. I want to put in the actual month instead of M1, M2 and so on. Any ideas would help. This is my code
SELECT *,
CONCAT(FORMAT((current_downloads/M_1)*100,2),'%') AS `M_1_Ratio`,
CONCAT(FORMAT((current_downloads/M_2)*100,2),'%') AS `M_2_Ratio`
FROM
(SELECT count(*) AS current_downloads
FROM `purchase`
WHERE date(`purchase`.`timestamp`) >= DATE_FORMAT(NOW() ,'%Y-%m-01')) t1
JOIN
(SELECT count(*) AS M_1
FROM `purchase`
WHERE date(`purchase`.`timestamp`) BETWEEN DATE_SUB(DATE_FORMAT(NOW(),'%Y-%m-01'), INTERVAL 1 MONTH) AND DATE_SUB(DATE(NOW()), INTERVAL 1 MONTH)) t2
JOIN
(SELECT count(*) AS M_2
FROM `purchase`
WHERE date(`purchase`.`timestamp`) BETWEEN DATE_SUB(DATE_FORMAT(NOW(),'%Y-%m-01'), INTERVAL 2 MONTH) AND DATE_SUB(DATE(NOW()), INTERVAL 2 MONTH)) t3
That gives something like this.
I need the header names to be actual months.
This is a horrible hack (and will only work if your output is purely for presentation), but you could just add another line of data to the table which includes the month names by using a UNION:
SELECT DATE_FORMAT(NOW(), '%b %y') as Current_Downloads, DATE_FORMAT(NOW() - INTERVAL 1 MONTH, '%b %y') as M_1, DATE_FORMAT(NOW() - INTERVAL 2 MONTH, '%b %y') as M_2, DATE_FORMAT(NOW() - INTERVAL 1 MONTH, '%b %y') as M_1_Ratio, DATE_FORMAT(NOW() - INTERVAL 2 MONTH, '%b %y') as M_2_Ratio
UNION ALL
... your query ...
This will give you something that looks like this:
Current Downloads M_1 M_2 M_1_Ratio M_2_Ratio
Mar 18 Feb 18 Jan 18 Feb 18 Jan 18
12,168 12,121 13,345 100.39% 91.18%

mysql counts in a month and total counts upto month

I want the count of records in every month and total count of records from start upto that month.
For ex.,
I have a table that looks like this:
#id,created#
1,'2016-01-01'
2,'2011-02-02'
3,'2011-02-09'
4,'2011-02-05'
5,'2011-03-07'
6,'2011-03-08'
How do I select and group these so the output is:
#Month, new, total#
Jan 2016, 1, 1
Feb 2016, 3, 4
Mar 2016, 2, 6
Thanks very much.
Here you go:
SELECT DATE_FORMAT(`created`,'%M %Y') AS month, COUNT(*) AS count,
(SELECT count(*) FROM test WHERE MONTH(created) <= MONTH(t.created)) AS total
FROM test t
GROUP BY MONTH(created);
Here's the SQL Fiddle.
Using single table read:
SELECT
CONCAT(LEFT(MONTHNAME(dt), 3), ' ', YEAR(dt)) month,
new,
#total:=#total + new total
FROM
(SELECT
created - INTERVAL DAY(created) - 1 DAY dt, COUNT(*) new
FROM
t
GROUP BY created - INTERVAL DAY(created) - 1 DAY
ORDER BY dt) t
CROSS JOIN
(SELECT #total:=0) t2
Demo

Diplaying records of last month and year

I am having a table in MYSQL in which among other fields i am having two fields one for Month (Varchar) and year (int). Months field is used to store the name of the month and year is used to store the year of the entered data. I am confused that how can use the where class to display only the records of max month and year.
For Example
10 records are there for month January 2013
50 records are there for month February 2013
.
.
.
100 records are there for the month of November 2014 --- (LAST ENTRY)
Now
HERE I want to display only the November 2014 records. My code is written in such a way that i can not use the select query, I have to do it using WHERE CLAUSE
SELECT *
FROM tablename
WHERE
(year, month) = (SELECT year, month
FROM tablename
ORDER BY
STR_TO_DATE(CONCAT_WS(' ', '01', month, year), '%d %M %Y') DESC
LIMIT 1)
select count(*), year, month
from your_table
group by year, month
order by year,
case when month = 'January' then 1
when month = 'February' then 2
when month = 'March' then 3
when month = 'April' then 4
when month = 'May' then 5
when month = 'June' then 6
when month = 'July' then 7
when month = 'August' then 8
when month = 'September' then 9
when month = 'October' then 10
when month = 'November' then 11
when month = 'December' then 12
end desc
limit 1
Try This
select Count(*),month,year from tablename
group by STR_TO_DATE(CONCAT_WS(' ', '01', month, year), '%d %M %Y') order by
STR_TO_DATE(CONCAT_WS(' ', '01', month, year), '%d %M %Y')

Is subquery the solution to this?

Here's the table structure and some sample data:
pID.....month.....year
27 .....3 .....2008
27 .....12 .....2012
31 .....6 .....2008
99 .....1 .....2006
42 .....1 .....2009
pID is the practiceID and month and year represent the date period they've entered data for. I need to grab the number of practices that have entered data for the first time in Oct 2012, Nov 2012, Dec 2012 and so on.
I tried the following query for Oct 2012:
SELECT *
FROM
IPIPKDIS
where
practiceID NOT IN (
SELECT practiceID
from
IPIPKDIS
where
year < 2012 and month < 10
)
and year = 2012
and month = 10
and measureCatRecID = 2
ORDER BY year, month;
but it's grabbing months and year less than 10/2012.
If I run the queries isolated (not as subquery) they both work fine.
Any ideas?
This summary query will yield the first (smallest) date in the table for each value of practiceID.
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
If you want to retrieve then the whole row for the first reported month, you'd do a nested query like this:
SELECT *
FROM IPIPKDIS I
JOIN (
SELECT practiceID,
MIN(STR_TO_DATE( CONCAT(year, ' ', month), '%Y %m')) first_date
FROM IPIPKDIS
GROUP BY practiceID
) first ON ( first.practiceID = I.practiceID
AND STR_TO_DATE( CONCAT(I.year, ' ', I.month), '%Y %m') = first.first_date)
The trick to the second query is to use the JOIN to extract just the first-month rows from your table. We use date arithmetic to do the date comparisons.

union of two queries to get the result in mysql

I'm confused about this:
SELECT request_id, SUM( cc_amount ) AS amt,
DATE_FORMAT( transaction_datetime, '%b %y' ) AS tdate
FROM ee_request_cc
GROUP BY DATE_FORMAT( transaction_datetime, '%b %y' )
UNION
SELECT request_id, SUM( request_amount ) AS amt,
DATE_FORMAT( transaction_date, '%b %y' ) AS tdate
FROM ee_request_paypal
GROUP BY DATE_FORMAT( transaction_date, '%b %y' )
I'm getting:
id amt tdate
20 86.00 Mar 12
80 5.00 Apr 12
23 55.00 Mar 12
Whereas I want to add all amounts for March and April like:
id amt tdate
20 141.00 Mar 12
80 5.00 Apr 12
Please suggest me the change in my query.
Try this:
select sum(amt), DATE_FORMAT(tdate, '%b %y') from (
SELECT amount1 AS amt, transaction_dt AS tdate
FROM table1
UNION ALL
SELECT request_amount, tr_date
FROM table2
) s
GROUP BY YEAR(tdate), MONTH(tdate)
Note you shouldn't take an ID from a grouped result... which one would you take?
Also grouping by numbers must be faster than transforming a date to a string and then grouping by string.
You need to get all the results, and then perform the aggregation:
SELECT table_both.request_id, table_both.tdate, SUM(table_both.amount) AS amt
FROM (SELECT request_id, cc_amount AS amt, DATE_FORMAT(transaction_datetime,'%b %y') AS tdate
FROM table1
UNION ALL --Don't remove the duplicates
SELECT request_id, request_amount, DATE_FORMAT(transaction_date,'%b %y')
FROM table2) table_both
GROUP BY table_both.request_id, table_both.tdate --You don't need to add the format function in the group by
You use an englobing SELECT with sum on amt and GROUP BY tdate
SELECT id, SUM(amt) as samt, tdate
FROM (YOUR_ABOBE_QUERY) AS thequery
GROUP BY thequery.tdate