您正在跟踪事件的发生。事件(焊接)在某个时间开始并在某个时间结束。像这样对事件实体进行建模可能很诱人:
StationID StartTime StopTime
每个焊接站都有一个唯一的标识符。一些示例数据可能如下所示:
17 08:00:00 09:00:00 17 09:00:00 10:00:00
为简单起见,我将时间设置为较大的值(每个1小时)并删除日期值。这告诉您#17焊接站在上午8点开始焊接,并在上午9点结束,此时第二次焊接开始于上午10点结束。
这看起来很简单。但请注意,第一个条目的StopTime与第二个条目的StartTime匹配。当然可以,一个焊接的结束表示下一个焊缝的开始。这就是系统的设计方式。
但是这会设置我称之为Row Spanning Dependency反模式:其中一行的一个字段的值必须与另一行中另一个字段的值同步。
这可能会产生许多问题。例如,如果第二个条目的StartTime显示'09:15:00'怎么办?现在我们在第一次焊接结束和下一次焊接开始之间有15分钟的间隙。系统不允许间隙 - 每个焊缝的末端也开始下一个焊缝。应该如何解释这个差距。第一行的StopTime是错误的吗?第二行的StartTime是错误的吗?都错了吗?或者它们之间是否有另一行被删除?没有办法分辨哪个是正确的解释。
如果第二个条目的StartTime显示'08:45'怎么办?这是一个重叠,其中第二个循环的开始假设在第一个循环结束之前开始。同样,我们无法知道哪一行包含错误数据。
行跨越依赖性允许间隙和重叠,数据中不允许这两者。需要大量的数据库和应用程序代码来防止这种情况发生,并且当它确实发生时(确实会这样),没有办法确定哪些数据是正确的,哪些是错误的 - 不是从数据库中,即。
一个简单的解决方案是完全取消StopTime字段:
StationID StartTime 17 08:00:00 17 09:00:00
每个条目都表示焊接的开始。焊缝的末端由下一个焊缝的开始表示。这简化了数据模型,使得不可能有间隙或重叠,并且更精确地匹配我们正在建模的系统。
但我们需要两排数据来确定焊缝的长度。
select w1.StartTime, w2.StartTime as StopTime from Welds w1 join Welds w2 on w2.StationID = w1.StationID and w2.StartTime =( select Max( StartTime ) from Welds where StationID = w2.StationID and StartTime < w2.StartTime );
这似乎是一个更复杂的查询,如果开始和停止时间在同一行 - 而且,它是 - 但想到所有检查代码不再需要编写,并在每个DML执行操作。由于StationID和StartTime的组合将是明显的PK,因此查询将仅使用索引数据。
还有一个建议。当天的第一次焊接或休息后(如午餐)以及当天的最后一次焊接或休息前的焊接情况如何?我们必须努力不将休息时间作为循环时间。我们可以包含智能来检测查询中的这种情况,但这会进一步增加复杂性。
另一种方法是在记录中包含状态值。
StationID StartTime Status 17 08:00:00 C 17 09:00:00 C 17 10:00:00 C 17 11:00:00 C 17 12:00:00 B 17 13:00:00 C 17 14:00:00 C 17 15:00:00 C 17 16:00:00 C 17 17:00:00 B
所以前几个条目代表一个周期的开始,而中午和下午5点的条目代表一个休息的开始。现在我们只需要追加这一行
where w1.Status = 'C'
到上面的查询结束。因此,'B'条目提供前一循环的结束时间但不开始另一循环。