Pergunta

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?

Foi útil?

Solução

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:

  1. Set the EndDate of the current status
  2. Insert a new record

You 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).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top