计算给定一段时间的两行之间的差异

时间:2014-10-20 12:04:41

标签: sql

让我们假设您需要跟踪采购订单项目交付在给定时间段内的变化情况,并且由于某种原因,此交付可能会遭受逆转。比你有一个表,至少有这些字段来保存你需要的数据:PO,POItem,QtyDelivered,DateFrom,DateTo,显然你可能想要保存更多关于项目的数据,但我省略了字段以简化解释。 QtyDelivered字段保存累计交付金额,此字段从0到您的采购订单中请求的金额,因此如果您的PO有100个单位材料的请求,QtyDelivered会从0到100.但如果交货遭受逆转,这使得QtyDelivered遭受了减少。 DateFrom和DateTo保存QtyDelivered保持相同值的日期间隔。假设该表包含以下这些记录:

OBS:并不总是遵守插入顺序,这就是我搞砸Id的原因

 Id      PO     POItem      QtyDelivered       DateFrom       DateTo
  3  4500000000   10             39           15/10/2014    15/10/2014
  4  4500000000   10             60           15/10/2014    15/10/2014
  1  4500000000   10             55           01/10/2014    13/10/2014
  7  4500000001   10             40           16/10/2014    17/10/2014
  5  4500000001   10             5            14/10/2014    16/10/2014
  6  4500000001   10             36           16/10/2014    16/10/2014
  2  4500000000   10             5            13/10/2014    15/10/2014
  8  4500000001   10             2            17/10/2014    18/10/2014

现在假设您需要知道从2014年2月2日到2014年10月14日交付的给定材料的单位数量。那么,从2014年10月1日到2014年10月13日,采购订单4500000000项目10交付55个单位,从2014年10月13日到15/10/2014这个相同的项目交付5个单位,所以它由于遭遇逆转,因此-50的负变化。请注意,在这种情况下,您选择的时间段介于两个记录的DateFrom和DateTo之间,但是如果您选择了01/10/2014到18/10/2014,该怎么办?在这种情况下,您选择的时间段包括记录的DateFrom和DateTo日期。如何构建一个查询来计算给定时间段内QtyDelivered之间的差异?

1 个答案:

答案 0 :(得分:1)

SELECT
 Table.PO
,Table.POItem
,(SELECT QtyDelivered
  FROM Table
  WHERE Id = TblId.MaxId) - (SELECT QtyDelivered
                             FROM Table
                             WHERE Id = TblId.MinId) AS [Qty delivered]
FROM Table
INNER JOIN(SELECT
            MIN(Id) AS MinId
           ,MAX(Id) AS MaxId
           FROM Table
           WHERE
                (DateFrom >= @DateFrom AND DateTo <= @DateTo)
             OR 
                ((@DateFrom BETWEEN DateFrom AND DateTo 
                   OR @DateTo BETWEEN DateFrom AND DateTo
                 )
                 AND DateTo <> @DateFrom
                 AND DateFrom <> @DateTo
                ) 
            GROUP BY
             PO
            ,POItem) AS TblId
ON TblId.MaxId = Table.Id

请注意,内部联接子查询仅返回联接发生的MIN和MAX Id,仅使用所选报告周期内的记录进行过滤。它显着减少了要连接的记录数量,因为过滤是在连接之前完成的。计算字段是子查询,它使用内连接子查询返回的Id来查找第一个和最后一个记录来计算它们之间的差异。

在内连接子查询中,where子句有点复杂,但易于理解。注意,系统用户选择的时间段可以在记录的日期之间,也可以是记录的日期之间或之后的日期。因此,第一个条件(DateFrom&gt; = @DateFrom AND DateTo&lt; = @DateTo)保证查询返回所选时段所包含的所有记录。 OR部分保证所有记录中所选日期中的日期在记录的to和from日期之间的记录将被返回。但是,它需要排除To日期等于所选期间的第一个日期且From日期等于所选期间的最后日期的记录,因此OR部分内的AND部分将保证(DateTo&lt;&gt; @DateFrom和DateFrom&lt;&gt; @DateTo)。连接条件ON TblId.MaxId = Table.Id使得连接与关于满足所选时间段的每条记录的最后一个Id一起发生,因此您具有每条记录的最终状态。