How to add specific if condition in sql - 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.

Related

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.

finding highest total price and converting

So I have to use a query where I list the trade id stock id and the total price converted to us dollars where it is the highest price total.
SELECT
tr.trade_id, tr.stock_id, round(tr.price_total * con.exchange_rate,2)
as "US Dollars"
from trade tr
JOIN stock_exchange se
on se.STOCK_EX_ID = tr.STOCK_EX_ID
JOIN currency curr
on curr.CURRENCY_ID = se.currency_id
JOIN conversion con
on con.from_CURRENCY_ID = curr.CURRENCY_ID
WHERE (tr.PRICE_TOTAL) = (Select Max(price_total) from trade) and curr.name =
'Dollar' and tr.stock_ex_id is not NULL
group by tr.trade_id, tr.stock_id, round(tr.price_total), tr.price_total,
round(tr.price_total * con.exchange_rate,2);
Trade (trade_id PK, stock_id FK2, transaction_time, shares, stock_ex_id FK1,price_total)
Stock-exchange( stock_ex_id PK, name, symbol, currency_id FK1)
conversion( from_currency_id PK, to_currency_id)
currency ( currency_id PK, name, symbol
expected output should be -
trade_id - 1 stock_id 1, price (non conversion) (225000000)
I'm not sure why in my output i get nothing. Any suggestions to fix this? Sorry if i did not format the question right
But you could start by seeing what your select max query returns, and then filtering down the trade table by that value. Trace this though all of your tables to see where the data on your trade table isn't on the others.
OR put you curr.name criteria up with the join and specify a LEFT JOIN for the last two tables to see if the data is missing like below:
SELECT tr.trade_id
,tr.stock_id
,round(tr.price_total * con.exchange_rate, 2) AS "US Dollars"
FROM trade tr
LEFT JOIN stock_exchange se
ON se.STOCK_EX_ID = tr.STOCK_EX_ID
LEFT JOIN currency curr
ON curr.CURRENCY_ID = se.currency_id
AND curr.name = 'Dollar'
LEFT JOIN conversion con
ON con.from_CURRENCY_ID = curr.CURRENCY_ID
WHERE (tr.PRICE_TOTAL) = (SELECT Max(trm.price_total) FROM trade trm)
AND tr.stock_ex_id IS NOT NULL
It could be other things as well, but one spot to look is this
You say WHERE tr.PRICE_TOTAL = (Select Max(price_total) from trade)
AND curr.name = 'Dollar'
If the trade with the Maximum price_total is not in Dollars, then you'll get nothing.
You need to either change your "Select Max(price_total) from trade" to get maximum values for Dollar trades only, or else get all the valid trades in a subquery and then get the maximum value from that.
After comment below - to debug - run "Select * from trade where price_total = (Select Max(price_total) from trade)" to get the valid trade record(s). Then look at them - they are going to fail somewhere - no STOCK_EX_ID on trade, or one of the other joins fails - you need to start from known data and go from there.

Show 0 for null rows

I'm working on a comparison query that will compare what was processed for the different credit card types versus what was actually processed by our POS service. I have ran into an issue where I am not seeing rows for certain card types if they did not process any payments on a given day but may have given a refund. IE: Nothing purchased with VISA but a VISA refund was given, but due to no purchases the row does not show up even though there's a refund for that type.
Here is my query:
WITH tran_total AS (
SELECT CONCAT(c.id_str, ' - ', c.clinic_str) AS Clinics,
t.clinic,
c.xcharge_mid,
p.pay_desc,
CAST(t.time_ran AS date) AS tran_date,
CASE WHEN SUM(t.amount) <> 0 THEN SUM(t.amount) * - 1
ELSE 0.00 END AS collection
FROM dbo.transactions AS t INNER JOIN
dbo.clinic_master AS c ON t.clinic = c.clinic INNER JOIN
dbo.paytype AS p ON t.clinic = p.clinic AND t.paytype_id = p.paytype_id
WHERE (t.time_ran > GETDATE() - 10)
AND (t.paytype_id IS NOT NULL)
AND (p.pay_desc = 'Visa' OR
p.pay_desc = 'MasterCard' OR
p.pay_desc = 'American Express' OR
p.pay_desc = 'Discover')
GROUP BY c.id_str, c.clinic_str, t.clinic, c.xcharge_mid, p.pay_desc, CAST(t.time_ran AS date))
SELECT w.Clinics,
w.pay_desc,
w.tran_date,
w.collection,
CASE WHEN w.pay_desc = 'Visa' THEN (SUM(VI_pur) - SUM(VI_ref))
WHEN w.pay_desc = 'MasterCard' THEN (SUM(MC_pur) - SUM(MC_ref))
WHEN w.pay_desc = 'American Express' THEN (SUM(AX_pur) - SUM(AX_ref))
WHEN w.pay_desc = 'Discover' THEN (SUM(DI_pur) - SUM(DI_ref)) END AS xcharge
FROM tran_total AS w LEFT OUTER JOIN
dbo.xcharge AS x ON w.xcharge_mid = x.xcharge_mid AND w.tran_date = x.settle_date
GROUP BY w.Clinics, w.pay_desc, w.tran_date, w.collection
ORDER BY w.Clinics, w.tran_date
I've thought about switching this around and starting with the comparison from the xcharge table but there is not a pay_desc that links those easily and if something is processed as the wrong card (VISA is chosen but Discover is scanned) then I feel the rows would be missed still.
What I would like, is for all of the pay_desc to show up for each tran_date even if the SUM(t.amount) does not have a value. I've tried a case statement to accomplish this without any luck.
EDIT: I feel the issue is more due to the t.time_ran variable. If there isn't a payment for a given pay_desc then there won't be a t.time_ran either, is there a function I can do to list out dates between GETDATE()-10 AND GETDATE() kind of thing and just have the t.time_ran and x.settle_date match up to that variable instead?
Any thoughts on this? Thanks in advance
UPDATE:
I have created a calendar table with individual dates and have tried the following query:
WITH tran_test AS(
SELECT cal.calendardate AS cd,
p.clinic,
p.pay_desc,
p.paytype_id
FROM calendar cal, paytype p
WHERE cal.calendardate BETWEEN GETDATE()-10 AND GETDATE()+1
AND (p.pay_desc = 'Visa' OR
p.pay_desc = 'MasterCard' OR
p.pay_desc = 'American Express' OR
p.pay_desc = 'Discover'))
SELECT w.cd,
CONCAT(c.id_str, ' - ', c.clinic_str) AS Clinics,
w.pay_desc,
ISNULL(SUM(t.amount)*-1, 0) AS collection,
CASE WHEN w.pay_desc = 'Visa' THEN (SUM(x.VI_pur) - SUM(x.VI_ref))
WHEN w.pay_desc = 'MasterCard' THEN (SUM(x.MC_pur) - SUM(x.MC_ref))
WHEN w.pay_desc = 'American Express' THEN (SUM(x.AX_pur) - SUM(x.AX_ref))
WHEN w.pay_desc = 'Discover' THEN (SUM(x.DI_pur) - SUM(x.DI_ref)) END AS xcharge
FROM tran_test w
INNER JOIN clinic_master c
ON (w.clinic=c.clinic)
LEFT OUTER JOIN transactions t
ON (t.clinic=w.clinic AND t.paytype_id=w.paytype_id AND CAST(t.time_ran AS date) = w.cd)
LEFT OUTER JOIN xcharge x
ON (w.cd=x.settle_date AND c.xcharge_mid=x.xcharge_mid)
GROUP BY w.cd, c.id_str, c.clinic_str, w.pay_desc
ORDER BY w.cd
However, I'm not getting an issue where my xcharge column seems to multiplying itself by random intervals and I'm not sure why.
It sounds like what you need is a Calendar table. You can generate one as part of a CTE (many examples on this site or just search Google), but IMO you should have a persistent table in your database. This way you can mark certain days as bank holidays, what quarter your business considers them to be in, etc.
Once you have that table in place you can SELECT your dates from that table and then LEFT OUTER JOIN to that table from your Transactions table. Any dates without matching rows in Transactions will still show up with a row, but you'll have 0.00 value for your SUM.

Use last available currency rate by date available to calculate totals

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.

Oracle SQL Distinct Clause not presenting distinct values

I have a script when I'm trying to select locations in an inventory where quantity of said location is <= 5. The query is complete, now I'm trying to do some fine tuning, and what I'm running into now is when I use the distinct clause I am still receiving duplicate records in the same column. I do know the column next to the first are unique, but I thought distinguishing distinct and one column would roll over to next related to said column.
Here is my code:
select DISTINCT bin.scannable_id as bin,
bi.bin_id as case1,
pallet.scannable_id as pallet,
-- bi.isbn as fcsku,
nvl(fs.asin,bi.isbn) as asin,
sum(bi.quantity) as quantity,
pallet.creation_date as received_date
from containers bin
join containers pallet on pallet.containing_container_id = bin.container_id
join containers case on case.containing_container_id = pallet.container_id
join bin_items bi on bi.container_id = case.container_id
left join fcskus fs on fs.fcsku = bi.isbn
where bin.scannable_id like 'R-1-T%'
and bi.quantity <= '5'
group by bin.scannable_id, pallet.scannable_id, bi.bin_id, bi.owner,bi.isbn,nvl(fs.asin,bi.isbn), pallet.creation_date
order by sum(bi.quantity);
My output, which is obviously showing duplicate records in the scannable_id column:
Correct Formatting Thanks to conrad.
select DISTINCT bin.scannable_id as bin,
pallet.scannable_id as pallet,
nvl(fs.asin,bi.isbn) as asin,
sum(bi.quantity) as quantity
from containers bin
join containers pallet on pallet.containing_container_id = bin.container_id
join containers case on case.containing_container_id = pallet.container_id
join bin_items bi on bi.container_id = case.container_id
left join fcskus fs on fs.fcsku = bi.isbn
where bin.scannable_id like 'R-1-T%'
having sum(bi.quantity) <= '5'
group by bin.scannable_id, pallet.scannable_id, nvl(fs.asin,bi.isbn), bi.quantity
order by sum(bi.quantity);
As said on the comments you dont need a DISTINCT if you have the group by statement. And format your date field because depending on your oracle client configuration it will not show you the entire date format (e.g. date time). So try with this:
select bin.scannable_id as bin,
bi.bin_id as case1,
pallet.scannable_id as pallet,
nvl(fs.asin,bi.isbn) as asin,
to_char(pallet.creation_date, 'yyyy-mm-dd') as received_date
sum(bi.quantity) as quantity,
from containers bin
join containers pallet on pallet.containing_container_id = bin.container_id
join containers case on case.containing_container_id = pallet.container_id
join bin_items bi on bi.container_id = case.container_id
left join fcskus fs on fs.fcsku = bi.isbn
where bin.scannable_id like 'R-1-T%'
and bi.quantity <= '5'
group by bin.scannable_id,
pallet.scannable_id,
bi.bin_id,
bi.owner,
bi.isbn,
nvl(fs.asin,bi.isbn),
to_char(pallet.creation_date, 'yyyy-mm-dd')
order by sum(bi.quantity);
bi.bin_id is different for each row, so you do only have distinct results in your resultset.
distinct is applied to the final visible resultset (once the to_char etc. functions are processed)
distinct is redundant if you already use a group by expression
Solution: skipp the bi.bin_id column from your select expression.
Your logic is also confusing. You want to know the SUM of all the bi.* elements. To do so you cannot group by bi.bin_id nor any field from the bi table. This is the reason why your quantity result is always 1.