【问题标题】:How to make constraint value of a column for the same value of other column?如何使一列的约束值与其他列的值相同?
【发布时间】:2020-08-16 23:50:39
【问题描述】:
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 sql sql-insert unique-constraint mysql-5.7


    【解决方案1】:

    您真正想要的是过滤后的唯一索引。唉,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 提供多个值,因此当 main_photo 值为 0 时,不会强制执行唯一性。

    Here 是一个 dbfiddle。

    【讨论】:

    • 使用 MySQL 5.7,修改表时出现错误 #1064。
    • @user1801605 。 . . MySQL 从 5.7.10 版本开始支持生成的列:dev.mysql.com/doc/refman/5.7/en/…
    • @user1801605 。 . .我还添加了一个 dbfiddle。
    【解决方案2】:

    用唯一的约束改变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 |学生ID |主照片 --------: | ---------: | ---------: 1 | 1 | 0 3 | 2 | 1

    db小提琴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 已经存在
    SELECT * FROM photos
    
    photo_id |学生ID |主照片 --------: | ---------: | ---------: 1 | 1 | 0 2 | 1 | 1 3 | 2 | 1

    db小提琴here

    【讨论】:

    • student_id 不需要约束。但是当值为1 时,我确实需要main_photo 的约束。
    • 为此,您需要一个 BEFORE INBSERT TRIGGER 查看更改的答案
    【解决方案3】:

    在最近的 MySQL 版本中,您可以在唯一索引中使用 case 表达式:

    create unique index idx_photos_uniq 
        on photos((case when main_photo then student_id end));
    

    这会强制 student_idmain_photo 在逻辑上为真的行上具有唯一性(这实际上假定这是一个布尔列 - 否则您可能需要 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'
    

    【讨论】:

    • 我使用的是 MySQL 5.7,创建唯一索引时出现错误 #1064。
    • @user1801605: 5.7 不符合最新版本的条件。我认为我的解决方案需要 8.0.13 版本。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 2021-09-26
    相关资源
    最近更新 更多