How to create a “unique” constraint on a boolean MySQL column?

前端 未结 6 782
遥遥无期
遥遥无期 2020-12-09 08:40

I would like to add a BOOLEAN column to a MySQL table which will be named is_default. In this column, only one record can have is_default

相关标签:
6条回答
  • 2020-12-09 09:26

    Check out triggers. They were introduced in version 5.0.2, I believe. You want a "before insert" trigger. If there is already a row with is_default=true, raise an error. I don't know what problems you might with concurrency and so on, but hopefully this is enough to you started.

    0 讨论(0)
  • 2020-12-09 09:31

    Check constraints are not supported in MySQL, this is the solution using trigger:

        create table if not exists myTable (
            id int not null auto_increment primary key,
            is_default bit not null
        ) engine=innodb;
    
        select 'create trigger tbi_myTable';
        drop trigger if exists tbi_myTable;
        delimiter //
        create trigger tbi_myTable 
            before insert on myTable 
            for each row
        begin
            if (select count(1) from myTable where is_default=true) > 0 && NEW.is_default then
            -- Signal is only in 5.6 and above use another way to raise an error: if less than 5.6
                SIGNAL SQLSTATE '50000' SET MESSAGE_TEXT = 'Cannot insert into myTable only one row with is_default true is allowed!';
            end if;
        END //
        delimiter ;
    
        insert into myTable (is_default) values (false);
        insert into myTable (is_default) values (true);
        insert into myTable (is_default) values (false);
        insert into myTable (is_default) values (false);
        -- This will generate an error
        insert into myTable (is_default) values (true);
        insert into myTable (is_default) values (false);
    
    
        select * from myTable;
        -- will give
        /*
        id  is_default
        1   false
        2   true
        3   false
        4   false
        */
    
    0 讨论(0)
  • 2020-12-09 09:33

    How are we dealing with this type of problem on DBs?

    In some DBMS you can create a partial index.

    In PostgreSQL this would look like this:

    CREATE UNIQUE INDEX only_one_true 
      ON the_table (is_default)
      WHERE is_default
    

    SQL Server 2008 has a very similar syntax.

    On Oracle it's a bit more complicated but doable as well:

    CREATE UNIQUE INDEX only_one_true 
      ON the_table (CASE 
                      WHEN is_default = 1 THEN 1
                      ELSE null
                    END)
    

    The Oracle solution might work on any DBMS that supports expression for an index definition.

    0 讨论(0)
  • 2020-12-09 09:34

    You can't have such a constraint in MySQL.

    However if instead of TRUE and FALSE you use the values TRUE and NULL then it will work because a UNIQUE column can have multiple NULL values. Note that this doesn't apply to all databases, but it will work in MySQL.

    CREATE TABLE table1(b BOOLEAN UNIQUE);
    
    INSERT INTO table1 (b) VALUES (TRUE);   // Succeeds
    INSERT INTO table1 (b) VALUES (TRUE);   // Fails: duplicate entry '1' for key 'b'
    
    INSERT INTO table1 (b) VALUES (FALSE);  // Succeeds
    INSERT INTO table1 (b) VALUES (FALSE);  // Fails: duplicate entry '0' for key 'b'
    
    INSERT INTO table1 (b) VALUES (NULL);   // Succeeds
    INSERT INTO table1 (b) VALUES (NULL);   // Succeeds!
    
    0 讨论(0)
  • 2020-12-09 09:35

    I don't think it is a problem with the database as much as it is a problem with your model. It is hard for me to come up with a good example of how to solve it since you haven't mentioned what type of data you are representing, but a XXXType or XXXConfiguration table would be able to hold a defaultXXXId column.

    Think of it like this: Should the color blue know that it is default or should something else know that the color blue is default when used in a given context?

    Changing the way you model your data is often a much better approach to cross-database compatibility than trying to use specific features of one database flavor to represent data in a way that is not necessarily natural to your problem domain if you think about it.

    0 讨论(0)
  • 2020-12-09 09:41

    I think this is not the best way to model the situation of a single default value.

    Instead, I would leave the IsDefault column out and create a separate table with one row and only the column(s) that make(s) up the primary key of your main table. In this table you place the PK value(s) that identify the default record.

    This results in considerably less storage and avoids the update issue of temporarily not having a default value (or, alternatively, temporarily having two default values) when you update.

    You have numerous options for ensuring that there is one-and-only-one row in the default table.

    0 讨论(0)
提交回复
热议问题