1

我有一张桌子:

INSTRUCTIONS:
  RecipeID
  Step
  ...

RecipeID由另一个系统生成。不需要有明确的外键关系RecipeID。当我为特定配方插入步骤Instructions时,我想Step增加。向新配方添加步骤时,step应返回 0,如下所示:

RecipeID | Step
---------------
    0    |  0
    0    |  1

RecipeID | Step
---------------
    0    |  0
    0    |  1
    0    |  2

RecipeID | Step
---------------
    0    |  0
    0    |  1
    0    |  2
    1    |  0

我将如何产生这种行为?

4

2 回答 2

2

不要这样做 你自己的问题表明这是一个糟糕的主意。你怎么能有一个部分密钥?根据定义,部分键不能是唯一的。

步骤中唯一需要的是订单,将它们显示(或使用 Row_number 查询它们)为 0 到 n 是微不足道的。

想想你必须做什么,插入你错过的步骤,或者交换它们......

RecipeStepID(作为代理主键)

RecipeID,StepNumber 作为索引

表的任何外键链接都使用代理键

然后重新订购只是在搞乱 StepNo

从来没有见过你试图不变成灾难的方法,而且我可以数出它在不脱手套的情况下没有作为灾难开始的次数。

于 2013-01-23T23:56:26.900 回答
0

免责声明:请参阅底部的注释。我不一定建议使用触发器。

您可以使用instead of触发器来更改step将插入的值:

Create Trigger Instructions_UpdateSet
  On [Instructions]
  Instead of Insert
AS
BEGIN
  insert instructions
  select
    i.recipe,
    coalesce(ii.maxstep, -1)
      + row_number() over (partition by i.recipe order by i.step),
    i.instruction
  from inserted i
  left join (select recipe, max(step) as maxstep from instructions group by recipe)
    ii on i.recipe = ii.recipe
END;

这应该无缝地处理单个或多个记录的插入。如果您确实在单个查询中插入多条记录,您可以提供一个step值来指示传入插入记录的顺序,它们将被适当地排序并重新编号以在现有记录之后按顺序跟随。

演示:http ://www.sqlfiddle.com/#!6/b13d5/1


在应用程序中使用触发器时需要注意的一些事项:

  • 很容易忘记触发器,因为它们隐藏得很好。确保记录它们,否则当他们插入的数据在数据库中不同时,下一个开发人员会感到困惑。
  • 如果您正在使用缓存层,请确保在插入记录后刷新缓存以获取由触发器引起的更改。
  • 一般来说,我建议避免触发业务逻辑。如果您正在寻找性能,最好使用存储过程,这对于意图和行为来说更加明显。触发器最适合透明操作,如数据验证、级联更新/删除、审计等。
于 2013-01-24T00:03:46.667 回答