简体   繁体   中英

Select last set of records in sql group

I have an Orable database with a table like follows:

ID  PROVIDER_ID FROM_CURRENCY   TO_CURRENCY         DATE    AMOUNT  ACTIVE  
1             1           USD           EUR    06-FEB-19      1.23     1
2             2           USD           EUR    06-FEB-19       1.5     1
3             1           GBP           EUR    06-FEB-19      1.23     1
4             1           CAD           EUR    06-FEB-19      1.23     1
5             1           USD           EUR    05-FEB-19       0.7     1
6             1           GBP           EUR    05-FEB-19       0.7     1

As you can see, we store exchange rates from different providers with its date, and what I need is to get the IDs of the latest available rates for a specific to_currency (eg. EUR) and provider_id (eg. 1) at a certain date. So I should get something like follows:

ID
1
3
4

Please be aware that DATE is not unique so values can be duplicated among different rows and I can not use it to join with a subquery. Also, consider that DATE and ID are not correlated, so higher dates don't necessarily mean higher IDs (I cannot just use MAX(ID) in the select clause to get the ID of the target row).

I have tried with the following query, but I get an error ORA-00979: not a GROUP BY expression

SELECT ID 
FROM EXCHANGE_RATE
WHERE ACTIVE = 1 AND PROVIDER_ID = 1 AND TO_CURRENCY = 'EUR' AND DATE <= TO_DATE('2019-02-06', 'YYYY-MM-DD')
GROUP BY PROVIDER_ID, FROM_CURRENCY, TO_CURRENCY
HAVING DATE = MAX(DATE)

I've also tried the following query with the same error:

SELECT ID, MAX(DATE)
FROM EXCHANGE_RATE
WHERE ACTIVE = 1 AND PROVIDER_ID = 1 AND TO_CURRENCY = 'EUR' AND DATE <= TO_DATE('2019-02-06', 'YYYY-MM-DD')
GROUP BY PROVIDER_ID, FROM_CURRENCY, TO_CURRENCY

The query that retrieves the rows I need is the following one, but I don't know how to obtain the ID field for these rows since ID is not part of the group by clause.

SELECT MAX(DATE)
FROM EXCHANGE_RATE
WHERE ACTIVE = 1 AND PROVIDER_ID = 1 AND TO_CURRENCY = 'EUR' AND DATE <= TO_DATE('2019-02-06', 'YYYY-MM-DD')
GROUP BY PROVIDER_ID, FROM_CURRENCY, TO_CURRENCY

Any idea about how can achieve what I need?

EDIT I think I've found a solution

SELECT ID
FROM EXCHANGE_RATE E JOIN
  (SELECT PROVIDER_ID, FROM_CURRENCY, TO_CURRENCY, MAX(DATE) AS LATEST
    FROM EXCHANGE_RATE
    WHERE DATE <= TO_DATE('2019-02-06', 'YYYY-MM-DD')
    GROUP BY PROVIDER_ID, FROM_CURRENCY, TO_CURRENCY) LATEST_EX
  ON E.PROVIDER_ID = LATEST_EX.PROVIDER_ID
  AND E.TO_CURRENCY = LATEST_EX.TO_CURRENCY
  AND E.FROM_CURRENCY = LATEST_EX.FROM_CURRENCY
  AND E.DATE = LATEST_EX.LATEST
WHERE E.ACTIVE = 1 AND E.PROVIDER_ID = 1 AND E.TO_CURRENCY = 'EUR'

user row_number() function to rank the dates in descending order for each currency

SELECT id
FROM
  (SELECT id, provider_id, from_Currency,
          row_number() over 
          ( partition by from_Currency order by "DATE" desc ) as rn
     FROM EXCHANGE_RATE
  )
WHERE rn=1

The easiest way to write a stored proc to hold the data row returned by the final query and get the Id by fetching the pointer for that in the table.

SELECT MAX(DATE)
FROM EXCHANGE_RATE
WHERE ACTIVE = 1 AND PROVIDER_ID = 1 AND TO_CURRENCY = 'EUR' AND DATE <= TO_DATE('2019-02-06', 'YYYY-MM-DD')
GROUP BY PROVIDER_ID, FROM_CURRENCY, TO_CURRENCY

Apart from this, the only way to get the ID return from single query is to use that in group by but i dont see that will solve the purpose, the subquery will not work as well as mentioned by you.

Hope this helps :)

You can use a subquery

SELECT ID
  FROM EXCHANGE_RATE
WHERE ("DATE") IN
(
SELECT MAX("DATE")
  FROM EXCHANGE_RATE
 WHERE ACTIVE = 1 
   AND PROVIDER_ID = 1 
   AND TO_CURRENCY = 'EUR' 
 )
   AND ACTIVE = 1 
   AND PROVIDER_ID = 1 
   AND TO_CURRENCY = 'EUR' 

Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM