Mysql
 sql >> Base de données >  >> RDS >> Mysql

Contrainte avec vérification de valeur conditionnelle dans MySQL

Selon la documentation ,

Donc supprimer le not null -contrainte de Status et en ajoutant un index unique sur (ContactId,PhoneId,Status) fonctionnera comme vous le souhaitez, si vous utilisez null au lieu de 0 pour inactif enregistrements.

Si vous ne voulez pas ou ne pouvez pas utiliser null pour votre Status colonne, vous voulez vous assurer que Status=0 et Status=null se comporter de manière identique, ou par ex. voulez traiter Status=2 comme actif (et en appliquant l'unicité) aussi, vous pouvez ajouter une colonne factice qui sera calculée à partir de Status .

Si vous utilisez MySQL 5.7+, vous pouvez le faire avec une colonne générée :

CREATE TABLE IF NOT EXISTS `ContactPhone` (
  `ContactPhoneId` int(10) unsigned NOT NULL auto_increment primary key,
  `ContactId` int(11) NOT NULL,
  `PhoneId` smallint(5) unsigned NOT NULL,
  `Status` tinyint(1) NOT NULL DEFAULT '1',
  `StatusUnq` tinyint(1) as (if(Status <> 0, 1, null)) stored null,
  constraint unique (ContactId, PhoneId, StatusUnq)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

insert into ContactPhone (ContactPhoneId, ContactId, PhoneId, Status)
values (1, 1, 1, 1);
insert into ContactPhone (ContactPhoneId, ContactId, PhoneId, Status)
values (2, 1, 1, 1);
-- Duplicate key error 
insert into ContactPhone (ContactPhoneId, ContactId, PhoneId, Status)
values (3, 1, 1, 0);
insert into ContactPhone (ContactPhoneId, ContactId, PhoneId, Status)
values (4, 1, 1, 0);
update ContactPhone set Status = 1 where ContactPhoneId = 4;
-- Duplicate key error 

Sinon, vous pouvez utiliser une colonne normale et utiliser des déclencheurs pour calculer la valeur de la colonne, par exemple :

create trigger trbi_contactPhoneUnique before insert on ContactPhone 
for each row
  set new.StatusUnq = if(new.Status <> 0, 1, null);

create trigger trbu_contactPhoneUnique before update on ContactPhone 
for each row
  set new.StatusUnq = if(new.Status <> 0, 1, null);

Vous pouvez bien sûr changer la formule par ex. if(new.Status <> 0, new.Status, null); si vous souhaitez autoriser différentes valeurs de Status aussi.