如何在MySQL表上添加自定义检查约束?
这张桌子我不舒服如何在MySQL表上添加自定义检查约束?,mysql,sql,database,constraints,check-constraints,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` (`meeti
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))
);
我希望有一个外键约束,这是可行的。然后,我还想向属性status
添加一个约束,使其只能接受值“a”、“d”和“u”。我无法将字段设置为Enum
或set
有人能告诉我为什么这段代码在MySQL中不起作用吗?
CHECK
MySQL不支持约束。您可以定义它们,但它们什么也不做(从MySQL 5.7开始)
从:
CHECK
子句已被解析,但被所有存储引擎忽略
解决方法是创建,但它们不是最容易使用的
如果您想要一个支持
检查约束的开源RDBMS,请尝试。实际上,它是一个非常好的数据库。除了触发器之外,对于您拥有的简单约束:
CONSTRAINT `participants_ibfk_2`
CHECK status IN ('a','d','u')
您可以使用外键
从状态
到参考表(参与者状态
,共3行:'a','d','u'
):
以下是一种快速、轻松地获得所需支票的方法:
drop database if exists gtest;
create database if not exists gtest;
use gtest;
create table users (
user_id integer unsigned not null auto_increment primary key,
username varchar(32) not null default '',
password varchar(64) not null default '',
unique key ix_username (username)
) Engine=InnoDB auto_increment 10001;
create table owners (
owner_id integer unsigned not null auto_increment primary key,
ownername varchar(32) not null default '',
unique key ix_ownername (ownername)
) Engine=InnoDB auto_increment 5001;
create table users_and_owners (
id integer unsigned not null primary key,
name varchar(32) not null default '',
unique key ix_name(name)
) Engine=InnoDB;
create table p_status (
a_status char(1) not null primary key
) Engine=InnoDB;
create table people (
person_id integer unsigned not null auto_increment primary key,
pid integer unsigned not null,
name varchar(32) not null default '',
status char(1) not null,
unique key ix_name (name),
foreign key people_ibfk_001 (pid) references users_and_owners(id),
foreign key people_ibfk_002 (status) references p_status (a_status)
) Engine=InnoDB;
create or replace view vw_users_and_owners as
select
user_id id,
username name
from users
union
select
owner_id id,
ownername name
from owners
order by id asc
;
create trigger newUser after insert on users for each row replace into users_and_owners select * from vw_users_and_owners;
create trigger newOwner after insert on owners for each row replace into users_and_owners select * from vw_users_and_owners;
insert into users ( username, password ) values
( 'fred Smith', password('fredSmith')),
( 'jack Sparrow', password('jackSparrow')),
( 'Jim Beam', password('JimBeam')),
( 'Ted Turner', password('TedTurner'))
;
insert into owners ( ownername ) values ( 'Tom Jones'),( 'Elvis Presley'),('Wally Lewis'),('Ted Turner');
insert into people (pid, name, status) values ( 5001, 'Tom Jones', 1),(10002,'jack Sparrow',1),(5002,'Elvis Presley',1);
我不明白为什么这里没有人提到带CHECK选项的视图可以很好地替代MySQL中的检查约束:
CREATE VIEW name_of_view AS SELECT * FROM your_table
WHERE <condition> WITH [LOCAL | CASCADED] CHECK OPTION;
p.S.:请记住,您的视图应该是可更新的!看见
(感谢Romeo Sierra在评论中的澄清)。从8.0.16版开始,MySQL增加了对检查约束的支持:
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
);
以前,这仅在使用插入前和更新前触发器时可用:
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;
谢谢你的简短而具体的回答有时我想知道为什么有人再使用MySQL——“哦,对不起,我们决定不实现数据完整性!”。如果您对RDBMS有任何类型的控制,并且希望开源,Postgres就是一种方法。如何避免主键的负值?没有检查(id>0)
功能。使用mysql 5.5MariaDB 10.2实现检查约束。对于mysql版本5.8.0.16及更高版本,这个答案不再正确。谢谢你的建议。“我不明白为什么这里没有人提到……”因为这是一个解决办法。当然,这可以非常有效地解决问题。你所需要做的就是确保你的视图是可更新的,瞧!问题解决了+1.正如前面提到的,最后MySQL 8.0.16引入了check constants:
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
);
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;