【问题标题】:Calculate column value based on criterias (values from both current row and a previous one)根据条件计算列值(当前行和前一行的值)
【发布时间】:2021-09-20 15:29:18
【问题描述】:

我正在尝试通过结合我对金融的兴趣来学习一些 SQL。目前我正在尝试根据交易列表(在 SQL Server 中)计算一些投资组合数据。

这是我的桌子:

create table StockTransactions 
(
    TransactionID int,
    Instrument varchar(32),
    TransactionType varchar(32),
    Units int,
    Price float,
    TransactionSum as case
        when TransactionType = 'Buy' then (-(Units * Price))
        when TransactionType = 'Sell'  then (Units * Price)
        else 0
        end,
    PurchaseCost float
)

样本数据:

insert into StockTransactions (TransactionID, Instrument, TransactionType, Units, Price)
values 
(1, 'Apple', 'Buy', 10, 120),
(2, 'Microsoft', 'Buy', 20, 290),
(3, 'Apple', 'Buy', 10, 125),
(4, 'Apple', 'Sell', 5, 140),
(5, 'Apple', 'Buy', 10, 130),
(6, 'Apple', 'Sell', 10, 135)

此表中的结果:

TransactionID Instrument TransactionType Units Price TransactionSum PurchaseCost
1 Apple Buy 10 120 -1200 NULL
2 Microsoft Buy 20 290 -5800 NULL
3 Apple Buy 10 125 -1250 NULL
4 Apple Sell 5 140 700 NULL
5 Apple Buy 10 130 -1300 NULL
6 Apple Sell 10 135 1350 NULL

我正在尝试计算 PurchaseCost 列的值。我想要的值是:

Row PurchaseCost
1 -1200
2 -5800
3 -2450
4 -1837.5
5 -3137.5
6 -2353.13

逻辑如下。如果已进行购买,则应将 TransactionSum 添加到该工具的最新先前 PurchaseCost。但是,当进行销售时,应该减去一定的金额。

在第四次交易中,我卖出了 20 股 Apple 股票中的 5 股。因此,我想减去之前 PurchaseCost 的 1/4,得到新的 PurchaseCost 值 -1837.5。

在交易 6 中,我卖出了 25 股 Apple 股票中的 10 股,然后想将 PurchaseCost 降低到 2353.13(之前价值的 60%)。

我自己似乎无法弄清楚如何做到这一点。有什么想法吗?

【问题讨论】:

  • 仅供参考,对于名为 Price 的列,数据类型 float 是一个糟糕的选择。货币价值应该永远存储为浮点数。
  • 看起来PurchaseCost 是一个运行总值。如果是这样,那不属于表格,最好在VIEW 中提供。
  • 也许可以从this 得到答案,除非您似乎在寻找 FIFO 而不是 LIFO
  • 您的表格也需要一个日期(可能还需要一个时间部分)——您应该重新考虑派生成本的会计逻辑,以便计算利润(或收入或您想要应用的任何术语)。在现实世界中,人们对旧交易进行长期修正,并在旧交易中添加新交易。如果打算将其用作真正的生产就绪系统,那么您当前的路径过于简单。
  • 感谢您的建议! Larnu:我将在我的数据库中更改 Price 的名称,并查看视图以了解它们如何在这种情况下使用。 SteveC:实际上在我的国家,我们使用平均成本而不是先进先出或后进先出。所以每次购买(只要我有职位)都会产生影响。 (这在报税季会很烦人。)

标签: sql sql-server


【解决方案1】:

您可以创建存储过程来计算每一行 这里是使用临时表计算和选择的代码

IF OBJECT_ID('tempdb..#TempStock') IS NOT NULL DROP TABLE #TempStock

DECLARE @TransId int
DECLARE @TempInst varchar(32)
DECLARE @TempPurchase float
DECLARE @TempUnit int
DECLARE @TempTrans varchar(32)
DECLARE @LastPurchase float
DECLARE @LastUnits int

CREATE TABLE #TempStock (
    TransactionID int,
    Instrument varchar(32),
    Units int,
    PurchaseCost float
)

DECLARE MY_CURSOR CURSOR
FOR SELECT DISTINCT TransactionID 
FROM StockTransactions


OPEN MY_CURSOR
FETCH NEXT FROM MY_CURSOR INTO @TransId
WHILE @@FETCH_STATUS = 0
BEGIN 
    SELECT @TempInst = Instrument, @TempTrans = TransactionType, @TempUnit = Units, @TempPurchase = TransactionSum FROM StockTransactions
    WHERE TransactionID = @TransId

    SELECT  TOP 1 @LastPurchase = PurchaseCost, @LastUnits = Units
    FROM #TempStock
    WHERE Instrument = @TempInst
    ORDER BY TransactionID DESC
    
    IF @@ROWCOUNT = 0
    BEGIN
        SELECT @LastPurchase = 0, @LastUnits = 0 
    END

    IF @TempTrans = 'Buy'
    BEGIN
        INSERT INTO #TempStock (TransactionID, Instrument, Units, PurchaseCost)
        VALUES (
            @TransId,
            @TempInst,
            ISNULL(@LastUnits,0) + ISNULL(@TempUnit,0),
            ISNULL(@LastPurchase,0) + ISNULL(@TempPurchase,0)
        )
    END
    ELSE IF @TempTrans = 'Sell'
    BEGIN
        INSERT INTO #TempStock (TransactionID, Instrument, Units, PurchaseCost)
        VALUES (
            @TransId,
            @TempInst,
            ISNULL(@LastUnits,0) - ISNULL(@TempUnit,0),
            (ISNULL(@LastPurchase,0) * (ISNULL(@LastUnits,0) - ISNULL(@TempUnit,0))) / ISNULL(@LastUnits,0)
        )
    END
    
    FETCH NEXT FROM MY_CURSOR INTO @TransId
END
CLOSE MY_CURSOR
DEALLOCATE MY_CURSOR

SELECT TransactionID, PurchaseCost FROM #TempStock

DROP TABLE #TempStock

您可以从该临时表更新主表

【讨论】:

  • 感谢您花时间写出如此全面的答案!通过尝试理解一切,我学到了很多东西。我也一直在玩它,使用不同的测试数据。那里似乎有一个错误,它有时会从错误的工具中获取 PurchaseCost 和 Units。您的代码适用于我上面的示例交易,但如果我要在 #2 插入另一个 Apple 交易(并将以下所有 TransactionID 更改为 +1),则在 #3(之前在 #2)的第一笔 Microsoft 交易将是一个组合#1 和 #3,尽管它们不属于同一乐器。
  • 我已编辑答案以修复错误。只需添加行数即可检查#tempstock
  • 解决了这个问题。再次感谢您!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多