【问题标题】:FIFO match first stock buys to first sells sqlFIFO匹配先买先卖sql
【发布时间】:2016-02-13 16:41:59
【问题描述】:

我的数据如下所示:

Stock buys and sells

我需要一个查询来将 FIFO 方法应用于 Buys 和 Sells,所以我得到一个如下所示的表: FIFO Buys and Sells

我希望能够将第一次买入与第一次卖出相匹配,左边是买入,右边是卖出。如果没有卖出,则应在右侧应用空值,如果没有买入,则应在左侧应用空值。经纪交易密钥可用作交易发生的顺序。这是我到目前为止所尝试的。任何帮助将不胜感激!

SELECT  a.ACCT_ID, a.Trade_Date_Key, a.Brokerage_Transaction_Key, a.Buy_Sell_Code, a.Principal_Amt, a.Security_Quantity
     , (a.Security_Quantity + b.Security_Quantity) CUMULATIVE_POSITION
     , a.SHARE_PRICE
     , (A.Principal_Amt + B.Principal_Amt) CUMULATIVE_VALUE
from #TRANSACTIONS_WITH_RANK a
     left join #TRANSACTIONS_WITH_RANK b 
     on a.acct_id = b.acct_id and a.rank = b.rank + 1
ORDER BY BROKERAGE_TRANSACTION_KEY

【问题讨论】:

    标签: sql sql-server common-table-expression fifo cursors


    【解决方案1】:

    在您的问题中,您提到将第一次购买与第一次卖出相匹配,但您的示例输出似乎忽略了该部分。下面是一个示例,如果您想根据 Acct_ID 和 Trade_Date 将首次购买与首次出售进行匹配,该怎么做

    SELECT buy.*, sell.*
    FROM #TRANSACTIONS_WITH_RANK buy
        INNER JOIN (
            SELECT MIN(Trade_Date) Trade_Date
            FROM #TRANSACTIONS_WITH_RANK
            WHERE Buy_Sell_Code = 'B'
            GROUP BY Acct_ID
        ) TDateBuy
        ON buy.Trade_Date = TDateBuy.Trade_Date
        FULL OUTER JOIN #TRANSACTIONS_WITH_RANK sell
            INNER JOIN (
                SELECT MIN(Trade_Date) Trade_Date
                FROM #TRANSACTIONS_WITH_RANK
                WHERE Buy_Sell_Code = 'S'
                GROUP BY Acct_ID
            ) TDateSell
            ON sell.Trade_Date = TDateSell.Trade_Date
        ON buy.Acct_ID = sell.Acct_ID
    

    编辑:在看到 OP 的评论后,我更改了查询

    SELECT 
        buy.Acct_ID, buy.Trade_Date, buy.Brokerage_Transaction_Key, buy.Buy_Sell_Code, buy.Principal_Amt, buy.Security_Quantity, 
        sell.Acct_ID, sell.Trade_Date, sell.Brokerage_Transaction_Key, sell.Buy_Sell_Code, sell.Principal_Amt, sell.Security_Quantity
    FROM (
            SELECT wr.*, MIN(TransKey) TransKey -- This is the value of the Sell to be joined
            FROM #TRANSACTIONS_WITH_RANK wr
                LEFT OUTER JOIN (
                    SELECT MIN(Brokerage_Transaction_Key) TransKey, Acct_ID
                    FROM (
                            SELECT 
                                tr.*, 
                                (
                                    SELECT MAX(Brokerage_Transaction_Key) --Purpose is to give outer query value to GROUP on
                                    FROM #TRANSACTIONS_WITH_RANK 
                                    WHERE Buy_Sell_Code = 'B' 
                                        AND Acct_ID = tr.Acct_ID
                                        AND Brokerage_Transaction_Key < tr.Brokerage_Transaction_Key
                                ) MaxLesserKey
                            FROM #TRANSACTIONS_WITH_RANK tr
                        ) data
                    WHERE Buy_Sell_Code = 'S'
                    GROUP BY Acct_ID, MaxLesserKey
                ) MinSell
                ON wr.Acct_ID = MinSell.Acct_ID
                    AND wr.Brokerage_Transaction_Key < MinSell.TransKey
            WHERE Buy_Sell_Code = 'B'
            GROUP BY wr.Acct_ID, Trade_Date, Brokerage_Transaction_Key, Buy_Sell_Code, Principal_Amt, Security_Quantity
        ) buy
        FULL OUTER JOIN (
            SELECT wr.*, MIN(MinBuy.TransKey) TransKey -- This is the value of the Buy to be joined
            FROM #TRANSACTIONS_WITH_RANK wr
                LEFT OUTER JOIN (
                    SELECT MIN(Brokerage_Transaction_Key) TransKey, Acct_ID
                    FROM (
                            SELECT 
                                tr.*,
                                (
                                    SELECT MAX(Brokerage_Transaction_Key) --Purpose is to give outer query a value to GROUP on
                                    FROM #TRANSACTIONS_WITH_RANK
                                    WHERE Buy_Sell_Code = 'S'
                                        AND Brokerage_Transaction_Key < tr.Brokerage_Transaction_Key
                                ) MaxLesserKey
                            FROM #TRANSACTIONS_WITH_RANK tr
                        ) data
                    WHERE Buy_Sell_Code = 'B'
                    GROUP BY Acct_ID, MaxLesserKey
                ) MinBuy
                ON wr.Acct_ID = MinBuy.Acct_ID
                    AND wr.Brokerage_Transaction_Key < MinBuy.TransKey
            WHERE Buy_Sell_Code = 'S'
            GROUP BY wr.Acct_ID, Trade_Date, Brokerage_Transaction_Key, Buy_Sell_Code, Principal_Amt, Security_Quantity
        ) sell
        ON buy.TransKey = sell.Brokerage_Transaction_Key
            OR sell.TransKey = buy.Brokerage_Transaction_Key
    

    基本上,它的作用是获取所有 Buy(s) 及其匹配的 Sell Brokerage_Transaction_Key (TransKey) 并在没有相反匹配的交易时执行 FULL OUTER JOIN (NULLs 买入或卖出侧) 到一组 Sell(s) 及其匹配的 Buy Brokerage_Transaction_Key (TransKey)。 对于每组买入/卖出,TransKey 是相对的Buy_Sell_Code 中最小的Brokerage_Transaction_Key。对于特定Acct_ID,这将为您提供每组交易的先卖到先买或先买到先卖。 MaxLesserKey 字段只是为了给TransKey 查询一个值给GROUP on

    【讨论】:

    • 对不起,我应该更清楚一点,brokerage_transaction_key 是一个唯一的字段,表示交易的顺序。所以需要用它来指示每个账户中哪个买在哪个卖之前。
    • 我现在明白了。这仅适用于第一个买卖集吗?即,一个账户有 3 次买入与一次卖出相匹配(称为set1),然后在以后他们有另外 2 次买入之前他们有卖出(称为set2)。 set2 应该在数据中显示为另一组买/卖,还是应该仍然只显示 set1?
    • 你是对的,应该设置2。如果有意义,买方的安全数量需要与卖方的安全数量相匹配。
    • 澄清一下,应该是set2还是两个?
    • 两套。因此,如果前 3 次买入为 100、200、100,第一次卖出为 400,则设置为 1,如果下一次买入为 100,接下来的两次卖出为 50 和 50,则设置为 2。
    猜你喜欢
    • 2010-09-28
    • 1970-01-01
    • 2019-12-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    相关资源
    最近更新 更多