MySQL: Get difference between two values in one table (multiple userids)? - mysql

I was trying to find a solution but did not succeed even if it seems simple. So this might be a newbie question...
I have a table userscores with 3 columns:
date userid points
2012-05-01 1 23
2012-06-01 1 34
2012-07-01 1 44
2012-05-01 2 78
2012-06-01 2 94
2012-07-01 2 99
2012-06-01 3 2
2012-07-01 3 9
Now I need to get the difference of the points between 2012-05-01 and 2012-06-01 for each user.
Users' points that are not existing (example userid 3) have to be calculated as 2 - 0... for this I guess I can use COALESCE(qa_points,0).
I read about combining two subqueries for the calculation but failed implementing it.
Any help appreciated.
PS: This is not working:
SELECT t1.userid, t1.points - t2.points AS mpoints FROM (
SELECT userid,points FROM `userscores`
WHERE YEAR(date) = YEAR('2012-05-01')
AND MONTH(date) = MONTH('2012-05-01') )
AS t1
JOIN (
SELECT userid,points FROM `userscores`
WHERE YEAR(date) = YEAR('2012-04-01')
AND MONTH(date) = MONTH('2012-04-01') )
AS t2
ORDER BY mpoints DESC, t1.userid DESC;

I suppose your query will look like this:
SELECT ul.userid,
ul.points - COALESCE(uf.points, 0) AS points_difference
FROM userscores ul
LEFT JOIN
(SELECT userid, points FROM userscores WHERE `date` = '2012-05-01') AS uf
ON uf.userid = ul.userid
WHERE ul.date = '2012-06-01'
LEFT JOIN is used because you told that there may be no records for this user/former date combination.

Use this query:
SELECT t1.userid,
( t1.points - (case t2.date when '2012-05-01' then t2.points else 0 end))
AS mpoints FROM userscores as t1
INNER JOIN userscores as t2
ON t1.date = '2012-06-01' AND t1.userid=t2.userid

Related

Select difference based on record having minimum and maximum date in MySql

Below is my table let's call account
**ID accountID score tracking_date
1 1 3 2014-09-25 00:01:05
2 2 4 2014-09-26 01:05:18
3 1 6 2014-09-27 09:23:05
4 2 9 2014-09-28 20:01:05
5 1 1 2014-09-28 23:21:34
6 3 7 2014-09-21 00:01:00
7 2 1 2014-09-22 01:45:24
8 2 9 2014-09-27 14:01:43
9 3 1 2014-09-24 22:01:27
I want to select record with max date and also the difference of score with the records having tracking_date as minimum for that accountId. So I want output like below
ID accountID score_with_maxdate diff_score_with_mindate max_tracking_date
1 1 1 -2 2014-09-28 23:21:34
2 2 9 8 2014-09-28 20:01:05
3 3 1 -6 2014-09-24 22:01:27
Any help?
Here is one option. We can self-join a subquery which finds both the min and max tracking dates, for each account, twice to your original table. This will bring in all metadata for those max tracking date records, including the scores.
SELECT
t1.accountID,
t2.score AS score_with_maxdate,
t2.score - t3.score AS diff_score_with_mindate,
t1.max_tracking_date
FROM
(
SELECT
accountID,
MAX(tracking_date) AS max_tracking_date,
MIN(tracking_date) AS min_tracking_date
FROM yourTable
GROUP BY accountID
) t1
INNER JOIN yourTable t2
ON t1.accountId = t2.accountID AND t2.tracking_date = t1.max_tracking_date
INNER JOIN yourTable t3
ON t1.accountId = t3.accountID AND t3.tracking_date = t1.min_tracking_date
ORDER BY
t1.accountID;
Demo
This is a somewhat tricky question. I think conditional aggregation is a convenient way to solve the problem:
select min(t.id) as id, t.accountId,
max(case when t.tracking_date = t2.max_td then t.score end) as score_with_maxdate,
max(case when t.tracking_date = t2.max_td then t.score
when t.tracking_date = t2.min_td then - t.score
end) as diff_score_with_mindate,
max(t.tracking_date) as max_tracking_date
from t join
(select t2.accountId, min(t2.tracking_date) as min_td, max(t2.tracking_date) as max_td
from t t2
group by t2.accountId
) t2
on t.accountId = t2.accountId
group by t.accountId;
Another hackish way of getting same results by using aggregate and string fucntion
select t.accountID,
t.score_with_maxdate,
t.score_with_maxdate - t.score_with_mindate score_with_maxdate,
t.max_tracking_date
from(
select accountID,
substring_index(group_concat(score order by tracking_date desc),',', 1) + 0 score_with_maxdate,
substring_index(group_concat(score order by tracking_date asc),',', 1) + 0 score_with_mindate,
max(tracking_date) max_tracking_date
from demo
group by accountID
) t
Demo
But i would suggest you to go with other solutions mentioned by Tim & Gordon

Get the Sum of Two Table GROUP BY date in year

I'm making a donation report, I have two tables tbldonation and tblpubdonation
I want to get their sum group by year.
tbldonation:
amount | received
100 : 2016-01-02 08:42:20
100 : 2015-12-01 09:20:00
tblpubdonation:
amount | received
100 : 2015-12-22 09:20:00
My query is :
SELECT * from
(
(SELECT YEAR(received) as YY, sum(amount) as AMT FROM tbldonation)
UNION ALL
(SELECT YEAR(received) as YY, sum(amount) as AMT FROM tblpubdonation)
) results
WHERE results.YY <= Curdate()
GROUP BY results.YY
ORDER BY results.YY DESC
I'm getting a result but it's not accurate.
It should be
YY | AMT
2016 : 100
2015 : 200
But my result is:
YY | AMT
2016 : 200
2015 : 100
The value is misplaced.
Try following for MySql (Since MySQL lacks support for FULL JOIN. we have to simulate It)
SELECT Yr , SUM(amountSum)
FROM ( SELECT SUM(ISNULL(t1.amount, 0)) AS amountSum ,
t1.year AS Yr
FROM tbldonation t1
GROUP BY t1.YEAR
UNION ALL
SELECT SUM(ISNULL(t2.amount, 0)) AS amountSum ,
t2.year AS Yr
FROM tblpubdonation t2
GROUP BY t2.YEAR
) Tbl
GROUP BY Tbl.Yr
Following works for T-SQL
SELECT SUM (ISNULL(t1.amount,0)) + SUM(ISNULL(t2.amount,0)), ISNULL(t1.YEAR,t2.YEAR)
FROM dbo.tbldonation t1
FULL OUTER JOIN dbo.tblpubdonation t2 ON t1.YEAR = t2.YEAR
GROUP BY t1.YEAR, t2.YEAR
You are using sum(amount) in the query .So in tbldonation the sum becomes .In pbldonationsum(amount)=100.At the end the order is given by years .So 2016 is at first and 2015 at the end.Year 2015 wont get the amount value 200 because union operator is used and both are having 2015 as common .So this is to chabged in the data itself as per me or else some data glitch.If I am wrong please suggest me also so that I can improve myself.
Thank you.
Regards, Raju.

how to get latest record or record with max corresponding date of all distinct values in a column in mysql?

For Example, I have table like this:
Date | Id | Total
-----------------------
2014-01-08 1 15
2014-01-09 3 24
2014-02-04 3 24
2014-03-15 1 15
2015-01-03 1 20
2015-02-24 2 10
2015-03-02 2 16
2015-03-03 5 28
2015-03-09 5 28
I want the output to be:
Date | Id | Total
---------------------
2015-01-03 1 20
2014-02-04 3 24
2015-03-02 2 16
2015-03-09 5 28
Here the distinct values are Id. I need latest Total for each Id.
You can use left join as
select
t1.* from table_name t1
left join table_name t2
on t1.Id = t2.Id and t1.Date >t2.Date
where t2.Id is null
http://dev.mysql.com/doc/refman/5.0/en/example-maximum-column-group-row.html
You can also use Max() in sql:
SELECT date, id, total
FROM table as a WHERE date = (SELECT MAX(date)
FROM table as b
WHERE a.id = b.id
)
You can do it as below
SELECT *
FROM YourTable D
WHERE date = (SELECT MAX(date) FROM YourTable WHERE ID = D.ID)
Another way is by using INNER JOIN
Find the latest date per ID then join result back to the table to get the value
select A.ID,A.Date,A.value
from yourtable A
INNER JOIN
(
select MAX(date) as Date,ID
from yourtable
group by ID
) B
ON A.ID =B.ID and A.Date = B.Date
The other answers didn't work for me. I found the following code, which worked great for me:
SELECT * FROM TABLE WHERE DATE IN (SELECT MAX(DATE) FROM TABLE)
I am using SSMS 2014, SQLServer

MySQL :: group by between price AND two dates

I have a table like following columns:
id date price pid
---------------------------
1 2015-02-01 34 2
2 2015-02-02 34 2
3 2015-02-03 34 2
4 2015-02-04 78 2
5 2015-02-05 78 2
6 2015-02-06 78 2
7 2015-02-07 52 2
8 2015-02-08 52 2
9 2015-02-09 52 2
10 2015-02-10 34 2
11 2015-02-11 34 2
12 2015-02-12 34 2
Now I want following result:
date_from date_to price pid
-------------------------------------
2015-02-01 2015-02-03 34 2
2015-02-04 2015-02-06 78 2
2015-02-07 2015-02-09 52 2
2015-02-10 2015-02-12 34 2
IMPORTANT:
I don't want to group the price "34" in this case.
One solution i can think of using user defined variables also i assume the id part is set to auto_increment
select min(t1.date) date_from,
max(t1.date) date_to,
t1.price,
t1.pid
from (
select t.*,
#r:= case when #g = price then #r else #r + 1 end r,
#g:= price g
from test t
cross join (select #g:=null,#r:=0) t
order by id
) t1
group by t1.r
DEMO
Borrowing M Khalid Junaid's fiddle...
SELECT a.date date_from
, MIN(c.date) date_to
, price
, pid
FROM test a
LEFT
JOIN test b
ON b.pid = a.pid
AND b.price = a.price
AND b.id = a.id - 1
LEFT
JOIN test c
ON c.pid = a.pid
AND c.price = a.price
AND c.id >= a.id
LEFT
JOIN test d
ON d.pid = a.pid
AND d.price = a.price
AND d.id = c.id + 1
WHERE b.id IS NULL
AND c.id IS NOT NULL
AND d.id IS NULL
GROUP
BY a.id, a.price, a.pid;
http://sqlfiddle.com/#!2/478f9/6
Try below query, it will group by three records on basis of date and price
SELECT min(created) AS date_from, max(created) AS date_to, price, pid
FROM t1
GROUP BY price, floor(DATEDIFF("2015-02-01", created) / 3);
Try this in MySQL. Here app_date is Date in your question:
set #rownum=1;
select min(app_date),max(app_date),price,pid from
(select t.id1 id,t.app_date app_date,t.price1 price,t.pid pid,
case when (t.price1=t.price2 or t.price2 is null) then #rownum else #rownum:=#rownum+1 end temp_num from
(select a.id id1,b.id id2,a.app_date app_date,a.price price1,b.price price2,a.pid pid from
test a left outer join test b on a.id=b.id+1) t
order by id1) temp
group by price,pid,temp_num
order by min(app_date);

select price having max year in another column

I have following select result
Code Price Year
1 200 2013
1 100 2012
2 250 2011
2 275 2012
2 300 2010
But I want following something like this with one extra column which hold price based on maximum year,
Code Price Year ExPrice
1 200 2013 200
1 100 2012 200
2 250 2011 275
2 275 2012 275
2 300 2010 275
Sorry for bad English and wrong way for asking this question.
You can do it with cross apply and select top 1 ... order by:
select Code, Price, Year, ExPrice
from TableName T
cross apply (
select top 1 Price
from TableName
where Code = T.Code
order by Year desc
) p(ExPrice)
or row_number and join (whatever you prefer):
;with cte as (
select Code, Price as ExPrice, rn = row_number() over (partition by Code order by Year desc)
from TableName
)
select T.Code, Price, Year, ExPrice
from TableName T
join cte on cte.Code = T.Code and cte.rn = 1
SQLFiddle sample
Try something like this:
SELECT T1.Code, T1.Price, T1.Year, T2.Price
FROM Table T1
INNER JOIN Table T2 ON T1.Code = T2.Code AND
T2.Year = (SELECT MAX(Year) FROM Table WHERE Table.Code = T2.Code)