【问题标题】:Changing the column from NULL to NOT NULL when some data is inserted插入某些数据时将列从 NULL 更改为 NOT NULL
【发布时间】:2026-01-10 02:45:01
【问题描述】:

我有一个专栏Col1 nvarchar(10) null

我必须编写一个检查约束或触发器(我认为检查约束不可能),当且仅当某些数据输入到字段中时,Col1 从 null 更改为 not null,或者更确切地说,在字段中输入一些非空值后,它将拒绝该列获取空值。

这是因为应用程序首先检查该字段是否为空,如果是,则为其添加一些值。之后该字段就不能改回null了。

现在我有以下内容:

  create trigger [TRG_Col1_NotNull] on my.Table
      instead of update
          as
              begin
                  if exists (
                      select * from inserted as i
                      where i.Col1 is null
                      )
                  raiserror ('You can not change the value of Col1 to null', 16, 1)
                  rollback transaction
              end

这是最好的(甚至是正确的)方法,还是有更好更简单的解决方案(也许以某种方式检查约束)?

好的!更新! 应用程序是这样工作的: 它首先以PK column, Col1, Col2, Col31, null, text, date 将数据保存到表中。之后,它检查Col1 是否为空并读取PK column 并将其值写入Col1。所以我得到了1, 1, text, data

【问题讨论】:

  • 你好。我认为可能存在某种概念错误:当几条记录具有 Col1 NULL 并且然后使用 Col1 插入一些新记录时会发生什么情况!= NULL?在这种情况下,现有的 NULL 值将不符合您的期望……它们应该自动更新吗?或者您只是想阻止插入新的 NULL 值?此外:您是否可以提供一些示例数据/表结构/ ...?
  • 您需要编写 ALTER TABLE 语句。 *.com/questions/689746/…
  • 该列不能有空值。应用程序总是提供一些价值。所以他们不是概念错误。我只是想防止插入空值,但在插入非空值之后。 @Amit:默认情况下,我在表中不能有非空约束,因为应用程序首先检查这是否为空字段,然后才发送一个要插入该字段的值。之后我需要防止输入回空值。

标签: sql sql-server sql-server-2016


【解决方案1】:

这可以满足您的要求(我知道:它是在 UPDATE 之后,所以实际上,您会更改两次值,但我不会使用 AFTER/INSTEAD:如果应该更新其他值怎么办?)。

CREATE TABLE TES1 (ID INT, COL1 VARCHAR(10));
INSERT INTO TES1 VALUES (1,'X');
INSERT INTO TES1 VALUES (2,NULL);


CREATE TRIGGER TRG1 ON TES1
 AFTER UPDATE
 AS
 BEGIN
     UPDATE A SET COL1=CASE WHEN d.COL1 IS NULL THEN i.COL1 ELSE d.COL1 END
     FROM TES1 A
     INNER JOIN DELETED d ON  A.ID = d.ID
     INNER JOIN INSERTED i ON A.ID = i.ID;
  END

样本数据

    UPDATE TES1 SET COL1 = NULL WHERE ID=1;
SELECT * FROM TES1;
    UPDATE TES1 SET COL1 = 'A' WHERE ID=1;
SELECT * FROM TES1;
    UPDATE TES1 SET COL1 = 'B' WHERE ID=2;
SELECT * FROM TES1;
    UPDATE TES1 SET COL1 = 'C' WHERE ID=2;
SELECT * FROM TES1;

【讨论】:

  • 这是否允许应用程序首次将空值写入 col1?如果我知道我是否有空值并将其删除(d.col1 为空),然后写入空(i.col1 为空),那么它会写入空(i.col1),因为'当 d.col1 为空时,我.col1'?我说的对吗?
  • 不,“deleted”是MSSQL触发器在更新前指示包含列值的记录的常规方式,而“inserted”是新值。你可以在微软网站上找到很多信息,寻找触发器。无论如何,可以在我的答案中使用脚本进行所有您想要的测试并验证结果。
  • 我稍微修改了你的答案,它就成功了。谢谢。
【解决方案2】:

可以创建一个仅适用于新值的CHECK 约束。

ALTER TABLE [dbo].[Test] WITH NOCHECK ADD CONSTRAINT [CK_Test] CHECK (([Col1] IS NOT NULL))
GO

ALTER TABLE [dbo].[Test] CHECK CONSTRAINT [CK_Test]
GO

WITH NOCHECK 选项表示即使表有NULL 值,也会成功创建约束。

但是,在创建此约束后,尝试插入新的 NULL 值或将现有值更新为 NULL 将失败。

【讨论】:

  • 这很酷,但它是否允许我先写入空值,然后再写入非空值?!
  • @IvanVC,此 CHECK 约束不适用于所有新值。它不允许插入新的 NULL 值。在阅读了您对所需逻辑的详细解释后,我认为您很可能需要一个触发器来实现您描述的逻辑。
  • 感谢您提供信息。我首先考虑的是这种约束,但不确定它是否能完成这项工作。不过还是谢谢你。