mysql

How to set constraints properly in Mysql?


When a user's email is confirmed, a mysql TIMESTAMP value is updated and it's value should not equal '1970-01-01 00:00:01' (DEFAULT). I'm trying to create a mysql constraint that enforces that. So if user has the following:
confirmed=1
email_confirmed_time='1970-01-01 00:00:01'
...then the constraint is violated. But if confirmed=0 with that same TIMESTAMP, then it's accepted.

What is wrong about my table command below? It tells me there is a violation on CHK_emailConfirmedTime_when_confirmed if I insert the following:

insert into user (username, `password`, first_name, last_name, `role`, `group`, logged_in, confirmed, approved, email_confirmed_time) values 
    ("0", "0", "joe", "dill", "{admin, user, guest}", "{create, read, update, delete}", 0, 0, 0, DEFAULT)
;
CREATE TABLE IF NOT EXISTS user (
    `id` SERIAL PRIMARY KEY,
    `username` varchar(75) NOT NULL,
    `password` varchar(100) NOT NULL,
    `first_name` varchar(50) NOT NULL,
    `last_name` varchar(50) NOT NULL,
    `role` varchar(25) NOT NULL DEFAULT "{guest}",
    `group` varchar(50) NOT NULL DEFAULT "{read}",
    `logged_in` int NOT NULL DEFAULT 0,
    `confirmed` INTEGER NOT NULL DEFAULT 0,
    `approved` INTEGER NOT NULL DEFAULT 0,
    `email_confirmed_time` TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:01',
    CONSTRAINT CHK_confirmed CHECK (`confirmed`=0 OR `confirmed`=1),
    CONSTRAINT CHK_approved CHECK (`approved`=0 OR `approved`=1),
    CONSTRAINT CHK_emailConfirmedTime_when_notConfirmed CHECK (`confirmed`=0 AND `email_confirmed_time`=TIMESTAMP('1970-01-01 00:00:01')),
    CONSTRAINT CHK_emailConfirmedTime_when_confirmed CHECK (`confirmed`=1 AND `email_confirmed_time`>TIMESTAMP('1970-01-01 00:00:01'))
);

Solution

  • Check conditions should be satisfied fully.
    So when confirmed=1 AND email_confirmed_time`>TIMESTAMP('1970-01-01 00:00:01') this both conditions should be true. This conditions forbid insert any row with confirmed<>1 and email_confirmed_time`<=TIMESTAMP('1970-01-01 00:00:01')

    Possible join your 2 CHECK to one

     CHECK( (`confirmed`=0 AND `email_confirmed_time`=TIMESTAMP('1970-01-01 00:00:01'))
         or (`confirmed`=1 AND `email_confirmed_time`>TIMESTAMP('1970-01-01 00:00:01'))
          )
    

    And may remove CONSTRAINT CHK_confirmed CHECK (confirmed=0 OR confirmed=1)

    CREATE TABLE IF NOT EXISTS `user` (
        `id` SERIAL PRIMARY KEY,
        `username` varchar(75) NOT NULL,
        `password` varchar(100) NOT NULL,
        `first_name` varchar(50) NOT NULL,
        `last_name` varchar(50) NOT NULL,
        `role` varchar(25) NOT NULL DEFAULT "{guest}",
        `group` varchar(50) NOT NULL DEFAULT "{read}",
        `logged_in` int NOT NULL DEFAULT 0,
        `confirmed` INTEGER NOT NULL DEFAULT 0,
        `approved` INTEGER NOT NULL DEFAULT 0,
        `email_confirmed_time` TIMESTAMP NOT NULL DEFAULT '1970-01-01 00:00:01',
        CONSTRAINT CHK_confirmed CHECK (`confirmed`=0 OR `confirmed`=1),
        CONSTRAINT CHK_approved CHECK (`approved`=0 OR `approved`=1),
        CONSTRAINT CHK_emailConfirmedTime_when_Confirmed_or_notConfirmed 
            CHECK( (`confirmed`=0 AND `email_confirmed_time`=TIMESTAMP('1970-01-01 00:00:01'))
                   or (`confirmed`=1 AND `email_confirmed_time`>TIMESTAMP('1970-01-01 00:00:01'))
                 )
    );
    
    
    insert into `user` (username, `password`, first_name, last_name, `role`, `group`, logged_in
      , confirmed, approved, email_confirmed_time) values 
        ("0", "0", "joe", "dill", "{admin, user, guest}", "{create, read, update, delete}", 0
      , 0, 0, DEFAULT);
    ;
    
    select * from `user`;
    
    id username password first_name last_name role group logged_in confirmed approved email_confirmed_time
    1 0 0 joe dill {admin, user, guest} {create, read, update, delete} 0 0 0 1970-01-01 00:00:01
    insert into `user` (username, `password`, first_name, last_name, `role`, `group`, logged_in
        , confirmed, approved, email_confirmed_time) values 
    ("0", "0", "bill", "dill", "{admin, user, guest}", "{create, read, update, delete}", 0
        , 1, 0, DEFAULT)
    ;
    
    Check constraint 'CHK_emailConfirmedTime_when_Confirmed_or_notConfirmed' is violated.
    
    insert into `user` (username, `password`, first_name, last_name, `role`, `group`, logged_in
        , confirmed, approved, email_confirmed_time) values 
    ("0", "0", "john", "dill", "{admin, user, guest}", "{create, read, update, delete}", 0
        , 0, 0, TIMESTAMP('1970-01-01 00:00:02'))
    ;
    
    Check constraint 'CHK_emailConfirmedTime_when_Confirmed_or_notConfirmed' is violated.
    
    insert into `user` (username, `password`, first_name, last_name, `role`, `group`, logged_in
        , confirmed, approved, email_confirmed_time) values 
    ("0", "0", "mike", "dill", "{admin, user, guest}", "{create, read, update, delete}", 0
        , 1, 0, TIMESTAMP('1970-01-01 00:00:02'))
    ;
    
    select id,first_name,logged_in, confirmed, approved, email_confirmed_time
    from `user`;
    
    id first_name logged_in confirmed approved email_confirmed_time
    1 joe 0 0 0 1970-01-01 00:00:01
    2 mike 0 1 0 1970-01-01 00:00:02

    fiddle