让我们假设您需要跟踪采购订单项目交付在给定时间段内的变化情况,并且由于某种原因,此交付可能会遭受逆转。比你有一个表,至少有这些字段来保存你需要的数据: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之间的差异?
答案 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一起发生,因此您具有每条记录的最终状态。