Mysql
多欄位唯一約束,我們基於空值包含一個或另一個欄位
假設我有四列
| x | y | z | w |
我想要以下約束:
- 如果
w
是NULL
,則x
,y
,z
必須是唯一的。- 如果
w
is notNULL
,則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 個觸發器可以合併為一個,以此類推。