Mysql

多欄位唯一約束,我們基於空值包含一個或另一個欄位

  • June 18, 2017

假設我有四列

| x | y | z | w |

我想要以下約束:

  1. 如果wNULL,則x, y,z必須是唯一的。
  2. 如果wis not NULL,則x, y,w必須是唯一的。

這可能嗎?

首先,對於 2 號約束,不需要什麼特別的。UNIQUE約束忽略 - 並接受 -值,因此一個NULL簡單的唯一約束(w,x,y)將很好地執行它。

對於第 1 個約束,我認為 5.6 版中沒有 DDL 方法,因此您最好的選擇可能是@stefan 的觸發解決方案。

如果可以升級到 5.7,則可以GENERATED在其上使用列和唯一索引:

ALTER TABLE t
 ADD wz int GENERATED ALWAYS AS (CASE WHEN w IS NULL THEN z END),
 ADD UNIQUE INDEX x_y_z_uq (x, y, wz) ; 

也許與此類似的東西會有所幫助(使用@McNets 建議的觸發器):創建2個觸發器,一個用於所需的每個“唯一”檢查(有關模擬MySQL檢查約束的文章可在此處找到)。使用的 MySQL 版本:5.7

drop trigger xyzunique;

delimiter $
create trigger xyzunique before insert on uc
for each row
begin
 if new.w is null then
   if exists (
     select *
     from uc
     where x = new.x and y = new.y and z = new.z 
   )
   then
     signal sqlstate '45000' set message_text = 'xyZ unique trigger: bad number';
   end if;
 end if;
end$
delimiter ;

drop trigger xywunique;

delimiter $
create trigger xywunique before insert on uc
for each row
begin
 if new.w is not null then
   if exists (
     select *
     from uc
     where x = new.x and y = new.y and w = new.w 
   )
   then
     signal sqlstate '45000' set message_text = 'xyW unique trigger: bad number';
   end if;
 end if;
end$
delimiter ;

表(用於測試)

create table uc ( x integer, y integer , z integer , w integer ) ;

插入測試:當使用相同的值時,每秒/後續插入必須失敗。

-- insert test xyz unique: second insert must fail
mysql> insert into uc (x,y,z,w) values (1,11,111,null) ;
Query OK, 1 row affected (0.00 sec)

mysql> insert into uc (x,y,z,w) values (1,11,111,null) ;
ERROR 1644 (45000): xyZ unique trigger: bad number

-- insert test xzw unique: second insert must fail
mysql> insert into uc values (9,99,999,9999) ;
Query OK, 1 row affected (0.00 sec)

mysql> insert into uc values (9,99,999,9999) ;
ERROR 1644 (45000): xyW unique trigger: bad number

查看:

mysql> select * from uc;
+------+------+------+------+
| x    | y    | z    | w    |
+------+------+------+------+
|    1 |   11 |  111 | NULL |
|    9 |   99 |  999 | 9999 |
+------+------+------+------+
2 rows in set (0.00 sec)

當然,這需要更多的測試。此外,2 個觸發器可以合併為一個,以此類推。

引用自:https://dba.stackexchange.com/questions/176411