經(jīng)過(guò)最近一個(gè)項(xiàng)目的開(kāi)發(fā),才發(fā)現(xiàn)了MYSQL中SET類(lèi)型的真正含義,以前都犯了Martin Fowler 在《重構(gòu)--改善既有代碼的設(shè)計(jì)》指出的 "基本型別偏執(zhí)"錯(cuò)誤,自己濫用INT類(lèi)型導(dǎo)致錯(cuò)過(guò)了其它數(shù)據(jù)類(lèi)型對(duì)于項(xiàng)目開(kāi)發(fā)所帶來(lái)的好處,現(xiàn)在好好記錄一下SET類(lèi)型的真正用法:
實(shí)際上,SET可以包含最多64個(gè)成員,其值為一個(gè)整數(shù)。這個(gè)整數(shù)的二進(jìn)制碼表示該SET的值的哪些成員為真。例如有`Status` set('ForSale','AuthSuccess','AuditSuccess','IntentionReached','SaleCanceled'),那么它們的值為:
SET member Decimal value Binary value
-----------------------------
ForSale 1 0001
AuthSuccess 2 0010
AuditSuccess 4 0100
IntentionReached 8 1000
如果將9存入Status字段,那么其二進(jìn)制值為1001,也就是說(shuō)這個(gè)值中'ForSale'和'IntentionReached'為真。
可以想到,如果這樣的話,大家可以用LIKE命令和 FIND_IN_SET() 函數(shù)來(lái)檢索SET值:
SELECT * FROM tbl_name WHERE Status LIKE '%value%'; SELECT * FROM tbl_name WHERE FIND_IN_SET('value',Status)>0;
當(dāng)然,以下SQL語(yǔ)句也是合法的,他們顯得更加簡(jiǎn)潔(注意兩個(gè)成員的順序及連接符,):
SELECT * FROM tbl_name WHERE Status = 'ForSale,IntentionReached';
同時(shí)我們還可以直接使用數(shù)值來(lái)查詢(xún):
SELECT * FROM tbl_name WHERE Status = 9
因?yàn)镾ET類(lèi)型的成員的位置都是固定的,數(shù)值9永遠(yuǎn)表示'ForSale'和'IntentionReached'為真;這樣即使以后再添加了一個(gè)狀態(tài),也不會(huì)影響之前的查詢(xún)邏輯。我們?cè)賮?lái)看看修改SET類(lèi)型字段的SQL語(yǔ)句使用技巧:
修改Status讓其'ForSale'成員為真
UPDATE tbl_name SET Status = 1 WHERE Id = 333
修改Status讓其'ForSale'、'AuthSuccess'、'IntentionReached' 成員為真
UPDATE tbl_name SET Status = 1 | 2 | 4 WHERE Id = 333;
在確認(rèn)目前狀態(tài)為7時(shí)去掉'ForSale'成員,讓7也作為操作的條件是確保目前狀態(tài)就是為7,如果沒(méi)有此需求可直接 SET Status = 6 ;
UPDATE tbl_name SET Status = 7 & ~1 WHERE Id = 333;
呵呵,利用SET類(lèi)型保存權(quán)限等數(shù)據(jù)確實(shí)讓開(kāi)發(fā)方便清晰了不少哇。