2014-10-20 160 views
0

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

OBS:插入顺序并不总是服从,这就是为什么我搞砸了标识的

 
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年10月2日至2014年10月14日交付。那么,从2014年10月1日到2013年10月13日,采购订单4500000000件10的交货量为55件,从2014年10月13日到2014年10月15日,这件商品的交货量为5件,因为它遭受了逆转,所以有-50的负变化。请注意,在这种情况下,您选择的时间段在两条记录的DateFrom和DateTo之间,但如果您选择了2014年10月1日至2014年10月18日,该怎么办?在这种情况下,您选择的时间段包含记录的DateFrom和DateTo日期。如何构建一个查询来计算给定时间段内的QtyDelivered之间的差异?

回答

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> = @DateFrom AND DateTo < = @DateTo)保证查询返回所选期间所涵盖的所有记录。 OR部分保证,所选记录中的日期在记录的日期和日期之间的所有记录都将被返回。但需要排除To date等于所选期间的第一个日期并且From Date等于所选期间的最后日期的记录,因此OR部分内的AND部分将保证(DateTo < > @DateFrom和DateFrom <> @DateTo)。连接条件ON TblId.MaxId = Table.Id使得连接发生在关于满足所选周期的每条记录的最后一个Id中,因此您具有每条记录的最终状态。