Use last available currency rate by date available to calculate totals - sql

I am trying to convert currency rates on orders.
The currency rates table is updated daily End of day for that particular day, however an order can be created earlier in the day, and as a result the rate will not be reflected with the current query. How would I add case statements and modify the query where by if the currency rate for the day does not exist use the last currency date available (within the table).
#Curr is the desired currency code. Could be 'USD', 'GBP' etc.
SELECT OrderNumber
,(CASE WHEN #Curr<>cur.code THEN
o.price * (SELECT Rate FROM xchangeRates xr
WHERE xr.FromCurrCode = c.Code
AND xr.ToCurrCode = #Curr
AND xr.Date= ISNULL((SELECT TOP 1 CAST(Crtd_DateTime AS Date) FROM ApDoc apdoc
WHERE apdoc.PONbr = o.OrderNumber AND apdoc.PONbr>''
ORDER BY apdoc.Crtd_DateTime DESC),o.orderdate)
)
ELSE o.price
END ) as o.price
from orders o
join currency c on c.curcode = o.curcode

Why not this:
...
o.price * (SELECT TOP 1 Rate FROM xchangeRates xr
WHERE xr.FromCurrCode = c.Code
AND xr.ToCurrCode = #Curr
ORDER BY xr.Date DESC)
...
If there are future dates in the xchangeRates table, all you have to do is add an additional filter to the WHERE clause to limit xr.Date to <= today.
EDIT: to handle this requirement:
if the invoice was created in the apdoc the it uses that Date for the
exchange rate, but if not then it uses the date the order was created.
forget your subselect to apDoc and JOIN it to orders in the outer query instead:
LEFT OUTER JOIN apDoc
ON apdoc.PONbr = o.OrderNumber
And then do this for your subquery instead of what I have above:
o.price * (SELECT TOP 1 Rate FROM xchangeRates xr
WHERE xr.FromCurrCode = c.Code
AND xr.ToCurrCode = #Curr
AND xr.Date =< COALESCE(CAST(apdoc.Crtd_DateTime AS Date),o.OrderDate)
ORDER BY xr.Date DESC)
nb: I CAST Crtd_DateTime AS Date because you did it in your code, and for all I know it's a varchar, but if it's a Datetime datatype, then the cast isn't necessary in my solution.

Related

How to add specific if condition in sql

I have built this query (snapshot attached) to check if there is any staleness in prices by comparing today's price with previous day price for certain timezones, what i need is it should only throw only that object_id which shows '0' as BP_move for the mentioned timezones. for eg in the snapshot we can see that AED fx price is 0 for across all the timezones so it is acceptable but other ccy like EUR, GHS ,KES ,NZD and QAR are stale only for one or two timezones so those should not get published in output. is there any if condition i can use in this query ?
select distinct
vyc.asof, vyc.timezone, vyc.object_id, i.name,
vpf.rate * 100 todays_rate, vpf2.rate * 100 prior_rate,
(vpf.rate - vpf2.rate) * 1000 bp_move
from
val_yield_curves vyc
inner join
val_prices_fx vpf on vyc.asof = vpf.asof
and vyc.rowkey = vpf.curve
inner join
val_yield_curves vyc2 on vyc.timezone = vyc2.timezone
and vyc2.asof = case when to_char(sysdate,'DY') = 'MON' then trunc(sysdate-3) else trunc(sysdate-1) end
and vyc.object_id = vyc2.object_id
inner join
val_prices_fx vpf2 on vyc2.asof = vpf2.asof
and vyc2.rowkey = vpf2.curve
and vpf.instrument = vpf2.instrument
inner join
instruments i on i.pkey = vpf.instrument
where
vyc.object_id like '%Spot%'
and vyc.timezone in ('L0200', 'L1000', 'L1200', 'L1500')
and (vpf.rate - vpf2.rate) * 1000 in '0'
and vyc.asof = trunc(sysdate)
order by
vyc.object_id
I don't know if I understood correctly your problem but...
If you don't need timezone information, you can
GROUP BY object_id, name, rates
HAVING COUNT(DISTINCT Timezone) >= 4
If you need timezone information, you can add a "OBJECT_ID IN (SELECT...)" condition in your WHERE. You have to make it check if you have the right number of lines for your OBJECT_ID. You can GROUP BY/HAVING COUNT this subrequest as above and returns OBJECT_ID.

daily incremental results on table where transaction date <= #Date parameter

specifically looking for General Leger results. This means that I can't sum up transactions for specfic dates, or cant run Between date.
to get the results for say, today I would need to query the table for all transactions <= #Today.
That said, i am tasked with running this for every single day in 2020 thus far. is there a method to do this where i dont have to manually run for each day myself?
Query example:
glo.GLValue
, Sum(UnitCR) AS 'Credit'
, Sum(UnitDR) AS 'Debit'
, sum(FirmCR) AS 'FirmCredit'
, sum(FirmDR) AS 'FirmDebit'
FROM glacct ga
inner join gldetail gd on gd.glacct = ga.AcctIndex
inner join glnatural gn on ga.glnatural = gn.GLNaturalID
inner join glunit glu on ga.glunit = glu.GLUnitID
inner join gloffice glo on ga.GLOffice = glo.GLOfficeID
WHERE gn.GLNat IN ('11001','11002','11003','11005','11007','11011','11016','11019','11020','11021','11022','11024','11025','11026','11027','11032','11033',
'11034','11035','11036','11037','11040','11041','11042','11043','11044','11050','11051','11052','11053','11190','11199','11201','11202','11203','11204',
'11205','11206','11207','11301','11603','11700','11705','11801','11802','11803','11804','11806','11807','11808','11809','11901')--,'22001')
AND gd.PostDate <= #Yesterday
GROUP BY
glo.GLValue
Create a sub-table that give the sums for each PostDate and GLValue similar to above but also grouped on PostDate, then join that to your select above, e.g.
inner join gloffice glo on ga.GLOffice = glo.GLOfficeID
inner join ( ... new grouped select here ...) gs on gs.GLValue = glo.GlValue and gs.PostDate < gd.PostDate
Now you should be able to sum the gs values:
, Sum(gs.Credit) as Credit
, Sum(gs.Debit) as Debit
etc.

How to fix "Conversion from string "August" to type 'Date' is not vaid in SSRS

SELECT
a.ItemCode,
SUM(a.NoOfApplication) AS NoOfApplication,
SUM(a.NoOfAccomplished) AS NoOfAccomplished,
SUM(a.NoOfPending) AS NoOfPending,
SUM(a.NoOfDocumentCompliance) AS NoOfDocumentCompliance,
a.[Year]
FROM
(SELECT
ItemCode,
COUNT(am.ReferenceNumber) AS NoOfApplication,
COUNT(TNA.NoOfAccomplished) AS NoOfAccomplished,
COUNT(TNP.NoOfPending) AS NoOfPending,
SUM(FDC.NoOfDocumentCompliance) AS NoOfDocumentCompliance,
DATENAME(month, ad.applicationdate) AS [Year]
FROM
AppTypes at
INNER JOIN
AssessmentMainDetails am ON at.Category = am.Category
INNER JOIN
InspectionProcesses i ON am.ReferenceNumber = i.ReferenceNo
LEFT JOIN
(SELECT
COUNT(Status) AS NoOfDocumentCompliance,
ReferenceNumber, Status
FROM
ApplicationStatus
WHERE
Status = 'For Document Compliance'
GROUP BY
ReferenceNumber, Status) AS FDC ON FDC.ReferenceNumber = i.ReferenceNo
LEFT JOIN
(SELECT
COUNT(ReferenceNo) AS NoOfAccomplished,
ReferenceNo
FROM
InspectionProcesses
WHERE
DateOfInspection <> ''
GROUP BY
ReferenceNo) AS TNA ON TNA.ReferenceNo = i.ReferenceNo
LEFT JOIN
(SELECT
COUNT(ReferenceNo) AS NoOfPending, ReferenceNo
FROM
InspectionProcesses
WHERE
DateOfInspection = ''
GROUP BY
ReferenceNo) AS TNP ON TNP.ReferenceNo = i.ReferenceNo
INNER JOIN
ApplicationDetails ad on i.ReferenceNo = ad.ReferenceNumber
INNER JOIN
Companies c on ad.CompanyId = c.CompanyID
INNER JOIN
Zones z on c.zonecode = z.zonecode
INNER JOIN
ZoneGroups zg on z.ZoneGroup = zg.ZoneGroupId
WHERE
DateOfInspection = ''
AND ad.ApplicationDate BETWEEN '2017-08-01' AND '2017-09-30'
AND zg.ZoneGroupCode = 'HO'
AND z.ZoneCode = 'VIDC'
GROUP BY
ItemCode, DATENAME(month, ad.applicationdate)) a
GROUP BY
a.ItemCode, a.[Year]
This my code, I already converted my date to get the month name. Please I need help
Look carefully. That giant derived table (a - nice meaningful name btw) has the same group by clause as the outermost query. So that means that [a] has a single row per ItemCode and datename(month, ad.applicationdate). Therefore, there is nothing to sum in your outer query since it is grouping by the same columns.
You also have the expression:
DateOfInspection = ''
which is highly suspicious based on the name of the column. What datatype is the DateOfInspection column? Doesn't sound like it should be string-based.
And lastly, the error message you posted sounds like it comes from SSRS and not sql server. Is that the case? Does your query run correctly from SSMS? Then the problem is in your report - and it would seem that you attempt to manipulate or interpret the Year column as a date (perhaps for sorting?). It also seems a bit short-sighted in your report design that your "Year" column is actually the name of a month and that your resultset does not include the year in some fashion. What happens when your data spans more than twelve months? And how do you intend to sort your report when you have month name but not month number?

SQL Select Where Between statement missing results that should be there?

I apologize if this question has already been asked, but I couldn't find anything on it.
Basically, my accounting department runs a report every month to pull up all orders from a specific client for the previous month. My problem is that I have orders that are not showing up in these reports. The only similarities I can find in the orders that are missing is that if there are 2 or more sequential order numbers, one or more of them will not be picked up by the report if most other fields are the same.
When I ran the report over a single 24 hour period, any orders that were missing from the month-long report would show up for that day.
This is the code I'm using for the query:
SELECT paydetail.ord_hdrnumber as ord_hdrnumber,
NULL As TotalRevenue,
paydetail.pyt_itemcode As Item,
NULL As ItemRevenue,
pyd_amount As ItemPay,
paydetail.asgn_type,
paydetail.asgn_id, ord_driver1,
ord_revtype1, pyt_description As ItemDesc,
pyt_basis As ItemBasis
FROM paydetail
LEFT OUTER JOIN payheader ON pyh_pyhnumber = pyh_number
JOIN orderheader on orderheader.ord_hdrnumber = paydetail.ord_hdrnumber
JOIN paytype on paytype.pyt_itemcode = paydetail.pyt_itemcode
WHERE ord_billto = #billto
AND ord_startdate BETWEEN #startdate + ' 00:00:00' AND #enddate + ' 23:59:59'
AND paydetail.pyt_itemcode NOT IN ('TCKEVE','TCKEXP','TCKDEB')
UNION ALL
SELECT invoicedetail.ord_hdrnumber as ord_hdrnumber,
ivh_totalcharge As TotalRevenue,
invoicedetail.cht_itemcode As Item,
ivd_charge As ItemRevenue,
NULL As ItemPay,
NULL As asgn_type,
NULL as asgn_id,
NULL as ord_driver1,
ord_revtype1,
[cht_description] As ItemDesc,
[cht_basis] As ItemBasis
FROM invoicedetail
LEFT OUTER JOIN invoiceheader ON invoiceheader.ivh_hdrnumber = invoicedetail.ivh_hdrnumber
JOIN orderheader on orderheader.ord_hdrnumber = invoicedetail.ord_hdrnumber
JOIN chargetype ON chargetype.cht_itemcode = invoicedetail.cht_itemcode
WHERE ivh_billto = #billto
AND ord_startdate BETWEEN #startdate + ' 00:00:00' AND #enddate + ' 23:59:59'
ORDER by ord_hdrnumber

Select only rows mith minimum cost

I need to pull back a set of data for a view where only rows with the the minimum cost are returned. I am joining 3 tables and they are big tables (225 million records a piece give or take) so performance is essential.
SELECT RIC.CarrierName, L.LoadGuid, RIC.RateIQCarrierid, RIRD.Cost
FROM tblLoads L
INNER JOIN RateIQRecord RIR ON L.LoadGuid = RIR.LoadGuId
INNER JOIN RateIQCarrier RIC ON RIR.RateIQRecordID = RIC.RateIQRecordID
INNER JOIN RateIQRateDetail RIRD ON RIC.RateIQRecordID = RIRD.RateIQRecordID
AND CAST(L.CreatedDate AS Datetime) Between '03/3/2014' and '03/3/2014 23:59:59.997'
Here is an example of the data set based of the code above
CarrierName LoadGuid Carrierid Cost
Carrier a FF98010A-90CE-4541-AB88-683645352712 210677951 192.51
Carrier a FF98010A-90CE-4541-AB88-683645352712 210677921 153.17
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677925 196.28
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677947 280.65
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677949 241.71
Here is what I need:
CarrierName LoadGuid Carrierid Cost
Carrier a FF98010A-90CE-4541-AB88-683645352712 210677921 153.17
Carrier b FF98010A-90CE-4541-AB88-683645352712 210677925 196.28
Try this out:
Note:I'm assuming you have SQL Server 2008 or above. ROW_NUMBER() won;t work otherwise.
SELECT *
FROM
(
SELECT RIC.CarrierName,
L.LoadGuid,
RIC.RateIQCarrierid,
RIRD.Cost,
--Partition says look at each carrier as a group, then number them in order of cost lowest to highest.
ROW_NUMBER() OVER (PARTITION BY RIC.CarrierName ORDER BY Cost) rank_num
FROM tblLoads L
INNER JOIN RateIQRecord RIR
ON L.LoadGuid = RIR.LoadGuId
INNER JOIN RateIQCarrier RIC
ON RIR.RateIQRecordID = RIC.RateIQRecordID
INNER JOIN RateIQRateDetail RIRD
ON RIC.RateIQRecordID = RIRD.RateIQRecordID
--Don't do it this way
--AND CAST(L.CreatedDate AS Datetime) Between '03/3/2014' and '03/3/2014 23:59:59.997'
--Try this instead
AND CAST(L.CreatedDate AS DATE) = '03/03/2014'
) A
--Only grab the lowest number aka first of row number
WHERE A.rank_num = 1