【问题标题】:SQL Server Instead Of Insert trigger on View causes Cannot Insert NullSQL Server 而不是视图上的插入触发器导致无法插入 Null
【发布时间】:2014-11-18 09:28:07
【问题描述】:

我们在视图上有一个“Instead-Of-Insert”触发器,它将所有值从 INSERTED 虚拟表复制到另一个表。

列表中的一个字段对于目标表是不可为空的,并且指定了默认值。

我们遇到的是,一些应用程序代码正在发送一个插入命令,并且没有指定不可为空的字段 - 这(如果插入是针对实际表执行的)通常会导致 SQL Server 插入列的默认值价值。但是,触发器对所有字段都是显式的,因此触发器会尝试为该字段插入 null ......导致错误。

我不想要的是这样的代码......

INSERT INTO XXXX (col1, col2, col3) 
   SELECT 
      ISNULL(col1, 0), ISNULL(COL2, 0), ISNULL(COL3, 0) 
   FROM INSERTED

我不希望触发器需要知道每列的实际默认值应该是什么(从可维护性的角度来看)...

谁有更好的解决方案?

谢谢

【问题讨论】:

  • 您是否考虑过在基础表中使用默认值?
  • 这就是问题所在——我们确实有基础表的默认值。因此,当视图为该列发送 NULL 时,表上的默认值是什么并不重要,数据库不会允许 null,并且不会使用默认值,因为 View 触发器查询指定了显式 null
  • 我能想到的避免硬编码实际默认值的唯一方法是有一个丑陋的查询,从sys.default_constraints 中提取定义 - 你需要反复加入这个表,对于您想要获取其默认值的每一列,您必须依赖用于默认值的实际值很容易转换为所需的实际数据类型。该解决方案的复杂性和脆弱性使得在触发器中嵌入列默认值(对我而言)是更好的选择。
  • @Damien_The_Unbeliever 同意了。

标签: sql sql-server triggers


【解决方案1】:

我可以想到一种丑陋且低效的方法。这个想法是插入一个默认行,然后一次更新一个列,使用try/catch 忽略错误。

declare @Id int;
insert int XXX DEFAULT VALUES;
set @id = @@IDENTITY;

begin try
    update XXX set col1 = val1 where id = @id;
end try
begin catch
end catch;

begin try
    update XXX set col2 = val2 where id = @id;
end try
begin catch
end catch;

. . .

如果您必须在 100 列上执行此操作,那可能是个坏主意。如果您只有两三列导致问题,那么这可能会解决您的问题。

【讨论】:

  • 谢谢 Gordon - 我同意 - 它被一根丑陋的棍子打了。我认为任何“解决方案”都会受到同样的影响。看起来 SQL 没有内置任何东西来处理这个问题。
【解决方案2】:

当您的应用程序将 NULL 值发送到不可为空的列时,没有太多选项。特别是当您不想对 isnull 使用输入验证时。

在这种情况下,我们使用默认值。如果可能的话,你可以改变你的桌子:

ALTER TABLE xxxx ADD CONSTRAINT DF_col1 DEFAULT N'default' FOR col1;

【讨论】:

  • 您好,请注意我们确实有默认设置。程序代码将行插入到视图中。视图有一个将插入代理到表的触发器。该表为其不可为空的字段设置了默认值。因为视图指定了插入时的所有列,所以程序代码省略的任何列都不会导致插入默认值,而是 NULL.. 这会导致错误。
猜你喜欢
  • 2022-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多