Don't think in terms of individual rows. You have sets of rows so think in terms of sets of each question. Using CTEs you can encapsulate each piece (result set for each part of the question) and combine the answers in either other CTEs or the final query.
The following adaptation of your query shows 3 CTEs:
- First we get USD values for each InvoiceID
- Second we get localized values for each InvoiceID
- Third we calculate the effective exchange rate based on the previous two aggregations, JOINing on their respective InvoiceIDs
Finally, in the main query we use the outcome of the effective Exchange Rate calculation
;WITH USD AS (
SELECT InvoiceID, SUM(InvoiceTable.USD_ChargeAmount) AS [Total]
FROM
{Some Joins}
GROUP BY InvoiceTable.InvoiceID
),
LOC AS (
SELECT InvoiceID, SUM(LocalInvoiceTable.ChargeTotal) AS [Total]
FROM
{Some Joins}
GROUP BY LocalInvoiceTable.InvoiceID
),
FX AS (
SELECT USD.InvoiceID,
CONVERT(MONEY, LOC.Total) / CONVERT(MONEY, USD.Total) AS [Rate]
FROM USD
INNER JOIN LOC
ON LOC.InvoiceID = USD.InvoiceID
),
SELECT InvoiceTable.InvoiceID,
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE A' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * FX.[Rate] AS [Type_A],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE B' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * FX.[Rate] AS [Type_B],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE C' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * FX.[Rate] AS [Type_C]
FROM InvoiceTable
{Some Joins}
INNER JOIN FX
ON FX.InvoiceID = InvoiceTable.InvoiceID
EDIT:
A more ideal approach would be to store the exchange rate used at the time that the InvoiceTable and LocalInvoiceTable rows are being inserted. You could use a table similar to:
InvoiceInfo
(
InvoiceID INT NOT NULL, -- PK, FK to InvoiceTable
ExchangeRate SMALLMONEY NOT NULL,
CurrencyCode CHAR(3) NOT NULL, -- USD, EUR, etc.
InvoiceTotalUSD MONEY, -- optional
InvoiceTotalLocal MONEY -- optional
)
I would recommend using the ISO 4217 currency codes. The two InvoiceTotal* fields are only for if you routinely need to aggregate by InvoiceID outside of needing to calculate the "effective exchange rate".
Storing the info at the time of Invoice creation reduces your query to just:
SELECT InvoiceTable.InvoiceID,
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE A' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * II.[ExchangeRate] AS [Type_A],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE B' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * II.[ExchangeRate] AS [Type_B],
SUM(CASE InvoiceTable.ChargeCode
when 'TYPE C' THEN InvoiceTable.USD_ChargeAmount
ELSE 0 END) * II.[ExchangeRate] AS [Type_C]
FROM InvoiceTable
{Some Joins}
INNER JOIN InvoiceInfo II
ON II.InvoiceID = InvoiceTable.InvoiceID