January 27, 2011 at 1:12 pm
(update: DDL is now posted lower in the thread.)
I apologize for the formatting, I've looked on the site to try to figure out how to post a table on the forums properly (If someone could give me a pointer in that direction, I'd appreciate it.)
I have a couple of tables and need to join them, but with a twist.
Table A has Student IDs, the Effective Date of the grade change, and the Grade they were
changed to ON that date:
IDEffDateGrade
6784432007-01-24 14:40:27.070Kindergarten - Half Day
6784432007-07-04 23:09:47.710Grade 1
6784432008-07-02 23:35:57.993Grade 2
6784432009-07-02 23:30:43.557Grade 3
7184662009-08-27 23:18:48.673Pre-Kindergarten
7184662010-07-09 23:18:52.717Kindergarten - Half Day
7184662010-08-02 23:14:53.147Pre-Kindergarten
7184662009-05-18 23:50:23.973Pre-Kindergarten
7184662009-07-02 23:27:47.673Kindergarten - Half Day
Table B has IDs and EventDates that occurred on a certain date:
IDEventDate
7184662010-11-16 00:00:00.000
7184662009-05-20 00:00:00.000
6784432007-12-07 00:00:00.000
What I need is the ID and EventDate from Table B, and the Grade from Table A, joining on ID, where the the EffDate on Table A is the most recent date but is not PAST the EventDate on Table B.
In other words, students get their grade changed on a yearly basis. When I look at an EventDate, I need to know what grade they were in at the time of that event -- so it will be the most recent grade change that occurred prior to the EventDate. Students may have multiple events, and we can assume all will have at least one Table A entry with a EffDate prior to any Table B EventDate entry.
In the case of the above tables, it would be something like:
IDEventDateGrade
6784432007-07-04Grade 1
7184662010-08-02Pre-Kindergarten
7184662009-05-18Pre-Kindergarten
I've spent a great deal of time on this, and sometimes almost seem to have it, but can't quite get it to work.
Thank you -- as a newbie, I certainly appreciate your help!
January 27, 2011 at 1:18 pm
daniel.potter (1/27/2011)
I apologize for the formatting, I've looked on the site to try to figure out how to post a table on the forums properly (If someone could give me a pointer in that direction, I'd appreciate it.)
Regarding this question I can certainly help 🙂
Look at the link in my signature on how to post questions. It will explain in detail how to post code on this site.
Good luck!
Need an answer? No, you need a question
My blog at https://sqlkover.com.
MCSE Business Intelligence - Microsoft Data Platform MVP
January 27, 2011 at 1:28 pm
Allright, I took a try at your problem.
I haven't tested it yet, but when you post the DDL statements and the INSERTS statements for sample data, the statement will be easy to test.
SELECT
ID= temp2.ID
,EventDate= temp2.EventDate
,Grade= temp2.Grade
FROM
(SELECT
temp.ID
,temp.EventDate
,temp.Grade
,ROW_NUMBER() OVER (PARTITION BY temp.ID ORDER BY temp.EventDate DESC) rid
FROM
(SELECT B.ID, B.EventDate, A.Grade
FROMTable_A A
INNER JOIN
Table_B B
ONA.ID = B.ID
ANDA.EventDate <= B.EventDate
) temp
) temp2
WHERE temp2.rid = 1
The most inner query (temp) performs an inner join between the two tables and it rules out rows from table A who are more recent than the EventDate from table B.
The second inner query takes those results and adds a row_number for each ID, starting with the most recent date. (look up the row_number() function for more information). Finally, I only select the rows with row ID = 1, ergo the most recent date.
I don't know if it is the most elegant solution, but I think it will get the job done.
Need an answer? No, you need a question
My blog at https://sqlkover.com.
MCSE Business Intelligence - Microsoft Data Platform MVP
January 28, 2011 at 7:50 am
Hi, thank you for your help!
Here's the DDL, with some changes to (hopefully) make the data more intuitive:
/* If the test table already exists, drop it */
IF OBJECT_ID('TempDB..#GradeChange','U') IS NOT NULL
DROP TABLE #GradeChange;
GO
IF OBJECT_ID('TempDB..#EventOccurrence','U') IS NOT NULL
DROP TABLE #EventOccurrence;
GO
/* Create first temp table */
CREATE TABLE #GradeChange
(
ID varchar(6),
EffectiveDate datetime,
Grade varchar(50)
);
GO
/* Populate it */
INSERT INTO #GradeChange
(ID, EffectiveDate, Grade)
SELECT '678443','Jul 2 2009 11:30PM','Grade 3' UNION ALL
SELECT '678443','Jan 24 2007 2:40PM','Kindergarten - Half Day' UNION ALL
SELECT '678443','Jul 4 2007 11:09PM','Grade 1' UNION ALL
SELECT '678443','Jul 2 2008 11:35PM','Grade 2' UNION ALL
SELECT '718466','May 18 2009 11:50PM','Pre-Kindergarten' UNION ALL
SELECT '718466','Jul 2 2009 11:27PM','Kindergarten - Half Day' UNION ALL
SELECT '718466','Aug 27 2009 11:18PM','Pre-Kindergarten' UNION ALL
SELECT '718466','Jul 9 2010 11:18PM','Kindergarten - Half Day' UNION ALL
SELECT '718466','Aug 2 2010 11:14PM','Kindergarten';
GO
/* Create 2nd temp table */
CREATE TABLE #EventOccurrence
(
ID varchar(6),
EventDate datetime
);
GO
/* Populate it */
INSERT INTO #EventOccurrence
(ID, EventDate)
SELECT '718466','Nov 16 2010 12:00AM' UNION ALL
SELECT '718466','May 20 2009 12:00AM' UNION ALL
SELECT '678443','Dec 7 2007 12:00AM';
GO
So the two tables would look like this:
And the expected results would look like this:
I've tried the code you posted, with (I think) appropriate changes:
SELECT
ID = temp2.ID
,EventDate = temp2.EventDate
,Grade = temp2.Grade
FROM
(SELECT
temp.ID
,temp.EventDate
,temp.Grade
,ROW_NUMBER() OVER (PARTITION BY temp.ID ORDER BY temp.EventDate DESC) rid
FROM
(SELECT B.ID, B.EventDate, A.Grade
FROM #GradeChange A
INNER JOIN
#EventOccurrence B
ON A.ID = B.ID
AND A.EffectiveDate <= B.EventDate
) temp
) temp2
WHERE temp2.rid = 1
But for ID # 718466, I only get one line returned: 718466 / 2010-11-16 00:00:00.000 / Pre-Kindergarten
I'd expect two results for this student, one for each event, as in the results image above.
Thanks again!
January 28, 2011 at 10:48 am
I've found a solution that works:
select eo.ID, eo.EventDate, gc.Grade
from #EventOccurrence eo
inner join #GradeChange gc
on eo.ID = gc.ID
and gc.EffectiveDate = (select max(gc.EffectiveDate)
from #GradeChange gc
where gc.ID = eo.ID
and gc.EffectiveDate <= eo.EventDate)
January 28, 2011 at 12:00 pm
d.potter (1/28/2011)
I've found a solution that works:
select eo.ID, eo.EventDate, gc.Grade
from #EventOccurrence eo
inner join #GradeChange gc
on eo.ID = gc.ID
and gc.EffectiveDate = (select max(gc.EffectiveDate)
from #GradeChange gc
where gc.ID = eo.ID
and gc.EffectiveDate <= eo.EventDate)
Great. Good that you found the solution and thanks for posting it here.
I guess I didn't read your requirements too well, since I didn't return those two rows :S
Need an answer? No, you need a question
My blog at https://sqlkover.com.
MCSE Business Intelligence - Microsoft Data Platform MVP
Viewing 6 posts - 1 through 6 (of 6 total)
You must be logged in to reply to this topic. Login to reply