【问题标题】:Forbid insert into table on certain conditions禁止在特定条件下插入表格
【发布时间】:2013-03-25 12:45:39
【问题描述】:

我有一个 SQL Server 2008 数据库。有三个端子连接到它(A、B、C)。数据库中有一个表SampleTable,它对任何终端活动作出反应。每次登录到此数据库的任何终端上都有一些活动时,新行将插入到SampleTable

我想将来自三个终端之一 (C) 的流量重定向到表 RealTable 而不是 SampleTable,但我必须在 DB 层执行此操作,因为将终端活动写入 DB 的服务位于黑盒中。

我已经有一些使用重定向逻辑在SampleTable 上工作的触发器,但问题是行仍在插入SampleTable

什么是最干净的解决方案。我确信删除插入触发器中的行是不好的,不好的,不好的。

请帮忙。

编辑:

我们目前的逻辑是这样的(这是伪代码):

ALTER TRIGGER DiffByTerminal
 ON SampleTable
AFTER INSERT
AS
DECLARE @ActionCode VARCHAR(3), 
    @ActionTime DATETIME,
    @TerminalId INT

  SELECT @ActionCode = ins.ActionCode, 
     @ActionTime = ins.ActionTime, 
     @TerminalId = ins.TerminalId
  FROM inserted ins

IF(@TerminalId = 'C')
BEGIN

    INSERT INTO RealTable 
    (   
         ...
    )
    VALUES
    (
         @ActionCode, 
         @ActionTime, 
         @TerminalId
    )
END

【问题讨论】:

  • 触发器是什么?最干净的可能是通过存储过程插入,这样你就有一个很好的抽象位置来添加额外的逻辑
  • 你现有的逻辑是什么?这听起来像是 INSTEAD OF 触发器的完美使用
  • 我们无法更改行插入的逻辑,因此它需要是触发器或类似触发器的东西。 @JNK 请查看我编辑的答案。
  • 这是不可能的。如果您在 SampleTable 中插入两行(例如INSERT ... SELECT something UNION ALL SELECT something else,则上述触发代码只会在 RealTable 中插入任意一行。
  • @nzic 仍然是一件非常危险的事情。明天有人可能会编写一个新方法,它不会盲目地遵守这种逐行要求(这也是低效的),当然你不能阻止任何人一开始就绕过你的应用程序并编写他们自己的广告——临时插入。

标签: sql database sql-server-2008 triggers insert-into


【解决方案1】:

为了在将行插入表之前“拦截”某些内容,您需要INSTEAD OF 触发器,而不是AFTER 触发器。因此,您可以删除现有触发器(其中还包括假设所有插入都是单行的有缺陷的逻辑)并创建此 INSTEAD OF 触发器:

DROP TRIGGER DiffByTerminal;
GO

CREATE TRIGGER dbo.DiffByTerminal
 ON dbo.SampleTable
INSTEAD OF INSERT
AS
BEGIN
  SET NOCOUNT ON;

  INSERT dbo.RealTable(...) SELECT ActionCode, ActionTime, TerminalID
    FROM inserted
    WHERE TerminalID = 'C';

  INSERT dbo.SampleTable(...) SELECT ActionCode, ActionTime, TerminalID
    FROM inserted
    WHERE TerminalID <> 'C';
END
GO

这将处理由 (a) 仅 C (b) 仅非 C 和 (c) 混合组成的单行插入和多行插入。

【讨论】:

  • 好的,请给我一些时间来测试一下,但是看看它似乎是一个完美的解决方案
  • 似乎一切正常。由于为该表(SampleTable)定义了一些其他触发器,我认为任何“AFTER INSERT 触发器”都会在该行实际插入到由“INSTEAD OF INSERT 触发器”过滤的 SampleTable 之后发生。你能确认一下吗?
  • 是的,AFTER 触发器在插入行后触发。当然,您可以通过回滚来撤消它,但这也会撤消 INSTEAD OF 触发器所做的任何其他事情。为什么需要多个触发器?
  • 老实说,我们使用多个触发器只是因为它们所代表的东西非常不同。在我们的终端上发生的活动可能会有很大差异,并会影响不同的桌子。这是糟糕的架构吗?
  • @nzic 这真的取决于。您还可以根据输入参数编写 15 个不同的存储过程,但您不必这样做。这完全取决于您喜欢维护一个对象还是一堆对象。
【解决方案2】:

对您来说最简单的解决方案之一是 INSTEAD OF 触发器。简单地说,它是在您决定的操作上“触发”并让您“覆盖”该操作的默认行为的触发器。

您可以使用 INSTEAD OF 触发器覆盖特定表/视图的 INSERT、DELETE 和 UPDATE 语句(您经常将它与组合来自不同表的数据的视图一起使用,并且您希望使视图可插入),您可以在其中把你的逻辑。在触发器内部,您可以在适当的时候再次调用 INSERT,并且您不必担心递归 - INSTEAD OF 触发器不会应用于触发器代码本身内部的语句。

享受吧。

【讨论】:

  • 对不起...不是问题而是回答
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-21
  • 1970-01-01
  • 2017-04-28
  • 2019-10-11
  • 1970-01-01
相关资源
最近更新 更多