29


我很想知道是否可以在 sql 中创建条件非空约束?换句话说,是否可以创建一个约束,使得 B 列可以为空,只要 A 列包含让我们说“新”,但如果 A 列的内容更改为其他内容,那么 B 列不再允许为空?
为了扩展这一点,只要 A 列显示“新”,就有可能使 B 列必须为空或为空?
谢谢大家 :D

4

4 回答 4

38

这对于 CONSTRAINT CHECK 来说非常好。只需这样做:

要求:

是否可以创建一个约束,使得 B 列可以为空,只要 A 列包含让我们说“新”,但如果 A 列的内容更改为其他内容,则 B 列不再允许为空?

注意这句话:B 列可以为空

解决方案:

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      A = 'NEW' -- B can be null or not null: no need to add AND here
      OR (A <> 'NEW' AND B IS NOT NULL)
    )
);

您可以进一步简化它:

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      A = 'NEW' 
      OR B IS NOT NULL
    )
);

要求与上述要求互不兼容:

为了扩展这一点,只要 A 列显示“新”,就有可能使 B 列必须为空或为空?

注意这句话:B 列必须为空

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      (A = 'NEW' AND B IS NULL)
      OR A <> 'NEW'
    )
);

可以用这个来简化,更简单但可能不像上面那样可读:

create table tbl
(
    A varchar(10) not null,
    B varchar(10),

    constraint uk_tbl check
    (
      A <> 'NEW'
      OR B IS NULL
    )
);
于 2012-04-23T01:58:18.470 回答
2

我认为您的第一个要求是:

IF ( B IS NULL ) THEN ( A = 'NEW' )

应用蕴涵重写规则:

IF ( X ) THEN ( Y )   <=>   ( NOT ( X ) OR ( Y ) )

在你的情况下;

( NOT ( B IS NULL ) OR ( A = 'NEW' ) )

小幅重写以利用 SQL 语法:

( B IS NOT NULL OR A = 'NEW' )

您的第二个陈述(“扩展”)要求:

IF ( A = 'NEW' ) THEN ( B IS NULL )

应用重写规则:

( NOT ( A = 'NEW' ) OR ( B IS NULL ) )

小改写:

( A <> 'NEW' OR B IS NULL )
于 2012-04-23T08:09:09.280 回答
1

编辑:如其他答案中所述, CHECK 是最好的方法,而不是我最初建议的触发器。原文如下:


正如 dbaseman 建议的那样,触发器是要走的路(不是这样)。尝试这样的事情(未经测试):

CREATE OR REPLACE TRIGGER test
  BEFORE UPDATE ON table1
FOR EACH ROW
WHEN (new.A = 'NEW' and new.B IS NOT NULL)
   RAISE_APPLICATION_ERROR (
     num=> -20001,
     msg=> 'B must be NULL for new rows (A = NEW)'
);
于 2012-04-23T01:33:13.850 回答
0

Per onedaywhen,这个答案在犯罪上是错误的,而且令人憎恶。您可以使用CHECK约束。 http://msdn.microsoft.com/en-us/library/ms188258.aspx

没有办法进行条件约束。但是,您应该能够使用触发器来完成这项工作。这就是他们的目的。

http://msdn.microsoft.com/en-us/library/ms189799.aspx

CREATE TRIGGER MyTable.ConditionalNullConstraint ON MyTable.ColumnB
AFTER INSERT
AS
IF EXISTS (SELECT *
    FROM inserted
    WHERE A <> 'NEW' AND B IS NULL
    )
BEGIN
    RAISERROR ('if A is ''NEW'' then B cannot be NULL', 16, 1);
    ROLLBACK TRANSACTION;
END;
GO

请注意,在查询中,您需要引用插入的对象,它是一个行为类似于表的特殊对象,并允许您引用导致触发器的行。

当然,在此示例中,您还需要处理AFTER UPDATE以强制执行约束,但这是一般的想法。

于 2012-04-23T01:29:26.743 回答