Search code examples
javasqlpostgresqljooq

PostgreSQL query for currency conversion rates


Let's consider the database table for currency conversion looks as below:

fromCurrency toCurrency effective date conversion rate
USD INR 1-Mar-2024 80
USD INR 1-Jan-2024 85
USD GBP 1-Oct-2023 .80
USD GBP 1-Mar-2024 .85
USD AUD 1-Mar-2023 1.55
USD AUD 1-Mar-2024 1.60

If database is queried on 1-Feb-2024, to get the conversion rate where fromCurrency='USD', it should return

fromCurrency toCurrency effective date conversion rate
USD INR 1-Jan-2024 85
USD GBP 1-Oct-2023 .80
USD AUD 1-Mar-2023 1.55

The same query on 15-April-2024 should return

fromCurrency toCurrency effective date conversion rate
USD INR 1-Mar-2024 80
USD GBP 1-Mar-2024 .85
USD AUD 1-Mar-2024 1.60

Basically for all possible combinations of (fromCurrency, toCurrency) there many many records in the database and on a particular date when the database is queried only one of those many records is applicable based on the effective date. I am trying to figure out the best possible postgres query to get the records.


Solution

  • Both in jOOQ and native PostgreSQL, you can use DISTINCT ON, which is a clause where you can request only the first record per DISTINCT ON expression, given the ORDER BY clause:

    With SQL:

    SELECT DISTINCT ON (fromCurrency, toCurrency) 
      fromCurrency, toCurrency, effectiveDate, conversionRate
    FROM conversions
    WHERE effectiveDate <= :currentDate
    ORDER BY fromCurrency, toCurrency, effectiveDate DESC
    

    With jOOQ (since you tagged the question with jOOQ):

    var c = CONVERSIONS.as("c");
    
    ctx.select(c.FROM_CURRENCY, c.TO_CURRENCY, c.EFFECTIVE_DATE, c.CONVERSION_RATE)
       .distinctOn(c.FROM_CURRENCY, c.TO_CURRENCY)
       .from(c);
       .where(c.EFFECTIVE_DATE.le(currentDate))
       .orderBy(c.FROM_CURRENCY, c.TO_CURRENCY, c.EFFECTIVE_DATE.desc())
       .fetch();
    

    See this db-fiddle