Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Restringir com verificação de valor condicional no MySQL


De acordo com a documentação ,

Portanto, removendo o not null -restrição de Status e adicionando um índice exclusivo em (ContactId,PhoneId,Status) funcionará como você deseja, se você usar null em vez de 0 para inativo registros.

Se você não quiser ou não puder usar null para seu Status coluna, queremos ter certeza de que Status=0 e Status=null comportam-se de forma idêntica, ou e. deseja tratar Status=2 como ativo (e impondo exclusividade) também, você pode adicionar uma coluna fictícia que será calculada a partir de Status .

Se você estiver usando o MySQL 5.7+, você pode fazer isso com uma coluna gerada:
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 

Caso contrário, você pode usar uma coluna normal e usar gatilhos para calcular o valor da coluna, por exemplo:
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);

É claro que você pode mudar a fórmula para, por exemplo, if(new.Status <> 0, new.Status, null); se você quiser permitir valores diferentes de Status também.