如何为其他列的相同值制作列的约束值?

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)。

Demo on dB Fiddle:

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