查询以显示事务表中的已用信用

时间:2018-04-24 18:06:26

标签: sql sql-server sql-server-2012

我正在使用一个包含信用交易的表格,我想显示在进行销售时花了多少信用。

在表格中:

  • Credits由实体使用唯一实体代码添加(记录在GivenByUserCode列中)
  • 信用额度总是有这样的代码。
  • 花费的积分总是会有负值。
  • 花费的信用额度不会包含实体代码(GivenByUserCode的值为null)。

如果用户在2018-01-02进行购买,则使用上述数据作为示例,报告应显示源自BM01的所有这些信用。增加的复杂性是购买可以分为多个添加,请参阅2018-02-03上的购买,该购买分为3个添加项。

我认为该解决方案与使用cteover有关,但我没有使用这些的经验。我确实在SqlServerCentral上找到了类似(不相同)的问题。

非常感谢任何帮助/指导。

输入和DDL

DECLARE @CreditLogs TABLE(CreditLogId int not null identity(1,1), Credits INT NOT NULL, OccurredOn DATETIME2(7) NOT NULL, GivenByUserCode VARCHAR(100) NULL)

INSERT INTO @CreditLogs (Credits, OccurredOn, GivenByUserCode) VALUES
  (10,  '2018-01-01', 'BM01')
, (10,  '2018-01-01', 'BM01')
, (-10, '2018-01-02', NULL)
, (-5,  '2018-01-04', NULL)
, (5,   '2018-02-01', 'SP99')
, (40,  '2018-02-02', 'BM02')
, (-40, '2018-02-03', NULL)
, (-4,  '2018-03-05', NULL)

以表格形式输入

CreditLogId | Credits | OccurredOn | GivenByUserCode
------------+---------+------------+----------------
          1 |      10 | 2018-01-01 |            BM01
          2 |      10 | 2018-01-01 |            BM01
          3 |     -10 | 2018-01-02 |            NULL
          4 |      -5 | 2018-01-04 |            NULL
          5 |       5 | 2018-02-01 |            SP99
          6 |      40 | 2018-02-02 |            BM02
          7 |     -40 | 2018-02-03 |            NULL
          8 |      -4 | 2018-03-05 |            NULL

预期输出

SELECT *
FROM (VALUES
     (3, '2018-01-02', 10, 'BM01')
    ,(4, '2018-01-04', 5, 'BM01')
    ,(7, '2018-02-03', 5, 'BM01')
    ,(7, '2018-02-03', 5, 'SP99')
    ,(7, '2018-02-03', 30, 'BM02')
    ,(8, '2018-03-05', 4, 'BM02')
) expectedOut (CreditLogId, OccurredOn, Credits, GivenByUserCode)

生成输出

CreditLogId | Occurred on | Credits | GivenByUserCode
------------+-------------+---------+----------------
          3 |  2018-01-02 |      10 |            BM01
          4 |  2018-01-04 |       5 |            BM01
          7 |  2018-02-03 |       5 |            BM01
          7 |  2018-02-03 |       5 |            SP99
          7 |  2018-02-03 |      30 |            BM02
          8 |  2018-03-05 |       4 |            BM02

到目前为止的代码

它并不多,我不确定从这里开始。

WITH totals AS (
    SELECT CreditLogId, OccurredOn, credits, sum(credits) OVER(ORDER BY OccurredOn) AS TotalSpent
    FROM @CreditLogs
    WHERE Credits < 0
)
SELECT *
FROM totals

补充说明

预期产出是针对这些信用来自的每个用过的信用额度。积分以先进先出(FIFO)为基础。这里对样本输出中的每个值进行了解释,希望这可以明确所需的输出。

  • 对于10个学分(学分日志ID 3)的支出可以追溯到信用记录id 1的增加
  • 对于5个学分(学分日志ID 4)的花费可以追溯到学分日志ID 2的添加(因为学分日志ID 1是&#34;用完了#34;)
  • 对于信用记录中的40个信用额度,ID 7可以追溯到
    • 从信用记录ID 2,5个学分添加的剩余部分
    • 信用记录ID 5(添加5)
    • 信用记录ID 6(剩余40个,另外10个)
  • 对于信用记录8中4个信用点的消费,使用信用记录ID 6的余额

请注意,剩余6个学分的总余额,余额不必为零,但永远不会为负,因为用户只能花费他们所拥有的。

2 个答案:

答案 0 :(得分:10)

试试这个:

WITH Credits_added AS (
    SELECT CreditLogId, OccurredOn, credits
    , SUM(credits) OVER (ORDER BY CreditLogId) - credits AS b --before
    , SUM(credits) OVER (ORDER BY CreditLogId) AS a --after
    , GivenByUserCode
    FROM @CreditLogs
    WHERE Credits > 0)
, Credits_spent AS (
    SELECT CreditLogId, OccurredOn, credits
    , SUM(credits) OVER (ORDER BY CreditLogId) * -1 + credits AS b
    , SUM(credits) OVER (ORDER BY CreditLogId) * -1 AS a
    FROM @CreditLogs
    WHERE Credits < 0)
SELECT s.CreditLogId, s.OccurredOn
, CASE WHEN a.a > s.a THEN s.a ELSE a.a END - CASE WHEN a.b > s.b THEN a.b ELSE s.b END AS Credits 
, a.GivenByUserCode
FROM Credits_added AS a
INNER JOIN Credits_spent AS s ON a.a > s.b AND s.a > a.b

答案 1 :(得分:6)

因为你提到每年会有4到5百万条记录,即使这可以通过查询来完成,也会是一个缓慢的查询。

我建议使用另一个包含creditSpent

(PurchaseCreditLogId , additionCreditLogId, Amount)表格

在插入购买时,查找所有记录,计算每个记录应减少的金额并将该信息存储在该表中

然后,当您运行报告时,您可以对此表进行简单查询