T-SQL中FIFO利润的计算

T-SQL中FIFO利润的计算,sql,sql-server,tsql,Sql,Sql Server,Tsql,我需要一些关于单个查询的帮助或指针,这些查询可以根据FIFO(先进先出)原则在下面附带的数据集上为每个股票交易建立损益。应与SQL Server 2016+和Azure SQL兼容 示例数据如下所示: 股票名称 交易日期 档码 量 价格美元 总金额美元 股票ABC 2017-12-11 11:16:11.000 购买 2364,444444 0,114323 270,310382 斯托克斯 2017-12-11 11:16:11.000 购买 2364,444444 0,114323 270,3

我需要一些关于单个查询的帮助或指针,这些查询可以根据FIFO(先进先出)原则在下面附带的数据集上为每个股票交易建立损益。应与SQL Server 2016+和Azure SQL兼容

示例数据如下所示:

股票名称 交易日期 档码 量 价格美元 总金额美元 股票ABC 2017-12-11 11:16:11.000 购买 2364,444444 0,114323 270,310382 斯托克斯 2017-12-11 11:16:11.000 购买 2364,444444 0,114323 270,310382 股票ABC 2017-12-14 14:16:24.000 卖 1000 0,158849 158,849 斯托克斯 2017-12-14 14:16:24.000 卖 1000 0,158849 158,849 股票ABC 2017-12-14 19:38:46.000 卖 700 0,198934 139,2538 斯托克斯 2017-12-14 19:38:46.000 卖 700 0,198934 139,2538 股票ABC 2017-12-15 09:38:09.000 卖 664,4444444 0,207171 137,65362
谢谢你的反馈,让我做一些改变

SELECT Currency,TransactionDate,
SUM(CASE WHEN TranCode = 'SELL' THEN CostBasis * (-1) ELSE CostBasis END )OVER(PARTITION BY Currency ORDER BY TransactionDate ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS TOTAL
FROM #Stock
GROUP BY Currency, TransactionDate, CostBasis, TranCode
下面是一种简单的方法(排序),它使用一个名为
dbo.fnTally
的函数为每个项目或数量的“份额”生成一行。“购买”和“出售”都使用
CROSS-APPLY
dbo.fnTally(1,s.Quantity)来扩展每个数量项目的行。此外,两个
CTE
都分配了一个称为“trans”的顺序行编号。通过将“trans\rn”上的两个
CTE
,只需将价格相加即可计算出
FIFO
的盈利能力。像这样的

dbo.fnTally

CREATE FUNCTION [dbo].[fnTally]
/**********************************************************************************************************************
    Jeff Moden Script on SSC: https://www.sqlservercentral.com/scripts/create-a-tally-function-fntally
**********************************************************************************************************************/
        (@ZeroOrOne BIT, @MaxN BIGINT)
RETURNS TABLE WITH SCHEMABINDING AS 
 RETURN WITH
  H2(N) AS ( SELECT 1 
               FROM (VALUES
                     (1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    ,(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
                    )V(N))            --16^2 or 256 rows
, H4(N) AS (SELECT 1 FROM H2 a, H2 b) --16^4 or 65,536 rows
, H8(N) AS (SELECT 1 FROM H4 a, H4 b) --16^8 or 4,294,967,296 rows
            SELECT N = 0 WHERE @ZeroOrOne = 0 UNION ALL
            SELECT TOP(@MaxN)
                   N = ROW_NUMBER() OVER (ORDER BY N)
              FROM H8;

仅供参考,自2008年以来,您已经能够在
INSERT
语句中使用
VALUES
表结构;无需使用昂贵的
UNION
,也无需再使用较便宜的
UNION ALL
。此外,在
INSERT
语句中,数字列不应放在单引号中-这只会导致不必要的字符串转换,然后再回到相应的数值-只需使用
158.849作为成本基础
-无单引号!嗨,谢谢你的建议。但这并不能解决我需要的问题。请阅读“我需要一个计算,它计算每个交易的利润。例如,如果我以5的价格购买10支股票ABC,然后以6的价格购买10支,然后以9的价格出售所有15支股票,我需要计算利润,将购买价格考虑在内。”这意味着我需要看到每次出售的利润/亏损,根据第一次购买的价格,@BennyChristiansen您好,我已经更新了答案,请检查并告诉我是否还有其他问题。再次感谢你。再次感谢,但数字似乎不匹配。以“2017-12-14 19:38:00.000”中的“卖出”为例。以0.198934000000000000的价格出售700个数量,从2017-12-11 11 11:16:00.000以0.114323000000000的价格批量购买,在您的计算中给出负利润。这应该是正利润,因为700辆车的购买价格几乎是其销售价格的一半。:)我已经用了两天的时间在这上面,没有找到任何东西:好吧,那么把‘卖’改为‘买’怎么样。非常感谢。这正是我想要的。非常感谢!
;with 
buy_cte(Currency, TransactionDate, Price, trans_rn) as (
    select Currency, TransactionDate, Price,
           row_number() over (partition by Currency order by TransactionDate)
    from #Stock s
         cross apply dbo.fnTally(1, s.Quantity) fn
    where TranCode='BUY'),
sell_cte(Currency, TransactionDate, Price, trans_rn) as (
    select Currency, TransactionDate, Price,
           row_number() over (partition by Currency order by TransactionDate)
    from #Stock s
         cross apply dbo.fnTally(1, s.Quantity) fn
    where TranCode='SELL')
select s.Currency, s.TransactionDate, 
       cast(sum(b.price) as decimal(14,2)) buy_sum, 
       cast(sum(s.price) as decimal(14,2)) sell_sum, 
       cast(sum(s.price-b.price) as decimal(14,2)) profit_sum, 
       count(*) q_sold
from buy_cte b
     join sell_cte s on b.Currency=s.Currency
                    and b.trans_rn=s.trans_rn
                    and b.TransactionDate<s.TransactionDate
group by s.Currency, s.TransactionDate
order by TransactionDate;
Currency    TransactionDate         buy_sum sell_sum    profit_sum  q_sold
StockABC    2017-12-14 14:16:00.000 114.32  158.85      44.53       1000
StockABC    2017-12-14 19:38:00.000 80.03   139.25      59.23       700
StockABC    2017-12-15 09:38:00.000 75.91   137.56      61.65       664
StockABC    2017-12-21 21:02:00.000 163.50  158.24      -5.26       334
StockABC    2017-12-26 10:45:00.000 195.32  174.92      -20.40      399
StockABC    2017-12-30 11:34:00.000 244.76  316.88      72.12       500
StockABC    2018-01-03 17:45:00.000 9.79    21.13       11.34       20
StockABC    2018-03-21 15:42:00.000 633.45  319.92      -313.53     1472
StockABC    2018-04-16 07:53:00.000 73.92   105.97      32.05       450
StockABC    2018-04-24 20:15:00.000 75.44   136.96      61.52       460
StockABC    2018-07-22 17:08:00.000 66.53   87.15       20.62       500
StockABC    2018-08-05 17:34:00.000 133.00  127.40      -5.60       1000