Let's say I have a table that has "user_id, date, score", and every user has exactly one score every month, but not always on the same day.
I want a query that has "user_id, date, score_delta" where score_delta is how much the score will change between "date" and the next month? Am I going to have to do something lame like to_date(to_char(date, ... ?
Here's one way (lameness quotient calculation left as an exercise to the reader):
CREATE TABLE scores (user_id VARCHAR2(32), test_date DATE, score NUMBER);
INSERT INTO scores VALUES('U1',SYSDATE-61, 85);
INSERT INTO scores VALUES('U1',SYSDATE-31, 89);
INSERT INTO scores VALUES('U1',SYSDATE, 92);
INSERT INTO scores VALUES('U2',SYSDATE-61, 65);
INSERT INTO scores VALUES('U2',SYSDATE-31, 89);
INSERT INTO scores VALUES('U2',SYSDATE, 84);
COMMIT;
SELECT s1.user_id, s1.test_date, s2.score-s1.score delta
FROM scores s1
JOIN (SELECT user_id, trunc(test_date,'MM') test_date, score FROM scores) s2
ON (s1.user_id = s2.user_id AND
trunc(add_months(s1.test_date,1),'MM') = s2.test_date);
USER_ID TEST_DATE DELTA
-------------------------------- --------- ----------
U1 9/15/2009 3
U1 8/16/2009 4
U2 9/18/2009 -5
U2 8/19/2009 24
EDIT : It's a slow afternoon, so I decided to look into this analytic function stuff that 10g offers (further dragging myself into the current century ;-), and rewrote the above using the LAG function:
SELECT user_id, test_date, score
, LAG(score, 1, NULL) OVER (PARTITION BY user_id ORDER BY test_date DESC) - score delta
, LAG(score, 1, NULL) OVER (PARTITION BY user_id ORDER BY test_date DESC) AS next_score
FROM scores
ORDER BY 1, 2 DESC;
Which produces:
USER_ID TEST_DATE SCORE DELTA NEXT_SCORE
-------------------------------- ----------- ---------- ---------- ----------
U1 10/19/2009 92
U1 9/18/2009 89 3 92
U1 8/19/2009 85 4 89
U2 10/19/2009 84
U2 9/18/2009 89 -5 84
U2 8/19/2009 65 24 89
Look, Ma! No self-join! Now THAT's slick ;-) (As an aside, the explain plans indicate the self-join is not as efficient).
As a springboard, I started with this asktom.com question .
Something like this should return the user_id, date and score entered next month.
select user_id, date, score from table where
date between ((select sysdate from dual)
and (select add_months(sysdate, 1) FROM dual));
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.