Reputation: 123
This seems like it should be relatively (no pun intended) easy to do, but I just can't get my mind around it. I have three tables, joined in a many-to-many relationship. A main "Issues" table, a "Statuses" table (lookup table indicating the name/description of different statuses: 'Open', 'In Progress', 'Closed', etc.), and a middle "IssuesStatuses" table to allow multiple statuses over time for the primary "Issues" record. I'm trying to write the T-SQL to get a list of "Issues", along with the most recent StatusName, based on the most recent related record in the IssuesStatuses table. Here's what the tables look like:
[Issues] table:
- IssueID (PK)
- IssueName
- IssueDescription
etc.
[IssuesStatuses] table:
- IssuesStatusesID (PK)
- IssueID (FK)
- StatusID (FK)
- IssuesStatusDate
[Statuses] table:
- StatusID (PK)
- StatusName
Users will add multiple records (for the same IssueID) to the IssuesStatuses table as they update the status of the main Issues record. So this query should get the [Issues] record, the most recent status for this record from the [IssuesStatuses] table, and the associated StatusName record from the [Statuses] table that's associated with that IssuesStatuses record. I'm pretty sure I need subquery(ies), and/or Max(StatusDate) functions, but I start writing too complicated nested subqueries when I attempt this in the SQL.
Does this make sense? Can someone please assist me with this?
Upvotes: 0
Views: 320
Reputation: 1270713
The statuses are what is referred to as a slowly changing dimension. One way to deal with these is to have an "effective" and "end" date for the records. With EffDate
and EndDate
, the query that you want would be quite easy, either:
select *
from IssueStatus ist
where EndDate is NULL
or
where EndDate = '9999-01-01' -- or whatever your far out future date is
The downside is that inserting a new status requires two steps:
EndDate
of the current statusYou would typically encapsulate this logic in a stored procedure or trigger.
Given your data structure, you can get the most recent status by using not exists
:
select ist.*
from IssueStatus ist
where not exists (select 1
from IssueStatus ist2
where ist2.issueId = ist.issueId and
ist2.IssueStatusDate > ist.IssueStatusDate
)
The logic is "Get me all rows from IssueStatus
where the given Issue has no later status date." That is equivalent to saying: "Get me the row with the maximum date." But for some reason, the database engine will do a good job optimizing this query when you have an index on IssueStatus(IssueId, IssueStatusDate)
.
Upvotes: 2