SQL Previous currency rate - sql

I would like to ask you for help with getting previous currency rate.
Eg. I have two tables (Orders and CurrencyRates) which I want to join. First table encloses orders in EUR, and second encloses currency rate from EUR to USD.
I would like to join it by Order Date. The problem is with order date "10.11.2018" which has null rate from CurrencyRates table. I would like to have here value from previous day rate (in this case "09.11.2018). And for the future date ("18.11.2018") I would like to have value having max(Date) from CurrencyRates table. Is there any way to join it to have expected values?
Thank you for your help!

You can use cross apply:
select o.*, cr.date, cr.rate, cr.currency
from orders o cross apply
(select top (1) cr.*
from currencyrates cr
where cr.date <= o.orderdate
order by cr.date desc
) cr;

Related

Joining 2 columns of a subqueried table into SQL

I'm trying to match the inventory for the day to the SKU.
Amazon_orders has the SKUs I want to match
Invhistory2 has the SKU, timestamp date (more than 1, here's the issue), and the inventory quantity
I'm trying to create a subquery that averages the inventory for the day, then join the timestamp and SKU to the SKUs on the amazon orders table. Null values are no issue here.
My code looks like this:
(SELECT AVG(quantity) AS qty FROM `perfect-obelisk-289514.inventory_history.invhistory2`) AS qtyok
FROM `perfect-obelisk-289514.reports.flat_file_orders_by_order_datereport` Amazon_Orders
LEFT JOIN (SELECT AVG(quantity) AS qty, sku, CAST(snapshot_date AS DATE) AS invdate
FROM `perfect-obelisk-289514.inventory_history.invhistory2`
GROUP BY sku, invdate) AS table2
ON (
Amazon_Orders.sku = table2.sku AND CAST(LEFT(Amazon_orders.purchase_date,10) AS DATE) = table2.invdate
)
The issue is that I get the same average for each row, it's not joining the quantity using SKU and date.
As you may notice I'm a beginner, looked thoroughly but can't find the solution, any help is appreciated!
Thanks for the help!
I managed to solve it. My code was redundant, I just needed this join:
LEFT JOIN (SELECT AVG(quantity) AS qty,
sku,
CAST(snapshot_date AS DATE) AS invdate
FROM `perfect-obelisk-289514.inventory_history.invhistory2`
GROUP BY sku, invdate) AS table2
ON
(Amazon_Orders.sku = table2.sku AND CAST(LEFT(Amazon_orders.purchase_date,10) AS DATE) = table2.invdate)
This gives me what I need

Adding a currency conversion to a SQL query

I have a database with a list of user purchases.
I'm trying to extract a list of users whose last successful purchase had a value of £100 or greater, which I have done:
SELECT
t.purchase_id
t.user_id,
t.purchase_date,
t.amount,
t.currency,
FROM
transactions t
INNER JOIN
(SELECT user_id, MAX(purchase_date) AS first_transaction
FROM transactions
GROUP BY user_id) frst ON t.user_id = frst.user_id
AND t.created_date = frst.first_transaction
WHERE
amount >= 100
ORDER BY
user_id;
The problem is that some of my purchases are in USD and some are in CAD. I would like to ensure that the value of the latest purchase is over £100 GBP despite the purchase currency.
Luckily I have another table with exchange rates:
base_currency currency exchange_rate
-----------------------------------------------
GBP USD 1.220185624
GBP CAD 1.602048721
So technically I just need to convert the amount using the exchange rate. I've hit a roadblock on how I can incorporate that into my current query. I'm thinking I need to create an extra column for amount_in_gbp but am not sure how to incorporate the case logic into my query?
You can avoid any JOIN statement:
SELECT t.purchase_id
,t.user_id
,t.purchase_date
,t.amount
,t.currency
FROM transactions t
INNER JOIN (
SELECT user_id
,MAX(purchase_date) AS first_transaction
FROM transactions
GROUP BY user_id
) frst ON t.user_id = frst.user_id
AND t.created_date = frst.first_transaction
WHERE (
SELECT t.amount / e.exchange_rate
FROM exchange AS e
WHERE t.currency = e.currency
) >= 100
ORDER BY user_id;
So that your column will be converted in GBP currency.
You join to the table:
SELECT t.*,
(t.amount / exchange_rate) as amoung_gbp
FROM transactions t LEFT JOIN
exchange e
ON t.currency = e.currency AND e.base_currency = 'GBP'
If you want to put this in a where clause, you need to repeat the expression:
where (t.amount / exchange_rate) > 100

how to query a table date against a series of dates on another table

I have two tables, INVOICES and INV_PRICES. I am trying to find the Invoice table's part price from the Inv_Prices based upon the Invoice_Dt on the Invoice table; if the Invoice_Dt is between (greater than, but less than) or greater than the max EFF_DT on the Inv_Prices, then return that part's price.
I have tired variations on the following code, but no luck. I either do not get all the parts or multiple records.
SELECT DISTINCT A.INVOICE_NBR, A.INVOICE_DT, A.PART_NO,
CASE WHEN TRUNC(A.INVOICE_DT) >= TRUNC(B.EFF_DT) THEN B.DLR_NET_PRC_AM
WHEN (TRUNC(A.INVOICE_DT)||ROWNUM >= TRUNC(B.EFF_DT)||ROWNUM) AND (TRUNC(B.EFF_DT)||ROWNUM <= TRUNC(A.INVOICE_DT)||ROWNUM) THEN B.DLR_NET_PRC_AM
/*MAX(B.EFF_DT) THEN B.DLR_NET_PRC_AM*/
ELSE 0
END AS PRICE
FROM INVOICES A,
INV_PRICES B
WHERE A.PART_NO = B.PART_NO
ORDER BY A.INVOICE_NBR
Can someone assist? I have a sample of each table if needed.
Doesn't it work to put the condition in the JOIN conditions? You can calculate the period when a price is valid using LEAD():
SELECT i.INVOICE_NBR, i.INVOICE_DT, i.PART_NO,
COALESCE(ip.DLR_NET_PRC_AM, 0) as price
FROM INVOICES i LEFT JOIN
(SELECT ip.*, LEAD(eff_dt) OVER (PARTITION BY PART_NO ORDER BY eff_dt) as next_eff_dt
FROM INV_PRICES ip
) ip
ON i.PART_NO = ip.PART_NO AND
i.invoice_dt >= ip.eff_dt AND
(i.invoice_dt < ip.next_eff_dt or ip.next_eff_dt is null)
ORDER BY i.INVOICE_NBR

Using a date field for matching SQL Query

I'm having a bit of an issue wrapping my head around the logic of this changing dimension. I would like to associate these two tables below. I need to match the Cost - Period fact table to the cost dimension based on the Id and the effective date.
As you can see - if the month and year field is greater than the effective date of its associated Cost dimension, it should adopt that value. Once a new Effective Date is entered into the dimension, it should use that value for any period greater than said date going forward.
EDIT: I apologize for the lack of detail but the Cost Dimension will actually have a unique Index value and the changing fields to reference for the matching would be Resource, Project, Cost. I tried to match the query you provided with my fields, but I'm getting the incorrect output.
FYI: Naming convention change: EngagementId is Id, Resource is ConsultantId, and Project is ProjectId
I've changed the images below and here is my query
,_cte(HoursWorked, HoursBilled, Month, Year, EngagementId, ConsultantId, ConsultantName, ProjectId, ProjectName, ProjectRetainer, RoleId, Role, Rate, ConsultantRetainer, Salary, amount, EffectiveDate)
as
(
select sum(t.Duration), 0, Month(t.StartDate), Year(t.StartDate), t.EngagementId, c.ConsultantId, c.ConsultantName, c.ProjectId, c.ProjectName, c.ProjectRetainer, c.RoleId, c.Role, c.Rate, c.ConsultantRetainer,
c.Salary, 0, c.EffectiveDate
from timesheet t
left join Engagement c on t.EngagementId = c.EngagementId and Month(c.EffectiveDate) = Month(t.EndDate) and Year(c.EffectiveDate) = Year(t.EndDate)
group by Month(t.StartDate), Year(t.StartDate), t.EngagementId, c.ConsultantName, c.ConsultantId, c.ProjectId, c.ProjectName, c.ProjectRetainer, c.RoleId, c.Role, c.Rate, c.ConsultantRetainer,
c.Salary, c.EffectiveDate
)
select * from _cte where EffectiveDate is not null
union
select _cte.HoursWorked, _cte.HoursBilled, _cte.Month, _cte.Year, _cte.EngagementId, _cte.ConsultantId, _cte.ConsultantName, _cte.ProjectId, _Cte.ProjectName, _cte.ProjectRetainer, _cte.RoleId, _cte.Role, sub.Rate, _cte.ConsultantRetainer,_cte.Salary, _cte.amount, sub.EffectiveDate
from _cte
outer apply (
select top 1 EffectiveDate, Rate
from Engagement e
where e.ConsultantId = _cte.ConsultantId and e.ProjectId = _cte.ProjectId and e.RoleId = _cte.RoleId
and Month(e.EffectiveDate) < _cte.Month and Year(e.EffectiveDate) < _cte.Year
order by EffectiveDate desc
) sub
where _cte.EffectiveDate is null
Example:
I'm struggling with writing the query that goes along with this. At first I attempted to partition by greatest date. However, when I executed the join I got the highest effective date for every single period (even those prior to the effective date).
Is this something that can be accomplished in a query or should I be focusing on incremental updates of the destination table so that any effective date / time period in the past is left alone?
Any tips would be great!
Thanks,
Channing
Try this one:
; with _CTE as(
select p.* , c.EffectiveDate, c.Cost
from period p
left join CostDimension c on p.id = c.id and p.Month = DATEPART(month, c.EffectiveDate) and p.year = DATEPART (year, EffectiveDate)
)
select * from _CTE Where EffectiveDate is not null
Union
select _CTE.id, _CTE.Month, _CTE.Year, sub.EffectiveDate, sub.Cost
from _CTE
outer apply (select top 1 EffectiveDate, Cost
from CostDimension as cd
where cd.Id = _CTE.id and cd.EffectiveDate < DATETIMEFROMPARTS(_CTE.Year, _CTE.Month, 1, 0, 0, 0, 0)
order by EffectiveDate desc
) sub
where _Cte.EffectiveDate is null

Revenue year by year SQL Server query

I have the following query which provides me with the item and item details, values, rate and quantity across each location.
I am trying to get the yearly revenue based on the Start and End Date. Example, if the chosen date was 2013-2015. The final result will create 3 columns one for 2013 revenue, one for 2014 revenue and one for 2015 revenue.
I am a newbie and still not an expert in writing queries, but here is what I have currently:
SELECT
department,
item,
itemdesc,
qty1,
qty2,
rate_1,
rate_2,
SUM(mm.days*mm.rate*mm.qty)
FROM
items it
LEFT JOIN
(SELECT
i.days, i.rate, i.days, ii.todate, ii.itemid
FROM
invoiceofitems ii
JOIN
invoices i on i.id = ii.id
WHERE
ii.todate BETWEEN #StartDate and #EndDate) mm ON mm.itemid = it.itemid
GROUP BY
department,
item,
itemdesc,
qty1, qty2,
rate_1, rate_2
ORDER BY
item
However, this does not provide me with a year to year aggregation of invoice revenue that I require.
I know this is possible to achieve via iterating through this. But how would I accomplish this and where would I start on this?
Would I need to know the start and end date of each year and iterate through that and then add a counter to the year until year= EndDate?
I'm extremely confused. Help would be appreciated.
I hope that PIVOT and YEAR help you to solve this problem (some columns are omitted):
;WITH SRC(department,item, ... , rate_2, yr, calculation) AS
(SELECT it.department, it.item, ..., it.rate_2, YEAR(ii.todate) as yr,
(i.days * i.rate *i.qty) as calculation
FROM items it
LEFT JOIN invoiceofitems ii ON ii.itemid = it.itemid
JOIN invoices i ON i.id = ii.id)
SELECT department,item, ..., [2013],[2014],[2015]
FROM SRC
PIVOT
(SUM(calculation) FOR yr IN ([2013],[2014],[2015])) PVT
The YEAR function returns only 'year' part of your date and makes grouping easier. PIVOT just rotates grouped data from rows to columns.