CURREGITEMS is the name of the table that contains historical data regarding representative rates of different currencies. It has three fields of interest, namely CURRENCY, CURDATE and EXCHANGE: these are self-explanatory. The table is populated automatically upon the entry of new data into the connected CURRENCIES table. So if one runs the report Financials > Maintenance of Financials > Exchange Rates > Daily Exchange Rates (CURRENCIES) for USD, one gets the following data:
Date | Rate |
---|---|
30/11/23 | 3.714 |
01/12/23 | 3.739 |
04/12/23 | 3.708 |
05/12/23 | 3.728 |
Thus if one wants the dollar representative rate for an invoice dated
04/12/23, simple code to do so would be
SELECT EXCHANGE FROM CURREGITEMS WHERE CURRENCY = -2 AND CURDATE = 04/12/23;
Of course, one would use parameters for CURRENCY and CURDATE; The result for
this query would be 3.708.
But what happens if one wants the exchange rate for Sunday, 03/12/23? One
must remember that the Bank of Israel does not publish representative
exchange rates for Saturdays and Sundays, and indeed the above table does
not have an entry for 03/12/23. The way that I was taught (or taught myself)
many years ago when first working with Priority is that when there is no
value in CURREGITEMS, one uses the value of the EXCHANGE field in the
CURRENCIES table which is the most up-to-date value. As a result, I have
written in many reports or procedures expressions such as
SELECT (:CURR = -1 ? 1.0 : (CURREGITEMS.EXCHANGE > 0.0 ? CURREGITEMS.EXCHANGE : CURRENCIES.EXCHANGE)) INTO :EXCH FROM CURRENCIES, CURREGITEMS ? WHERE CURRENCIES.CURRENCY = CURREGITEMS.CURRENCY AND CURRENCIES.CURRENCY = :CURR AND CURREGITEMS.CURDATE = :DATE;
A problem with this code is if one is showing data from several months ago;
the representative rate for the dollar might have been 3.5 but now it's much
higher. I thought that I would have to write a loop to get the
representative rate of the date previous to the desired rate, something
like
LABEL 10; :EXCH = 0.0; (:CURR = -1 ? 1.0 : (CURREGITEMS.EXCHANGE > 0.0 ? CURREGITEMS.EXCHANGE)) INTO :EXCH FROM CURREGITEMS WHERE CURREGITEMS.CURRENCY = :CURR AND CURREGITEMS.CURDATE = :DATE; :DATE = :DATE - 24:00; LOOP 10 WHERE :EXCH = 0.0;
But it transpires that this is totally unnecessary! There is a value
for 03/12/23 in CURREGITEMS - it's the same value as for 01/12/23, or in
other words, the last known representative rate. There's no need for left
joins between CURRENCIES and CURREGITEMS.
I have no idea whether this has always been the case and that the queries
that I wrote in 2007 were misguided even then, or whether the method of
inserting tuples in CURREGITEMS has changed in the passing years. I suspect
that there has been no change and that I have been perpetuating a
misunderstanding for the last 17 years. I learn something new every
day.
APPENDUM: the original code with a left join between CURRENCIES and
CURREGITEMS is necessary when the given date is in the
future. In this case, there definitely will not be an appropriate entry in CURREGITEMS and so it's 'correct' to use the value from CURRENCIES.
I don't remember it being any other way, although I'm not sure if I dealt with currency conversions in my early days with Priority.
ReplyDeleteI confess that it also took me a while to understand why the system was queried the way it is when the rates-for-past-dates list seemed to only have certain past dates, but I learned by copying standard code (queries - I didn't know about cursors and never found out used func/GetExchange) and it all worked right...
Anyway, if I may offer some refinements to your observations:
Perhaps the extra rows are added after setting a rate in CURRENCIES but I'm more used to seeing it after additions to the CURREGITEMS table, via the sub-form which is called CURREG if I'm not mistaken. There is a table column which distinguishes between explicitly-set rates (I don't want to say manually as an interface may have set them) and the fill-in rows which are generated as you describe.
It's also not quite adequate to say that the outer join is required just because of future dates - that sounds like the future compared to now - rather it's necessary for any date since the last date added to CURREGITEMS, which could already be some time in the past, and actually also before the first date there. In both cases the rate in CURRENCIES is used as there is (obviously) nothing better.
I hope that's a constructive addition.