Calculating the weighted average cost in firebird sql - sql

I have the same problem in this question but in Firebird 2.5
Calculating the Weighted Average Cost of products stock
And this answer didn't work (as Firebird 2.5 doesn't have row_number)
with recursive
stock_temp as (
select
*,
row_number() over(partition by product_id order by row_num) as rn
from
stock_table
)
,cte as (
select
document_type, document_date,
product_id, qty_out, qty_in, price,
row_num, stock_balance, rn,
price as wac
from
stock_temp where document_type = 'SI'
union all
select
sub.document_type, sub.document_date,
sub.product_id, sub.qty_out, sub.qty_in, sub.price,
sub.row_num, sub.stock_balance, sub.rn,
case when sub.qty_in = 0 then main.wac else
((sub.stock_balance - sub.qty_in) * main.wac + sub.qty_in * sub.price)
/ ((sub.stock_balance - sub.qty_in) + sub.qty_in) end as wac
from
cte as main
join stock_temp as sub
on (main.product_id = sub.product_id and main.rn + 1 = sub.rn)
)
select * from cte

Related

Problem with Recursive CTE very long query plan

When I execute below query SQL run this plan and it took a long time to run it and it will not be over.
QueryPlanLink
I have 3 million records in #T table.
myCode:
;WITH cte1 AS (
SELECT NationalId,len(NationalId) as LenNationalId,CustomerType,FullDateInt,time,
SUM(Price) as SUMPrice
,AVG(Price) as Price
,SUM(Volume) as Volume
,SUM (sum([Volume])) OVER (PARTITION BY NationalId,len(NationalId) ORDER BY FullDateInt,[Time]) as SumVol
,ROW_NUMBER() OVER (PARTITION BY NationalId,len(NationalId) ORDER BY FullDateInt,[Time]) AS rn
from #T as T1
group by NationalId,len(NationalId),CustomerType,FullDateInt,time
), rcte AS (
SELECT *, Price AS Cost , cast(0 as decimal) as Profit
FROM cte1 AS base
WHERE base.rn = 1
UNION ALL
SELECT curr.*, Case when curr.Volume>0 Then ((curr.Volume *curr.Price) + (prev.Cost*prev.SumVol))/nullif(curr.SumVol,0)
when curr.Volume<0 Then prev.Cost
End
as Cost
,ISNULL(Cast (Case when curr.Volume<0 Then -1*(curr.Price-Cost)*curr.Volume End as decimal),0) as Profit
FROM cte1 AS curr
INNER JOIN rcte AS prev
ON curr.NationalId = prev.NationalId AND curr.rn = prev.rn + 1
)
Select * from rcte
option (maxrecursion 0)
Is there any way to make it better?
Thanks
I Change My Query like below And Everything is Done. Thanks For All.
SELECT NationalId,len(NationalId) as LenNationalId,CustomerType,FullDateInt,time,
SUM(Price) as SUMPrice
,AVG(Price) as Price
,SUM(Volume) as Volume
,SUM (sum([Volume])) OVER (PARTITION BY NationalId,len(NationalId) ORDER BY FullDateInt,[Time]) as SumVol
,ROW_NUMBER() OVER (PARTITION BY NationalId,len(NationalId) ORDER BY FullDateInt,[Time]) AS rn
into #TCTE from #T as T1
group by NationalId,len(NationalId),CustomerType,FullDateInt,time
;With rcte AS (
SELECT *, Price AS Cost , cast(0 as decimal) as Profit
FROM #TCTE AS base
WHERE base.rn = 1
UNION ALL
SELECT curr.*, Case when curr.Volume>0 Then ((curr.Volume *curr.Price) + (prev.Cost*prev.SumVol))/nullif(curr.SumVol,0)
when curr.Volume<0 Then prev.Cost
End
as Cost
,ISNULL(Cast (Case when curr.Volume<0 Then -1*(curr.Price-Cost)*curr.Volume End as decimal),0) as Profit
FROM #TCTE AS curr
INNER JOIN rcte AS prev
ON curr.NationalId = prev.NationalId AND curr.rn = prev.rn + 1
)
Select *
into #TFinal from rcte
option (maxrecursion 0)

Use of count in where statement sql

I have N transactions with camera_id = 6 and i want to sample every N // 100 transaction.
I have the following query:
SELECT t.id from (
SELECT id, camera_id, start_ts, ROW_NUMBER() OVER (ORDER BY start_ts) AS rownum
FROM transactions
WHERE camera_id = 6
) as t
where t.rownum % (N / 100) = 1
order by t.start_ts
How can i change it so i don't need additional query for determining N?
Untested
Does the following work for you - add a windowed count in addition to your Rownumber and use that:
SELECT t.id from (
SELECT id, camera_id, start_ts,
Row_Number() OVER (ORDER BY start_ts) AS rownum,
Count(*) over() Qty
FROM transactions
WHERE camera_id = 6
) as t
where t.rownum % (Qty / 100) = 1
order by t.start_ts

PostgreSQL Percent Change using Row Number

I'm trying to find the percent change using row number with PostgreSQL but I'm running into an error where my "percent_change" column shows 0.
Here is what I have as my code.
WITH CTE AS (
SELECT date, sales, ROW_NUMBER() OVER (ORDER by date) AS rn
FROM sales_2019)
SELECT c1.date, c1.sales,
CAST(COALESCE (((c1.sales - c2.sales) * 1.0 / c2.sales) * 100, 0) AS INT) AS percent_change
FROM CTE AS c1
LEFT JOIN CTE AS c2
ON c1.date = c2.date AND c1.rn = c2.rn + 1
Here is my SQL table in case it's needed. Thank you in advance, I greatly appreciate it.
You can use LAG() for your requirement:
select
date,
sales,
round(coalesce((((sales-(lag(sales) over (order by date)))*1.0)/(lag(sales) over (order by date)))*100,0),2)
from sales_2019
or you can try with WITH clause
with cte as ( select
date,
sales,
coalesce(lag(sales) over (order by date),0) as previous_month
from sales_2019
)
select
date,
sales,
round( coalesce( (sales-previous_month)*1.0/nullif(previous_month,0),0 )*100,2)
from cte
DEMO
EDIT as per requirement in comment
with cte as ( select
date_,
sales,
ROW_NUMBER() OVER (ORDER by date_) AS rn1,
ROW_NUMBER() OVER (ORDER by date_)-1 AS rn2
from sales_2019
)
select t1.date_,
t1.sales,
round( coalesce( (t1.sales-t2.sales)*1.0/nullif(t2.sales,0),0 )*100,2)
from cte t1 left join cte t2 on t1.rn2=t2.rn1
DEMO

Calculate Profit Based on First-In, First-Out Pricing By Date Of Sale

How can I find the sales margin every Day via SQL, assuming they are sold in the order they were purchased?
Please try this solution -
;with cte as
(
select purchase_date,item,cost, qty as num from purchase
union all
select purchase_date,item,cost, num-1 from cte where num>1
),
cte2 as
(
select sale_date,item,price, qty as num from sales
union all
select sale_date,item,price, num-1 from cte2 where num>1
)
select sale_date, sum(price-cost) from (
(select sale_date, item, price ,row_number() over (order by sale_date,num) rn from cte2) s
inner join
(select purchase_date, item, cost ,row_number() over (order by purchase_date,num) rn2 from cte) z
on s.item=z.item and s.rn=z.rn2)
group by sale_date

Oracle SQL, calculating next order qty based on order history

I am using the following script to get the order history of a particular manufacturing order;
select ds.status, ds.catnr, ds.part_no, ds.print_type, ds.nr_discs, ds.qty, ds.ship_date
from
(select 'Open Order' status, gb.catnr, gb.part_no, decode(gb.tec_criteria,'XX','SCREEN','OF','OFFSET','PI','OFFSET','MC','OFFSET') print_type, sp.nrunits nr_discs, sum(gb.or_menge_fd) qty, min(trunc(gb.shd_date)) ship_date
from gps_beweg gb, oes_customer oc, scm_packtyp sp
where gb.part_no = 'A0101628358-VV92-1900'
and gb.uebergabe_oes = '1'
and gb.pwerk_disc = 'W'
and gb.cunr = oc.cunr
and gb.packtyp = sp.packtyp
group by gb.cunr, oc.name, gb.part_no, sp.nrunits, gb.tec_criteria, gb.catnr, gb.prodtyp, gb.packtyp
UNION ALL
select unique 'Shipped Order' status,
null catnr, null part_no, null print_type, null nr_discs,
(select sum(ds1.planqty) from oes_delsegview ds1 where ds.ordnr = ds1.ordnr and ds.catnr = ds1.catnr and ds.prodtyp = ds1.prodtyp and ds.packtyp = ds1.packtyp) qty,
(select trunc(max(ds1.gps_planshpdate)) from oes_delsegview ds1 where ds.ordnr = ds1.ordnr and ds.catnr = ds1.catnr and ds.prodtyp = ds1.prodtyp and ds.packtyp = ds1.packtyp) ship_date
from part_description pd1, oes_delsegview ds
where pd1.part_no =
(select max(gb.part_no)
from gps_beweg gb
where gb.part_no = 'A0101628358-VV92-1900'
and gb.uebergabe_oes = '1'
and gb.pwerk_disc = 'W')
and pd1.catnr = ds.catnr
and pd1.prodtyp = ds.prodtyp
and pd1.packtyp = ds.packtyp
and ds.ord_o_status in ('7','9')
order by status, ship_date desc) ds
where rownum <=5
The result for this script looks like this...
I would like to use the data in the QTY and SHIP_DATE column to predict the next qty and date. I can do this in Excel using the TREND function. Is there a way of doing this in SQL? Will it be in line with the REGR_SLOPE function (I can't seem to get my head around how this works!?!).
As mentioned, as far as I know Oracle's SQL has no built-in trend functions to help you here. What you could do, though, is to to play around with analytic functions and come up with some algorithm.
ship_date - LAG(ship_date) OVER (ORDER BY ship_date) gives you the days between last and current order for instance. You'd have to weight these values, however, say multiply them with ROW_NUMBER() OVER (ORDER BY ship_date). Then divide to get the value to add to MAX(ship_date).
Here is the according query. A little hard to read and understand, but still an option in my opinion. The query retrieves all rows from yours plus a trend date and quantity for each row. So you can see what would have been forcast at some time and what shipment really followed. The last row gives you the current forecast.
select
status, catnr, part_no, print_type, nr_discs, qty, ship_date,
round(qty + sum(qty_diff_weighted) over (order by rn) /
(sum(rn) over (order by rn) - 1)) as trend_qty,
round(ship_date + sum(date_diff_weighted) over (order by rn) /
(sum(rn) over (order by rn) - 1)) as trend_date
from
(
select
status, catnr, part_no, print_type, nr_discs, qty, ship_date,
row_number() over (order by ship_date) *
(qty - lag(qty) over (order by ship_date)) as qty_diff_weighted,
row_number() over (order by ship_date) *
(ship_date - lag(ship_date) over (order by ship_date)) as date_diff_weighted,
row_number() over (order by ship_date) as rn
from (your query)
)
order by ship_date;
Result:
STATUS CATNR ... QTY SHIP_DATE TREND_QTY TREND_DATE
Shipped Order 500 06.06.2014
Shipped Order 500 17.11.2014 500 30.04.2015
Shipped Order 300 21.09.2015 180 28.05.2016
Shipped Order 300 16.08.2016 233 29.05.2017
Open Order PPD168 300 24.03.2017 257 11.12.2017
This shows the technique. You may come up with a completely different algorithm that suits you better, of course.