Question

I have a question according SQL. The database is Firebird but that shouldn't matter much as I would like to use ANSI standard if possible.

I have to select a costrate based on the user qualification and the date the user has been assigned that qualification (I hope this sounds right). I have got tables that look like this:

Usertable   Variables      Qualification    Rapportcostrate    Timeaccount
=========   =========      =============    ===============    ===========
UserId      VarId          QuaId            RcrId              TiaID
UserName    VarUserId      QuaName          RcrName            TiaValue
            VarQuaId       QuaRcrId         RcrRate            TiaDate
            VarValidFrom                                       TiaUserId

What I need to get now is this:

UserName, RcrRate, TiaValue, TiaDate

My problem is that the qualification could change at any time and the qualifications that where entered before might still be valid. This should calculate (or select) the

RcrRate * TiaValue 

based on the value in VarValidFrom and TiaDate. I can't bring them together! :-(

Am I making myself clear? I hope so! Please feel free to ask questions at any time!

== Edit 20 hours later ==

I'm using this sql command at the moment:

SELECT RcrRate, VarValidFrom, TiaValue FROM USERTABLE
    JOIN VARIABLES ON UserId = VarUserId
    JOIN QUALIFICATIONS ON VarQuaId = QuaId
    JOIN RAPPORTCOSTRATE ON QuaRcrId = RcrId
    JOIN TIMEACCOUNT ON UserId = TiaUserId
WHERE UserId = XYZ

Now let's say table qualifications is filled with several sets

 Qualifications          Rapportcostrate
 ===============         ===============
 1    Dummy    1         1   Value01   20
 2    Testing  2         2   Value02   30
 3    Another  3         3   Value03   40
 4    FooBar   4         4   Value04   50

If user xyz has three entries in Variables like

 Variables
 =========
 1    1    1    2008-03-01
 2    1    2    2009-04-01
 3    1    3    2010-05-10
 4    1    4    2013-12-12

The expected result should return the RcrRate that fits the VarValidFrom date to the TiaDate. I want to receive only one line per TiaDate.

... it's quite a fight to make oneself clear ... ;-)

Was it helpful?

Solution

There are multiple solutions for this, in the solution below I used CTEs (common table expressions) to split the work in logical units. cteVarTimes selects all valid combinations of Variables and Timeaccount, then cteMostRecent selects the latest for the user. In the main select I combine this with the information from Qualifications and Rapportcostrate.

This solution doesn't work if you need to be able to return rows for all users. In that case you would need to replace cteMostRecent with a query that selects rows using a group wise maximum of VarValidFrom and TiaDate per user.

WITH cteVarTimes AS (    
    SELECT v.VarUserId as UserId, v.VarQuaId, tia.TiaValue, tia.TiaDate, v.VarValidFrom
    FROM Variables v
    INNER JOIN Timeaccount tia
        ON tia.TiaUserId = v.VarUserId
    WHERE tia.TiaDate >= v.VarValidFrom
),
cteMostRecent AS (
    SELECT UserId, VarQuaId, TiaValue, VarValidFrom
    FROM cteVarTimes
    WHERE UserId = 1 -- Parameter in real use
    ORDER BY VarValidFrom DESC, TiaDate DESC
    ROWS 1
)
SELECT RcrRate, TiaValue, VarValidFrom
FROM cteMostRecent a
INNER JOIN Qualifications q
    ON q.QuaId = a.VarQuaId
INNER JOIN Rapportcostrate rcr
    ON rcr.RcrId = q.QuaRcrId
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top