如何为其他列的相同值制作列的约束值?
How to make constraint value of a column for the same value of other column?
TABLE 1 (photos)
photo_id | student_id | main_photo
----------------------------------
1 | 1 | 0
2 | 1 | 1
3 | 2 | 1
4 | 1 | 0
我需要确保对于同一张 student_id,只有一张主照片。因此,1
的值只能是一个,不能是两个或多个(对于同一个student_id),但是0
的值可以是多个(大于一个)。
MySQL版本:5.7
您真正想要的是过滤后的唯一索引。唉,MySQL 不允许这样。
相反,您可以对生成的列使用技巧:
alter table photos add main_photo_null int generated always as
(nullif(main_photo, 0));
然后你可以在唯一约束中使用它:
create unique index unq_photos_main on photos(student_id, main_photo_null);
MySQL 允许 NULL
在唯一 index/constraint 中有多个值,因此当 main_photo
值为 0
时不强制执行唯一性。
Here 是一个 db<>fiddle.
在最近的 MySQL 版本中,您可以在唯一索引中使用 case
表达式:
create unique index idx_photos_uniq
on photos((case when main_photo then student_id end));
这会在 main_photo
逻辑上为真的行上强制执行 student_id
的唯一性(这实际上假定这是一个布尔列 - 否则您可能需要 when main_photo = 1
)。
create table photos (
photo_id int auto_increment primary key,
student_id int,
main_photo int
);
create unique index idx_photos_uniq
on photos((case when main_photo then student_id end));
insert into photos (student_id, main_photo) values (1, 1);
insert into photos (student_id, main_photo) values (1, 0);
insert into photos (student_id, main_photo) values (2, 1);
insert into photos (student_id, main_photo) values (1, 0);
-- ok
insert into photos (student_id, main_photo) values (1, 1);
-- error: Duplicate entry '1' for key 'photos.idx_photos_uniq'
用一个唯一的约束改变 atbe,你会看到下面的结果
CREATE TABLE photos (
`photo_id` INTEGER,
`student_id` INTEGER,
`main_photo` INTEGER
);
ALTER TABLE photos
ADD CONSTRAINT UC_student_id UNIQUE (student_id);
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('1', '1', '0')
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('2', '1', '1')
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('3', '2', '1')
SELECT * FROM photos
photo_id | student_id | main_photo
-------: | ---------: | ---------:
1 | 1 | 0
3 | 2 | 1
db<>fiddle here
为了您的目的,您可以使用 BEFORE INSERT TRIGGER,它可以检查 main_photo =1
CREATE TABLE photos (
`photo_id` INTEGER,
`student_id` INTEGER,
`main_photo` INTEGER
);
#DELIMITER $$
CREATE TRIGGER before_photos_insert
BEFORE INSERT
ON photos FOR EACH ROW
BEGIN
IF EXISTS(SELECT 1 FROM photos WHERE `main_photo` = 1 AND `student_id` = NEW.`student_id`) THEN
SIGNAL sqlstate '45002' set message_text = 'mainphoto already exsits';
END IF;
END ;
#$$
#DELIMITER ;
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('1', '1', '0')
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('2', '1', '1')
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('3', '2', '1')
INSERT INTO photos
(`photo_id`, `student_id`, `main_photo`)
VALUES
('4', '1', '1')
mainphoto already exsits
SELECT * FROM photos
photo_id | student_id | main_photo
-------: | ---------: | ---------:
1 | 1 | 0
2 | 1 | 1
3 | 2 | 1
db<>fiddle here
TABLE 1 (photos)
photo_id | student_id | main_photo
----------------------------------
1 | 1 | 0
2 | 1 | 1
3 | 2 | 1
4 | 1 | 0
我需要确保对于同一张 student_id,只有一张主照片。因此,1
的值只能是一个,不能是两个或多个(对于同一个student_id),但是0
的值可以是多个(大于一个)。
MySQL版本:5.7
您真正想要的是过滤后的唯一索引。唉,MySQL 不允许这样。
相反,您可以对生成的列使用技巧:
alter table photos add main_photo_null int generated always as
(nullif(main_photo, 0));
然后你可以在唯一约束中使用它:
create unique index unq_photos_main on photos(student_id, main_photo_null);
MySQL 允许 NULL
在唯一 index/constraint 中有多个值,因此当 main_photo
值为 0
时不强制执行唯一性。
Here 是一个 db<>fiddle.
在最近的 MySQL 版本中,您可以在唯一索引中使用 case
表达式:
create unique index idx_photos_uniq
on photos((case when main_photo then student_id end));
这会在 main_photo
逻辑上为真的行上强制执行 student_id
的唯一性(这实际上假定这是一个布尔列 - 否则您可能需要 when main_photo = 1
)。
create table photos (
photo_id int auto_increment primary key,
student_id int,
main_photo int
);
create unique index idx_photos_uniq
on photos((case when main_photo then student_id end));
insert into photos (student_id, main_photo) values (1, 1);
insert into photos (student_id, main_photo) values (1, 0);
insert into photos (student_id, main_photo) values (2, 1);
insert into photos (student_id, main_photo) values (1, 0);
-- ok
insert into photos (student_id, main_photo) values (1, 1);
-- error: Duplicate entry '1' for key 'photos.idx_photos_uniq'
用一个唯一的约束改变 atbe,你会看到下面的结果
CREATE TABLE photos ( `photo_id` INTEGER, `student_id` INTEGER, `main_photo` INTEGER ); ALTER TABLE photos ADD CONSTRAINT UC_student_id UNIQUE (student_id);
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('1', '1', '0')
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('2', '1', '1')
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('3', '2', '1')
SELECT * FROM photos
photo_id | student_id | main_photo -------: | ---------: | ---------: 1 | 1 | 0 3 | 2 | 1
db<>fiddle here
为了您的目的,您可以使用 BEFORE INSERT TRIGGER,它可以检查 main_photo =1
CREATE TABLE photos ( `photo_id` INTEGER, `student_id` INTEGER, `main_photo` INTEGER );
#DELIMITER $$ CREATE TRIGGER before_photos_insert BEFORE INSERT ON photos FOR EACH ROW BEGIN IF EXISTS(SELECT 1 FROM photos WHERE `main_photo` = 1 AND `student_id` = NEW.`student_id`) THEN SIGNAL sqlstate '45002' set message_text = 'mainphoto already exsits'; END IF; END ; #$$ #DELIMITER ;
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('1', '1', '0')
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('2', '1', '1')
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('3', '2', '1')
INSERT INTO photos (`photo_id`, `student_id`, `main_photo`) VALUES ('4', '1', '1')
mainphoto already exsits
SELECT * FROM photos
photo_id | student_id | main_photo -------: | ---------: | ---------: 1 | 1 | 0 2 | 1 | 1 3 | 2 | 1
db<>fiddle here