如何向表中添加检查约束?

Mat*_*Bak 32 mysql sql database constraints check-constraints

我在这张桌子上遇到了麻烦

CREATE TABLE `Participants` (
  `meetid` int(11) NOT NULL,
  `pid` varchar(15) NOT NULL,
  `status` char(1) DEFAULT NULL,
  PRIMARY KEY (`meetid`,`pid`),
  CONSTRAINT `participants_ibfk_1` FOREIGN KEY (`meetid`) REFERENCES `Meetings` (`meetid`) ON DELETE CASCADE
  CONSTRAINT `participants_ibfk_2` CHECK (status IN ('a','d','u'))
  CONSTRAINT `participants_ibfk_3` CHECK (pid IN (SELECT name FROM Rooms) OR pid IN (SELECT userid FROM People))
);
Run Code Online (Sandbox Code Playgroud)

我希望有一个外键约束,这是有效的.然后我想为属性添加一个约束,status这样它只能取值'a','d'和'u'.我不可能将字段设置为Enumset.

任何人都可以告诉我为什么这段代码在MySQL中不起作用?

Nul*_*ion 72

CHECKMySQL不支持约束.您可以定义它们,但它们什么都不做(从MySQL 5.7开始).

手册:

CHECK子句被解析但被所有存储引擎忽略.

解决方法是创建触发器,但它们不是最容易使用的.

如果你想要一个支持CHECK约束的开源RDBMS ,试试PostgreSQL.它实际上是一个非常好的数据库.

  • 有时我想知道为什么有人再使用MySQL了 - "哎呀,抱歉,我们决定不实现数据完整性!".如果您对RDBMS有任何控制权,并且您想要开源,那么Postgres就是The Way. (19认同)
  • MariaDB 10.2实现了CHECK约束. (5认同)
  • 对于 MySQL 5.8.0.16 及更高版本,此答案不再适用。https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html (2认同)
  • MySQL 8.0.16(2019 年 4 月)及更高版本支持“CHECK”约束。 (2认同)

guz*_*off 18

我不明白为什么没有人提到VIEW WITH CHECK OPTION可以替代MySQL中的CHECK CONSTRAINT:

CREATE VIEW name_of_view AS SELECT * FROM your_table
WHERE <condition> WITH [LOCAL | CASCADED] CHECK OPTION;
Run Code Online (Sandbox Code Playgroud)

MySQL站点上有一个doc:View WITH CHECK OPTION子句

DROP TABLE `Participants`;

CREATE TABLE `Participants` (
  `meetid` int(11) NOT NULL,
  `pid` varchar(15) NOT NULL,
  `status` char(1) DEFAULT NULL check (status IN ('a','d','u')),
  PRIMARY KEY (`meetid`,`pid`)
);

-- should work
INSERT INTO `Participants` VALUES (1,1,'a');
-- should fail but doesn't because table check is not implemented in MySQL
INSERT INTO `Participants` VALUES (2,1,'x');

DROP VIEW vParticipants;
CREATE VIEW vParticipants AS 
  SELECT * FROM Participants WHERE status IN ('a','d','u')
  WITH CHECK OPTION;

-- should work
INSERT INTO vParticipants VALUES (3,1,'a');
-- will fail because view uses a WITH CHECK OPTION
INSERT INTO vParticipants VALUES (4,1,'x');
Run Code Online (Sandbox Code Playgroud)

PS:请记住,您的视图应该是可更新的!请参阅MySQL可更新视图 (感谢Romeo Sierra在评论中的澄清).

  • "*我不明白为什么这里没有人提到......*",因为这是一个解决方法.但当然,这可以非常有效的方式解决问题.您需要做的就是确保**视图可以更新**,瞧!问题消失了.为此+1. (2认同)

ype*_*eᵀᴹ 15

除了触发器之外,还有简单的约束,例如你所拥有的约束:

CONSTRAINT `participants_ibfk_2` 
  CHECK status IN ('a','d','u')
Run Code Online (Sandbox Code Playgroud)

你可以使用Foreign Keyfrom status到一个Reference表(ParticipantStatus有3行:) 'a','d','u':

CONSTRAINT ParticipantStatus_Participant_fk
  FOREIGN KEY (status)
    REFERENCES ParticipantStatus(status) 
Run Code Online (Sandbox Code Playgroud)


Vla*_*cea 10

从 8.0.16 版本开始,MySQL 添加了对 CHECK 约束的支持:

ALTER TABLE topic
ADD CONSTRAINT post_content_check
CHECK (
    CASE
        WHEN DTYPE = 'Post'
        THEN
            CASE
                WHEN content IS NOT NULL
                THEN 1
                ELSE 0
            END
        ELSE 1
    END = 1
);
 
ALTER TABLE topic
ADD CONSTRAINT announcement_validUntil_check
CHECK (
    CASE
        WHEN DTYPE = 'Announcement'
        THEN
            CASE
                WHEN validUntil IS NOT NULL
                THEN 1
                ELSE 0
            END
        ELSE 1
    END = 1
);
Run Code Online (Sandbox Code Playgroud)

以前,这只能使用 BEFORE INSERT 和 BEFORE UPDATE 触发器:

CREATE
TRIGGER post_content_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
   IF NEW.DTYPE = 'Post'
   THEN
       IF NEW.content IS NULL
       THEN
           signal sqlstate '45000'
           set message_text = 'Post content cannot be NULL';
       END IF;
   END IF;
END;
 
CREATE
TRIGGER post_content_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
   IF NEW.DTYPE = 'Post'
   THEN
       IF NEW.content IS NULL
       THEN
           signal sqlstate '45000'
           set message_text = 'Post content cannot be NULL';
       END IF;
   END IF;
END;
 
CREATE
TRIGGER announcement_validUntil_check BEFORE INSERT
ON topic
FOR EACH ROW
BEGIN
   IF NEW.DTYPE = 'Announcement'
   THEN
       IF NEW.validUntil IS NULL
       THEN
           signal sqlstate '45000'
           set message_text = 'Announcement validUntil cannot be NULL';
       END IF;
   END IF;
END;
 
CREATE
TRIGGER announcement_validUntil_update_check BEFORE UPDATE
ON topic
FOR EACH ROW
BEGIN
   IF NEW.DTYPE = 'Announcement'
   THEN
       IF NEW.validUntil IS NULL
       THEN
           signal sqlstate '45000'
           set message_text = 'Announcement validUntil cannot be NULL';
       END IF;
   END IF;
END;
Run Code Online (Sandbox Code Playgroud)