FIFO Stock Valuation Through CTE-Recursion - sql-server

I have copied it from this site because it's been already closed but I needed it for further solution. thus, kindly help me out.....
Problem : it's calculating the closing stock valuation through FIFO of issue as a whole. but i need cost of issues into Price column in the same row it belongs to itself.
declare #Stock table (Item char(3) not null,[Date] datetime not null,TxnType varchar(3) not null,Qty int not null,Price decimal(10,2) null)
insert into #Stock(Item , [Date] , TxnType, Qty, Price) values
('ABC','20120401','IN', 200, 750.00),
('ABC','20120405','OUT', 100 ,null ),
('ABC','20120410','IN', 50, 700.00),
('ABC','20120416','IN', 75, 800.00),
('ABC','20120425','OUT', 175, null ),
('XYZ','20120402','IN', 150, 350.00),
('XYZ','20120408','OUT', 120 ,null ),
('XYZ','20120412','OUT', 10 ,null ),
('XYZ','20120424','IN', 90, 340.00);
;WITH OrderedIn as (
select *,ROW_NUMBER() OVER (PARTITION BY Item ORDER BY [DATE]) as rn
from #Stock
where TxnType = 'IN'
), RunningTotals as (
select Item,Qty,Price,Qty as Total,0 as PrevTotal,rn from OrderedIn where rn = 1
union all
select rt.Item,oi.Qty,oi.Price,rt.Total + oi.Qty,rt.Total,oi.rn
from
RunningTotals rt
inner join
OrderedIn oi
on
rt.Item = oi.Item and
rt.rn = oi.rn - 1
), TotalOut as (
select Item,SUM(Qty) as Qty from #Stock where TxnType='OUT' group by Item
)
select
rt.Item,SUM(CASE WHEN PrevTotal > out.Qty THEN rt.Qty ELSE rt.Total - out.Qty END * Price)
from
RunningTotals rt
inner join
TotalOut out
on
rt.Item = out.Item
where
rt.Total > out.Qty
group by rt.Item
The result is only Closing Stock as per FIFO Basis as below:
Item ClsStock
ABC 40000.00
XYZ 37600.00
But I need the followings Result from the same query:
Item Date TxnType OpnQty OpnRate OpnVal InnQty InnRate InnVal OutQty OutRate OutVal ClsQty ClsRate ClsVal
ABC 20120401 IN 200 750 150000 200 750.00 150000
ABC 20120405 OUT 200 750.00 150000 100 750 75000 100 750.00 75000
ABC 20120410 IN 100 750.00 75000 50 700 35000 150 733.33 110000
ABC 20120416 IN 150 733.33 110000 75 800 60000 225 755.56 170000
ABC 20120425 OUT 225 755.56 170000 175 742.86 130000 50 800.00 40000
Total 0 0.00 0 325 753.85 245000 275 745.45 205000 50 800.00 40000
XYZ 20120402 IN 150 350 52500 150 350.00 52500
XYZ 20120408 OUT 150 350.00 52500 120 350 42000 30 350.00 10500
XYZ 20120412 OUT 30 350.00 10500 10 350 3500 20 350.00 7000
XYZ 20120424 IN 20 350.00 7000 90 340 30600 110 341.82 37600
Total 0 0.00 0 240 346.25 83100 130 350 45500 110 341.82 37600
Grand Total 0 #DIV/0! 0 565 580.71 328100 405 618.52 250500 160 485.00 77600

Related

How to add sum value to every row?

Below is my table:
id order_number order_date order_details
---------------------------------------------
1 222 01-01-2020 44
2 222 02-01-2020 66
3 222 03-01-2020 20
4 223 03-01-2020 33
5 224 04-01-2020 55
6 225 02-01-2020 77
I want to have sum(order_details) where order_number = 222
like this table
order_date sum_order_details
----------------------------------
01-01-2020 130
02-01-2020 130
03-01-2020 130
I tried the below but it doesn't work
select order_number , order_date , sum(order_details) sum_orders from ex
group by order_number
having order_number = 222
It seems like you're after this is a windowed SUM:
SELECT order_date,
SUM(order_details) OVER () AS sum_orders
FROM YourTable
WHERE order_number = 222;

Running (Average True Range) calculation in a column SQL

I have a dataset of price data and would like to get the calculation of the ongoing ATR (Average True Range) for all rows > 21. Row 21 is the AVG([TR]) from Rows 2-21 and is equal to 353.7.
The calculation that needs to be continuous for the rest of that [ATR_20] column will need to be:
ATR_20 (after row 21) = (([Previous ATR_20]*19)+[TR])/20
My dataset:
Date Open High Low Close TotalVolume Prev_Close TR_A TR_B TR_C TR ATR
2017-02-01 5961 5961 5425 5498 22689 NULL 536 NULL NULL NULL NULL
2017-02-02 5697 5868 5615 5734 22210 5498 253 370 117 370 NULL
2017-02-03 5742 5811 5560 5725 15852 5734 251 77 174 251 NULL
2017-02-06 5675 5679 5545 5554 9777 5725 134 46 180 180 NULL
2017-02-07 5597 5613 5426 5481 12692 5554 187 59 128 187 NULL
2017-02-08 5459 5630 5450 5625 9134 5481 180 149 31 180 NULL
2017-02-09 5615 5738 5532 5668 10630 5625 206 113 93 206 NULL
2017-02-10 5651 5661 5488 5602 9709 5668 173 7 180 180 NULL
2017-02-13 5700 6195 5639 6161 26031 5602 556 593 37 593 NULL
2017-02-14 6197 6594 6073 6571 35969 6161 521 433 88 521 NULL
2017-02-15 6510 6650 6275 6492 22046 6571 375 79 296 375 NULL
2017-02-16 6505 6680 6325 6419 12515 6492 355 188 167 355 NULL
2017-02-17 6434 6670 6429 6658 14947 6419 241 251 10 251 NULL
2017-02-21 6800 6957 6603 6654 23838 6658 354 299 55 354 NULL
2017-02-22 6704 6738 6145 6222 25004 6654 593 84 509 593 NULL
2017-02-23 6398 6437 5901 6343 46677 6222 536 215 321 536 NULL
2017-02-24 5280 5589 5260 5404 51757 6343 329 754 1083 1083 NULL
2017-02-27 5437 5461 5260 5300 19831 5404 201 57 144 201 NULL
2017-02-28 5258 5410 5167 5195 15900 5300 243 110 133 243 NULL
2017-03-01 5251 5299 5052 5215 16958 5195 247 104 143 247 NULL
2017-03-02 5160 5231 5063 5130 17805 5215 168 16 152 168 353.7
2017-03-03 5141 5363 5088 5320 14516 5130 275 233 42 275 NULL
I got to this point by the following
WITH cte_ACIA ([RowNumber], [Date], [Open], [High], [Low], [Close],
[Prev_Close], [TotalVolume], [TR_A], [TR_B], [TR_C])
AS
(SELECT
ROW_NUMBER() OVER (ORDER BY [Date] ASC) RowNumber,
[Date],
[Open],
[High],
[Low],
[Close],
LAG([Close]) OVER(ORDER BY [Date]) AS Prev_Close,
[TotalVolume],
ROUND([High]-[Low], 5) AS TR_A,
ABS(ROUND([High]-LAG([Close]) OVER(ORDER BY [Date]), 5)) AS TR_B,
ABS(ROUND([Low]-LAG([Close]) OVER(ORDER BY [Date]), 5)) AS TR_C,
FROM NASDAQ.ACIA_TEMP)
SELECT [RowNumber], [Date], [Open], [High], [Low], [Close], [Prev_Close],
[TotalVolume], [TR_A], [TR_B], [TR_C], [TR],
CASE
WHEN RowNumber = 21 THEN AVG([TR]) OVER (ORDER BY [Date] ASC ROWS 19 PRECEDING)
END AS ATR_20
FROM
(
SELECT [RowNumber],[Date],[Open],[High],[Low],[Close],
IIF(RowNumber = 1, NULL, Prev_Close) Prev_Close,
[TotalVolume],
[TR_A],
IIF(RowNumber > 1, [TR_B], NULL) TR_B,
IIF(RowNumber > 1, [TR_C], NULL) TR_C,
CASE
WHEN TR_A > TR_B AND TR_A > TR_C THEN TR_A
WHEN TR_B > TR_A AND TR_B > TR_C THEN TR_B
ELSE TR_C
END AS TR
FROM cte_ACIA) sub
Please let me know if you have questions or I need to clarify anything.
I suppose you are just looking for a hint. Otherwise you would have posted your table definition. We can't construct a query for you since we don't have the basic pieces. However, here's the hint! Use an aggregating window function with the OVER clause specifying ROWS PRECEDING.
See SELECT - OVER Clause

How to add values in sql

Hey i have a table like this
Product_name Rate Cost GST_percentage Recipt_no Amount Final_Amount ID Description GST_price Quantity OrderID Discount Net_Unit_Price Stock_Pending Payment_Pending
SINGTEL DATA + EZ $10 1.5 GB 7 DAYS 10 120.00 5 1 120.00 126 1 A 6.00 12 ODR1 0.00 10.00 Received Paid
SINGTEL DATA + EZ $10 1.5 GB 7 DAYS 12 180.00 0 2 180.00 180.00 2 A 0.00 15 ODR2 0.00 12.00 NULL NULL
SINGTEL DATA + EZ $8 CHINA 888 10 120.00 0 2 120.00 120.00 3 B 0.00 12 ODR2 0.00 10.00 NULL NULL
and i want to show the final_Amount column value groupped by order Id.then i want to show the final_amount for those which is Payment_Pending status is not null but i can't get the correct result.
Note:
i got a result as
query:
SELECT [OrderID],
SUM(convert(float,[Final_Amount])) as Final_Amount,
(select sum(convert(float,Final_Amount)) as Final_Amount
from Purchase_Order
where Payment_Pending is not null) as paid
FROM [Purchase_Order]
group by [OrderID]
order by OrderID desc
OrderID Final_Amount paid
ODR2 300 126
ODR1 126 126
but i want like this
OrderID Final_Amount paid
ODR2 300 0
ODR1 126 126
(Because ODR2 Payment_Pending Column filled with null)
Probably your sub-query is wrong. It need to include a reference to OrderId of main query
SELECT [OrderID],
SUM(convert(float,[Final_Amount])) as Final_Amount,
(select sum(convert(float,Final_Amount)) as Final_Amount
from Purchase_Order x
where x.Payment_Pending is not null
and x.OrderId = p.OrderId) as paid
FROM [Purchase_Order] p
group by [OrderID]
order by OrderID desc

Grouping rows to minimise deviation

I have a Employee Wages table like this, with their EmpID and their wages.
EmpId | Wages
================
101 | 1280
102 | 1600
103 | 1400
104 | 1401
105 | 1430
106 | 1300
I need to write a Stored Procedure in SQL Server, to group the Employees according to their wages, such that similar salaried people are in groups together and the deviations within the group is as minimum as possible.
There are no other conditions or rules mentioned.
The output should look like this
EmpId | Wages | Group
=======================
101 | 1280 | 1
106 | 1300 | 1
103 | 1400 | 2
104 | 1401 | 2
105 | 1430 | 2
102 | 1600 | 3
You can use a query like the following:
SELECT EmpId, Wages,
DENSE_RANK() OVER (ORDER BY CAST(Wages - t.min_wage AS INT) / 100) AS grp
FROM mytable
CROSS JOIN (SELECT MIN(Wages) AS min_wage FROM mytable) AS t
The query calculates the distance of each wage from the minimum wage and then uses integer division by 100 in order to place records in slices. So all records that have a deviation that is between 0 - 99 off the minimum wage are placed in the first slice. The second slice contains records off by 100 - 199 from the minimum wage, etc.
You can for +-30 deviation as the below:
DECLARE #Tbl TABLE (EmpId INT, Wages INT)
INSERT INTO #Tbl
VALUES
(99, 99),
(100, 101),
(101, 1280),
(102, 1600),
(103, 1400),
(104, 1401),
(105, 1430),
(106, 1300)
;WITH CTE AS ( SELECT *, ROW_NUMBER() OVER (ORDER BY Wages) AS RowId FROM #Tbl )
SELECT
A.EmpId ,
A.Wages ,
DENSE_RANK() OVER (ORDER BY MIN(B.RowId)) [Group]
FROM
CTE A CROSS JOIN CTE B
WHERE
ABS(B.Wages - A.Wages) BETWEEN 0 AND 30 -- Here +-30
GROUP BY A.EmpId, A.Wages
ORDER BY A.Wages
Result:
EmpId Wages Group
----------- ----------- --------------------
99 99 1
100 101 1
101 1280 2
106 1300 2
103 1400 3
104 1401 3
105 1430 3
102 1600 4

How to group data into buckets in Microsoft SQL

Currently my SQL statement is the following
SELECT NAME, ROUND([DR# BASE]/DAYS_WORKED,0) AS 'BASE/DAY'
FROM MYTABLE
And the output data looks like the following
NAME BASE/DAY
James 300
Jane 310
Jim 313
John 325
Jonah 400
Is there a SQL statement to make the Output look like the following?
NAME BUCKET BASE/DAY
James 300 <= 325 300
Jane 300 <= 325 310
Jim 300 <= 325 313
John 300 <= 325 325
Johnny 325 <= 350 329
Jonah 350 <= 400 400
SELECT NAME,
CASE WHEN [BASE/DAY] <= 325 THEN '300 <= 325'
WHEN [BASE/DAY] <= 350 THEN '325 <= 350'
WHEN [BASE/DAY] <= 400 THEN '350 <= 400'
END AS BUCKET,
[BASE/DAY]
FROM
(
SELECT NAME, ROUND([DR# BASE]/DAYS_WORKED,0) AS 'BASE/DAY' FROM MYTABLE
) T
ORDER BY 1, 2, 3
SELECT NAME,
[BASE/DAY],
CAST( ([BASE/DAY]-1) / 25) * 25 AS varchar(20)) + ' <= ' +
CAST( ([BASE/DAY]-1) / 25 + 1) * 25 AS varchar(20)) As Bucket,
FROM
(SELECT Name, ROUND([DR# BASE]/DAYS_WORKED,0) AS [BASE/DAY]
FROM MYTABLE) T
Edit: fixed the boundary values to appear within the lower bucket.

Resources