更新时间:2022-12-31 10:14:41
您可以使用 可以使用以下查询获得:
声明@Trade TABLE(ID INT 身份,UserCompetitionId INT DEFAULT(92170),StockId INT 默认(122),单位 INT,购买价格 NUMERIC(8, 4));INSERT @Trade(Units, PurchasePrice)值 (100, 97.8774),(200, 97.89),(-300, 97.8858),(600, 48.9429),(100, 60.9),(-600, 60.395);和一个 AS(选择*,金额 = SUM(IIF(Units > 0, Units * PurchasePrice, 0)) OVER(按 UserCompetitionId、StockId 划分按 Id 行***排序),数量 = SUM(IIF(Units > 0, Units, 0)) OVER(按 UserCompetitionId、StockId 划分按 Id 行***排序)来自@Trade)选择单位为金额,CAST(PurchasePrice AS NUMERIC(6,2)) AS [购买价格],CAST(ABS(Units * PurchasePrice) AS NUMERIC(12,2)) AS [采购金额],CAST(Amount/Qty AS NUMERIC(6, 2)) AS调整后的购买价格"从 A按 ID 排序;
输出:
+--------+--------------+---------------+------------------------+|金额|购买价格|购买金额|调整后的购买价格|+--------+--------------+--------------+-----------------------+|100 |97,88 |9787,74 |97,88 ||200 |97,89 |19578,00 |97,89 ||-300 |97,89 |29365,74 |97,89 ||600 |48,94 |29365,74 |65,26 ||100 |60,90 |6090,00 |64,82 ||-600 |60,40 |36237,00 |64,82 |+--------+--------------+--------------+-----------------------+
I am trying to calculate the weighted average price for stocks using Microsoft SQL Server 2016. The difference with what I'm asking is that when all stocks have been sold the weighted price should be reset
Issue
NewPrice is incorrect in the following trades table
Expected Output
Row NewPrice
1 186.4000
2 186.4000
3 183.0800
4 183.0800
5 183.0800
6 183.0800
7 183.0800
8 183.0800
7 183.0800
Query
SELECT *,
PriceRunningTotalFinal =
SUM(CASE
WHEN QuantityRunningTotal = 0 THEN -1 * PriceRunningTotal
WHEN Units < 0 THEN 0 ELSE PurchasePrice * Units END) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
CASE WHEN Results1.QuantityRunningTotal <= 0 then 0
else
SUM(CASE
WHEN QuantityRunningTotal <= 0 THEN -1 * PriceRunningTotal
WHEN Units < 0 THEN 0 ELSE PurchasePrice * Units END) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
) / Results1.QuantityRunningTotal
end as NewPrice
FROM
(
SELECT Id, UserCompetitionId, StockId, Type, Units, PurchasePrice, CreatedOn,
QuantityRunningTotal = SUM(Units) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
PriceRunningTotal = SUM(CASE WHEN Units <= 0 THEN 0 ELSE PurchasePrice * Units END) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM Trade
) AS Results1
WHERE UserCompetitionId =@UserCompetitionId AND StockId = 122
The problem I'm having is with the newPrice.
From Row 4 onwards the price should be 183.08000
This is because all previous stocks have been sold (QuantityRunningTotal is 0). Therefore the weighted purchase price calculation needs to start again and not take into account the previous rows
UPDATE
Looking at Andrei Odegov answer, the solution works. But one thing I failed to mention is that I would like to get the adjusted weighted prices for each row
As can be seen in this screenshot:
Weighted average price I tried to get the average price, it sort of works but I'm not sure it's the right way to go about it?
DECLARE @Trade TABLE(
Id INT IDENTITY,
UserCompetitionId INT DEFAULT(92170),
StockId INT DEFAULT(122),
Type INT,
Units INT,
PurchasePrice NUMERIC(8, 4)
);
INSERT @Trade(Type, Units, PurchasePrice)
VALUES (10, 42, 186.4),
(20, -42, 183.08),
(10, 40, 183.08),
(20, -5, 183.92),
(20, -1, 181.68),
(20, -1, 181.68),
(20, -1, 181.68),
(20, 17, 181.68),
(20, -10, 181.68);
WITH
A AS(
SELECT
*,
QuantityRunningTotal = SUM(Units) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM @Trade
),
B AS (
SELECT
*,
Grp = SUM(IIF(QuantityRunningTotal - Units <= 0, 1, 0)) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM A
)
SELECT *, TotalAmount / Qty
FROM (
SELECT
*,
Units * PurchasePrice AS PurchaseAmount,
NewPrice = FIRST_VALUE(PurchasePrice) OVER
(
PARTITION BY UserCompetitionId, StockId, Grp
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
row_number() over (partition by UserCompetitionId, StockId order by Id desc) as Seq,
TotalAmount = SUM(CASE WHEN Units < 0 THEN 0 ELSe Units * PurchasePrice END) OVER
(
PARTITION BY UserCompetitionId, StockId, Grp
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
Qty = SUM(CASE WHEN Units < 0 THEN 0 ELSe Units END) OVER
(
PARTITION BY UserCompetitionId, StockId, Grp
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM B
)AS Result
WHERE Result.Seq = 1 AND QuantityRunningTotal > 0
ORDER BY StockId;
UPDATE2 (Gets the overall purchase price $50.65)
DECLARE @Trade TABLE(
Id INT IDENTITY,
UserCompetitionId INT DEFAULT(92170),
StockId INT DEFAULT(122),
Units INT,
PurchasePrice NUMERIC(8, 4)
);
INSERT @Trade(Units, PurchasePrice)
VALUES (100, 97.8774),
(200, 97.89),
(-300, 97.8858),
(600, 48.9429),
(100, 60.9),
(-600, 60.395);
WITH
A AS(
SELECT
*,
Amount = SUM(IIF(Units > 0, Units * PurchasePrice, 0)) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
Qty = SUM(IIF(Units > 0, Units, 0)) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
Qty2 = SUM(Units) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
TotalAmount = SUM(Units * PurchasePrice) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM @Trade
)
SELECT
Units AS Amount,
CAST(PurchasePrice AS NUMERIC(6,2)) AS [Purchase Price],
CAST(ABS(Units * PurchasePrice) AS NUMERIC(12,2)) AS [Purchase Amount],
CAST(Amount / Qty AS NUMERIC(6, 2)) AS "Adjusted Purchase Price",
Qty2,
TotalAmount,
IIF(Qty2 = 0, 0,TotalAmount/ Qty2) AS Average
FROM A
ORDER BY Id;
Any ideas would be greatly appreciated
You can get the desired result using the FIRST_VALUE
function.
WITH
A AS(
SELECT
*,
QuantityRunningTotal = SUM(Units) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM @Trade
),
B AS (
SELECT
*,
Grp = SUM(IIF(QuantityRunningTotal - Units <= 0, 1, 0)) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM A
)
SELECT
*,
NewPrice = FIRST_VALUE(PurchasePrice) OVER
(
PARTITION BY UserCompetitionId, StockId, Grp
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM B
ORDER BY Id;
Output:
+----+-------------------+---------+------+-------+---------------+----------------------+-----+----------+
| Id | UserCompetitionId | StockId | Type | Units | PurchasePrice | QuantityRunningTotal | Grp | NewPrice |
+----+-------------------+---------+------+-------+---------------+----------------------+-----+----------+
| 1 | 92170 | 122 | 10 | 42 | 186,4000 | 42 | 1 | 186,4000 |
| 2 | 92170 | 122 | 20 | -42 | 183,0800 | 0 | 1 | 186,4000 |
| 3 | 92170 | 122 | 10 | 40 | 183,0800 | 40 | 2 | 183,0800 |
| 4 | 92170 | 122 | 20 | -5 | 183,9200 | 35 | 2 | 183,0800 |
| 5 | 92170 | 122 | 20 | -1 | 181,6800 | 34 | 2 | 183,0800 |
| 6 | 92170 | 122 | 20 | -1 | 181,6800 | 33 | 2 | 183,0800 |
| 7 | 92170 | 122 | 20 | -1 | 181,6800 | 32 | 2 | 183,0800 |
| 8 | 92170 | 122 | 20 | -2 | 181,6800 | 30 | 2 | 183,0800 |
| 9 | 92170 | 122 | 20 | -30 | 181,6800 | 0 | 2 | 183,0800 |
| 10 | 92170 | 122 | 20 | 17 | 181,6800 | 17 | 3 | 181,6800 |
| 11 | 92170 | 122 | 20 | -10 | 181,6800 | 7 | 3 | 181,6800 |
+----+-------------------+---------+------+-------+---------------+----------------------+-----+----------+
Demo:
https://rextester.com/IMN29774.
Update:
The figures of this your screenshot can be obtained using the following query:
DECLARE @Trade TABLE(
Id INT IDENTITY,
UserCompetitionId INT DEFAULT(92170),
StockId INT DEFAULT(122),
Units INT,
PurchasePrice NUMERIC(8, 4)
);
INSERT @Trade(Units, PurchasePrice)
VALUES (100, 97.8774),
(200, 97.89),
(-300, 97.8858),
(600, 48.9429),
(100, 60.9),
(-600, 60.395);
WITH
A AS(
SELECT
*,
Amount = SUM(IIF(Units > 0, Units * PurchasePrice, 0)) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
),
Qty = SUM(IIF(Units > 0, Units, 0)) OVER
(
PARTITION BY UserCompetitionId, StockId
ORDER BY Id ROWS UNBOUNDED PRECEDING
)
FROM @Trade
)
SELECT
Units AS Amount,
CAST(PurchasePrice AS NUMERIC(6,2)) AS [Purchase Price],
CAST(ABS(Units * PurchasePrice) AS NUMERIC(12,2)) AS [Purchase Amount],
CAST(Amount / Qty AS NUMERIC(6, 2)) AS "Adjusted Purchase Price"
FROM A
ORDER BY Id;
Output:
+--------+--------------+---------------+-----------------------+
| Amount |Purchase Price|Purchase Amount|Adjusted Purchase Price|
+--------+--------------+---------------+-----------------------+
| 100 | 97,88 | 9787,74 | 97,88 |
| 200 | 97,89 | 19578,00 | 97,89 |
| -300 | 97,89 | 29365,74 | 97,89 |
| 600 | 48,94 | 29365,74 | 65,26 |
| 100 | 60,90 | 6090,00 | 64,82 |
| -600 | 60,40 | 36237,00 | 64,82 |
+--------+--------------+---------------+-----------------------+