计算一段时间内的最大值

时间:2020-03-02 11:10:45

标签: sql sql-server max

所以我在MS SQL Server上有三个表:

  • 储备金(ReserveID,ProjectID,TypeID,DateCreated,当前(二进制),金额)
  • 付款(付款ID,ProjectID,TypeID,创建日期,状态,金额)
  • 链接(LinkID,ReserveID,PaymentID)

类型将付款/储备金分为建筑材料,固定装置,人工成本,专业服务等

因此,当项目开始时,将根据预期成本设置一系列准备金。

您可能最初估计材料的成本为5,000美元,但是在进行了一些查询之后,您意识到材料的成本更像是10,000美元,在这种情况下,设置了10,000美元的新准备金,并且原始项目的表格设置为0

当发票进入并被支付时,它将进入付款表,储备金和付款之间的链接被输入到第三张表中。当在前端向用户显示付款时,将从准备金中扣除付款,但是在后端,未更改准备金表。例如,如果有$ 10,000的物料储备金和$ 2,500的物料发票已支付,则后端仍将有10,000储备金和2.5k付款,但前端将显示7.5k储备金,2.5k付款和共10,000。

如果某笔付款超出某类型的预留金额,那么前端将显示0预留,12,000笔付款和12,000笔总额。 (其他任何类型的储备金都将保持不变-例如,如果材料超出预算5k,则不会减少人工储备。)

如果在付款后更改了储备金(这导致“储备金”表中出现新行),则前端将停止从中扣除先前的付款。因此,在前面的示例中,前端显示7.5k储备金,2.5k付款和10k总数。如果用户然后将储备金更改为10k,则前端将显示10k储备金,2.5k付款和12.5k付款。

做事方式很差,但是我不能改变前端。

所以我需要做的是在任何时间点计算每个项目的最大总计。在理想情况下,这将是当前位置,但是过去可能会高估事物,然后在发现可以修复而不是替换的东西时减少储备。

我完全不知道如何执行此操作,更不用说以有效的方式运行相当大的数据集了。

非常感谢您的帮助。

样本数据

保留

ReserveID ProjectID TypeID  DateCreated Current Amount

23  64  4   03/01/2020  0   5,000.00 
24  65  3   03/01/2020  1   1,000.00 
25  64  4   05/01/2020  1   10,000.00 
26  64  1   08/01/2020  1   500.00 
27  66  1   09/01/2020  1   750.00 
28  64  3   10/01/2020  1   250.00 
29  68  3   10/01/2020  0   20,000.00 
30  68  3   11/01/2020  1   5,000

付款

PaymentID   ProjectID   TypeID  DateCreated Status  Amount

87  64  4   08/01/2020  Declined    10,000.00 
88  64  8   09/01/2020  Approved    1,000.00 
89  71  2   10/01/2020  Approved    5,000.00 
90  66  1   12/01/2020  Approved    700.00 

链接

LinksID ReserveID   PaymentID

21  25  87
22  25  88
23  27  90

所需的输出

ProjectID   MaxPotentialCost

64   11,750.00 
65   1,000.00 
66   750.00 
68   20,000.00 
71   5,000.00 

1 个答案:

答案 0 :(得分:0)

虽然我对您想要的东西还不是很清楚(该示例并不十分稳健或完整)我可以给您一个至少(希望如此)的有效示例涵盖了您似乎想要的方法。

(我将整理自己的数据,以更清楚地说明我的意思...)

3   2      1    110       90
4   3      1    120       90


第一件事似乎是在单个时间序列数据集中而不是在两个时间序列中获得所有数据。然后,到目前为止要有一个连续的付款总数,而不是各个金额。这样一来,每个ProjectID TypeID EffectiveDate Reserve 64 4 01/01/2020 1,000 64 4 07/01/2020 5,000 64 4 11/01/2020 1,000 64 5 12/01/2020 1,000 ProjectID TypeID EffectiveDate Payment 64 4 03/01/2020 1,000 64 4 05/01/2020 1,000 64 4 09/01/2020 2,000 64 5 10/01/2020 3,000 的曝光量(您所指的“总数”)就更容易计算。

(ProjectId,TypeID)

示例SQL:

PID,TID   EffectiveDate   Reserve   Payment   NewSpent   OldSpent   Exposure

64,4      01/01/2020        1,000         0         0         0     1,000   -- Reserve Added
64,4      03/01/2020        1,000     1,000     1,000         0     1,000   -- Payment Made, so newSpent increases
64,4      05/01/2020        1,000     1,000     2,000         0     2,000   -- Payment Made, so newSpent increases
64,4      07/01/2020        5,000         0         0     2,000     7,000   -- Reserve Revised, newSpent is added to OldSpent and then resets to zero 
64,4      09/01/2020        5,000     2,000     2,000     2,000     7,000   -- Payment Made, so newSpent increases
64,4      11/01/2020        1,000         0         0     4,000     5,000   -- Reserve Revised, newSpent is added to OldSpent and then resets to zero 

64,5      10/01/2020            0     3,000     3,000         0     3,000   -- Payment Made, so newSpent increases
64,5      12/01/2020        1,000         0         0     3,000     4,000   -- Reserve Revised, newSpent is added to OldSpent and then resets to zero 


这时,我将其全部折叠到“曝光”已改变的程度,因为这将使交错多个类型变得更加简单。

WITH
  combined AS
(
  SELECT
    payments.ProjectID,
    payments.TypeID,
    links.ReserveID,
    payments.DateCreated,
    COALESCE(reserve.Amount, 0)   AS reserve,
    payments.Amount               AS spent
  FROM
    payments
  LEFT JOIN
    links
      ON payments.PaymentID = links.PaymentID
  LEFT JOIN
    reserve
      ON reserve.ReserveID  = links.ReserveID        
  WHERE
    payments.status = 'Approved'

  UNION ALL

  SELECT
    reserve.ProjectID,
    reserve.TypeID,
    reserve.ReserveID,
    reserve.Amount,
    0
  FROM
    reserve
)
,
  runningTotal AS
(
  SELECT
    ProjectID,
    TypeID,
    DateCreated,
    reserve,
    SUM(spent)
      OVER (PARTITION BY ProjectID, TypeID, ReserveID
                ORDER BY DateCreated
           )
             AS spentReserve,
    SUM(spent)
      OVER (PARTITION BY ProjectID, TypeID
                ORDER BY DateCreated
           )
             AS spentProjectType
  FROM
    combined
)
,
  exposure AS
(
  SELECT
    ProjectID,
    TypeID,
    DateCreated,
    reserve,
    spentReserve                      AS spentNew,
    spentProjectType - spentReserve   AS spentOld,
    CASE WHEN
      spentReserve > reserve  -- If new spending exceeds the current reserve
    THEN                      -- The the exposure equals total spending to date
      spentProjectType        -- Otherwise it's the old spent value, plus the reserve
    ELSE
      spentProjectType - spentReserve + reserve
    END
                                      AS exposure
  FROM
    runningTotal
)

示例SQL:

PID,TID   EffectiveDate   Exposure   Delta

64,4      01/01/2020      1,000      1,000   -- Reserve Added
64,4      03/01/2020      1,000          0   -- Payment Made
64,4      05/01/2020      2,000      1,000   -- Payment Made
64,4      07/01/2020      7,000      5,000   -- Reserve Revised
64,4      09/01/2020      7,000          0   -- Payment Made
64,4      11/01/2020      5,000     -2,000   -- Reserve Revised

64,5      10/01/2020      3,000      3,000   -- Payment Made
64,5      12/01/2020      4,000      1,000   -- Reserve Revised


然后可以按时间顺序交错多个类型,并在整个项目中累加DeltaExposure值...

,
  deltaExposure AS
(
  SELECT
    exposure.*,
    exposure.exposure
    -
    LAG(exposure.exposure, 0)
      OVER (PARTITION BY exposure.ProjectID, exposure.TypeID
                ORDER BY exposure.DateCreated
           )
             AS deltaExposure
  FROM
    exposure
)

示例SQL:

PID,TID   EffectiveDate   Delta   ProjectExposure

64,4      01/01/2020      1,000      1,000   -- Reserve Added
64,4      03/01/2020          0      1,000   -- Payment Made
64,4      05/01/2020      1,000      2,000   -- Payment Made
64,4      07/01/2020      5,000      7,000   -- Reserve Revised
64,4      09/01/2020          0      7,000   -- Payment Made
64,5      10/01/2020      3,000     10,000   -- Payment Made
64,4      11/01/2020     -2,000      8,000   -- Reserve Revised
64,5      12/01/2020      1,000      9,000   -- Reserve Revised


显示需要每天计算的示例:

想象一个由Exp1和Exp2两部分组成的项目。在每个活动日期(每次付款或准备金修订)计算出风险之后,我们将获得以下“ DeltaExposure”值。

,
  projectExposure AS
(
  SELECT
    deltaExposure.*,
    SUM(deltaExposure.exposure)
      OVER (PARTITION BY deltaExposure.ProjectID
                ORDER BY deltaExposure.DateCreated
           )
             AS projectExposure
  FROM
    deltaExposure
)
SELECT
  ProjectID,
  MAX(ProjectExposure)   AS MaxProjectExposure
FROM
  projectExposure
GROUP BY
  ProjectID

最高风险暴露于Exp1上的第二次付款之日。中间支付三;如果不考虑其他所有时间序列,就无法知道Exp1的哪些付款日期是高峰暴露的候选者。