I have a table that logs logins for each user and the current points total of that user at each login.
What I'd like to do is get their first login for each day and calculate the points difference between their previous days' points total.
To make things clearer, I have written a statement that gets each user's min login per day as follows:
SELECT loginLog.username, A.logInDate, loginLog.pointsTotal
FROM loginLog
JOIN
(SELECT MIN(logID) AS logID, username, CAST(logInTime AS DATE) AS logInDate
FROM loginLog
GROUP BY username, CAST(logInTime AS DATE)) A
ON loginLog.logID = A.logID
ORDER BY username, logInDate DESC
Which produces the following results set:
username logInDate pointsTotal
user1 2015-10-28 82685
user1 2015-10-27 51330
user1 2015-10-26 7810
user2 2015-10-28 221223
user2 2015-10-27 207234
user2 2015-10-26 178781
user3 2015-10-28 616120
user3 2015-10-27 598715
user3 2015-10-26 591289
user4 2015-10-28 187654
user4 2015-10-27 198378
user4 2015-10-26 115014
user5 2015-10-28 248138
user5 2015-10-27 224729
user5 2015-10-26 216229
user6 2015-10-28 68546
user6 2015-10-28 24139
user6 2015-10-27 33171
user6 2015-10-27 6459
user6 2015-10-26 6391
So for example, on the first record I'd like to add a column dailyGrowth that would calculate 82685 - 51330, on the second record if would calculate 51330 - 7810 etc etc.
Is this possible?
Since you are using Sql Server 2012
, lead
window function is easiest here:
DECLARE @t TABLE
(
username VARCHAR(10) ,
logInDate DATE ,
pointsTotal INT
)
INSERT INTO @t
VALUES ( 'user1', '2015-10-28', 82685 ),
( 'user1', '2015-10-27', 51330 ),
( 'user1', '2015-10-26', 7810 ),
( 'user2', '2015-10-28', 221223 ),
( 'user2', '2015-10-27', 207234 ),
( 'user2', '2015-10-26', 178781 )
select *, pointsTotal - lead(pointsTotal) over(partition by username order by logInDate desc) AS dailyGrowth
from @t
Output:
username logInDate pointsTotal dailyGrowth
user1 2015-10-28 82685 31355
user1 2015-10-27 51330 43520
user1 2015-10-26 7810 NULL
user2 2015-10-28 221223 13989
user2 2015-10-27 207234 28453
user2 2015-10-26 178781 NULL
To use your existing query:
select *, pointsTotal - lead(pointsTotal) over(partition by username order by logInDate desc) AS dailyGrowth
from (existing query goes here)t
Use correlated sub-query to find previous row's pointsTotal
:
select t1.username, t1.logInDate, t1.pointsTotal,
t1.pointsTotal - (select TOP 1 t2.pointsTotal
from tablename t2
where t2.username = t1.username
and t2.logInDate < t1.logInDate
order by t2.logInDate desc)
from tablename t1
( SELECT TOP 1
is SQL Server specific. The ANSI SQL way is to add fetch first 1 row only
after the ORDER BY
clause. Some other dbms products have LIMIT 1
instead.)
Assuming that your result view in your question (with the pointsTotal) is called loginPoints
you can join the table with itself using the username and the date. To get the next date you can use DATEADD
:
SELECT username,p1.loginDate, p1.pointsTotal-p2.PointsTotal AS dailyGrowth
FROM loginPoints p1 inner join loginPoints p2 on
p1.username=p2.username AND DATEADD(day,1,p2.loginDate)=p1.loginDate
Note that depending on which DBMS you use, the DATEADD
function can be slightly different.
Create a view on your above query and then use analytical lead()
function that get next row value and then calculate the difference of first value.
Detail here
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.