什么是最有效编辑“时间表”的好算法?

时间:2008-10-05 17:07:21

标签: database algorithm diff

这适用于小型调度应用。我需要一种算法来有效地比较两个“时间表”,找到差异,并仅更新已更改的数据行,以及将此表作为外键的另一个表中的条目。这是一个很大的问题,所以我马上就说我正在寻找一般建议特定解决方案

编辑:正如所建议的那样,我已经大大缩短了这个问题。

在一个表中,我将资源与使用它们的时间段相关联。

我还有第二个表(表B),它使用表A中的ID作为外键。

表A中对应于表B的条目将具有包含来自表B的时间跨度的时间跨度。并非表A中的所有条目都具有表B中的条目。 / p>

我正在为用户提供一个界面,用于编辑表A中的资源调度。它们基本上为表A提供了一组新的数据,我需要将其视为来自版本的 diff DB。

如果他们从表A中完全删除表A中的对象,我也希望从表B中删除该条目。

所以,考虑到以下3组:

  • 表A中的原始对象(来自数据库)
  • 表B中的原始对象(来自数据库)
  • 表A中已编辑的对象集(来自用户,因此没有唯一ID)

我需要一种算法:

  • 如果不需要对这些对象进行任何更改,则表A和表B中的行保持不变。
  • 根据需要向表A添加行。
  • 根据需要从表A和表B中删除行。
  • 根据需要修改表A和表B中的行。

只需将对象排序到我可以应用适当数据库操作的安排中,这对解决方案来说已经足够了。

同样,请按照具体通常进行回答,我正在寻求建议,但如果某人有完整的算法可以让我的一天。 :)

编辑:为了回应lassvek,我提供了一些额外的细节:

表B的项目始终完全包含在表A项目中,而不仅仅是重叠。

重要的是,表B的项目是量化的,因此它们应该完全落入或完全落在外面。如果没有发生这种情况,那么我有一个数据完整性错误,我必须单独处理。

例如(使用速记):

Table A
ID Resource    Start         End
01 Resource A  10/6 7:00AM   10/6 11:00AM
02 Resource A  10/6 1:00PM   10/6 3:00PM

Table B
ID Table_A_ID  Start         End
01 02          10/6 1:00PM   10/6 2:00PM

所以我想要以下行为:

  • 如果我从表A中删除ID 02,或将其缩短到下午2:00 - 3:00,我应该从表B中删除ID 01。
  • 如果我将表A ID 01扩展到下午1:00结束,这两个条目应合并为一行,表B ID 01现在应指向表A ID 01
  • 如果我从表A ID 01中删除8:00 AM-10:00AM,该条目应分为两个条目:一个用于7:00 AM-8:00AM,一个新条目(ID 03)用于10:00 AM -11:00AM

5 个答案:

答案 0 :(得分:7)

我已经广泛地使用了句号,但我担心我不完全理解表A和B如何协同工作,也许这是我不理解的 subsume 这个词。

你能举出一些你想做的具体例子吗?

你的意思是表A中记录的时间跨度包含表B中的完全时间跨度,就像这样?

|---------------- A -------------------|
    |--- B ----|      |--- B ---|

或与?

重叠
    |---------------- A -------------------|
|--- B ----|                        |--- B ---|

或相反的方式,B中的时间跨度包含/与A?

重叠

让我们说它是第一个,其中B中的时间跨度与表A中的链接时间跨度相同。

这是否意味着:

* A removed A-timespan removes all the linked timespans from B
* An added A-timespan, what about this?
* A shortened A-timespan removes all the linked timespans from B that now falls outside A
* A lenghtened A-timespan, will this include all matching B-timespans now inside?

以下是一个例子:

|-------------- A1 --------------|    |-------- A2 --------------|
  |---- B1 ----|  |----- B2 ---|       |---- B3 ----|  |-- B4 --|

然后你加长A1并缩短并移动A2,以便:

|-------------- A1 ---------------------------------|  |--- A2 --|
  |---- B1 ----|  |----- B2 ---|       |---- B3 ----|  |-- B4 --|

这意味着你想修改这样的数据:

1. Lengthen (update) A1
2. Shorten and move (update) A2
3. Re-link (update) B3 from A2 to A1 instead

这个修改怎么样,A1被加长了,但不足以完全包含B3,A2以同样的方式移动/缩短:

|-------------- A1 -----------------------------|      |--- A2 --|
  |---- B1 ----|  |----- B2 ---|       |---- B3 ----|  |-- B4 --|

由于B3现在不完全在A1或A2范围内,请将其删除?

我需要一些具体的例子来说明你想做什么。


修改更多问题

好的,怎么样:

|------------------ A -----------------------|
  |------- B1 -------|  |------- B2 ------|
                           |---|                   <-- I want to remove this from A

这个怎么样?

或者:

|------------------ A1 ----|   |---- A2 -----|
  |------- B1 -------|  |B3|   |--- B2 ---|

或:

|------------------ A1 ----|   |---- A2 -----|
  |------- B1 -------|

总结我到目前为止如何看待问题:

  • 您希望能够在A上执行以下操作
    • 缩短
    • 加长
    • 当它们相邻时组合,将两个或多个组合成一个
    • 通过删除一段时间在其中打孔,然后拆分它
  • 在上述更新后仍包含在A中的B,必要时重新链接
  • 包含的B,但现在完全在外面,删除它们
  • 包含的B,但现在部分在外面,编辑:删除这些,参考数据完整性
  • 对于上述所有操作,执行必要的最少工作以使数据与操作保持一致(而不是仅删除所有内容并重新插入)

我将在C#中实施一个可能在我下班回家时工作的实现,今晚我会再回来。


编辑以下是对算法的抨击。

  1. 首先优化新列表(即组合相邻时段等)
  2. 以下列方式将此列表与数据库中的主时段“合并”:
    1. 跟踪两个列表中的位置(即新的和现有的)
    2. 如果当前新期间完全在当前现有期间之前,请添加,然后转到下一个新期间
    3. 如果当前新期间完全在当前现有期间之后,则删除现有期间及其所有子期间,然后移至下一个现有期间
    4. 如果两者重叠,则以下列方式调整当前现有周期等于新周期,然后继续下一个新的和现有的周期
      1. 如果新期间在现有期间之前开始,只需移动开始
      2. 如果新时段在现有时段之后开始,请检查是否有任何子时段处于差异时段,并记住它们,然后移动开始
      3. 对另一端做同样的事情
  3. 对于您“记住”的任何时段,查看是否需要重新链接或删除
  4. 您应该创建大量的单元测试,并确保涵盖所有修改组合。

答案 1 :(得分:2)

我建议你将问题分成两个单独的问题: 第一个应该是这样的:“当将一个计划原子表示为具有开始时间和结束时间的资源时,我如何推理资源调度?”在这里,ADept建议使用区间代数似乎是合适的。请参阅The Wikipedia entry 'Interval Graph'The SUNY algorithm repository entry on scheduling。 第二个问题是数据库问题:“给定一个算法来调度间隔并指示两个间隔是否重叠或一个是否包含在另一个间隔中,如何使用此信息来管理给定模式中的数据库?”我相信一旦调度算法到位,数据库问题将更容易解决。 HTH, 尤瓦

答案 2 :(得分:1)

你发帖几乎是在“太长;没读”的类别 - 缩短它可能会给你更多的反馈。

无论如何,关于主题:您可以尝试查看名为"Interval Algebra"

的内容

答案 3 :(得分:1)

据我了解,您的用户只能直接影响表A.假设您使用C#编程,您可以使用简单的ADO.Net DataSet来管理对表A的修改.TableAdapter知道单独保留未触动的行并且适当地处理新的,修改的和删除的行。

此外,您应该定义级联删除,以便自动删除表B中的相应对象。

唯一不以这种方式处理的情况是,如果表A中的时间跨度缩短了s.t.它不再包含表B中的相应记录。您只需在更新存储过程中检查该情况,或者在表A上定义更新触发器。

答案 4 :(得分:1)

在我看来,任何算法都需要通过NewA,匹配ResourceID,StartTime和EndTime,并跟踪OldA中的哪些元素被击中。然后你有两组不匹配的数据,UnmatchedNewA和UnmatchedOldA。

我能想到的最简单的方法是基本上重新开始: 将所有UnmatchedNewA写入DB,将UnmatchedOldA中的B元素转移到新A键(刚生成),尽可能删除。然后清掉所有UnmatchedOldA。

如果有很多变化,这肯定不是一种有效的方法。但是,如果数据的大小不是很大,我更喜欢简单到聪明的优化。


在没有更多背景的情况下,不可能知道这个最终建议是否有意义,但是如果你没有这样想的话,这是不可能的:

您是否可以使用事件监听器或类似的东西来更新数据模型而不是需要进行更改,而不是来回传递整个A集合?这样,被更改的对象将能够确定动态需要哪些DB操作。