數據庫狀態標識位flag設計


設計目的

  • 減少各種狀態值字段
  • 減少數據庫冗余和存儲空間
  • 增加狀態值時可靈活調整,無需增加額外字段

運用場景

例子1:管理用戶的支付方式

比如針對不同用戶組設置了不同的支付方式支持,假設支付方式有支付寶微信銀聯借條等。A用戶支持支付寶、微信;B用戶支持支付寶、微信、借條。一般用戶支付方式數據庫設計為:

ID name alipay weixin union iou
1 A 1 1 0 0
2 B 1 1 0 1

這時如果后續多了其它支付方式后,就需要調整表結構增加字段,如快錢、貨到付款等。這種設計方式明顯不符合數據庫設計第一范式,增加了很多冗余字段和存儲空間。

例子2:設置用戶的操作權限

比如有一組權限列表,查看編輯發布刪除,數據庫可能會是這樣:

ID name is_visible is_editble is_publishable is_deleteable
1 A 1 1 0 0
2 B 1 1 1 1

上面只是舉些例子來說明一個問題,當一張表的字段里包含很多這些狀態值01時,我們可以使用二進制的方式來表示,而且只需要一個字段就好了。

設計思路

比如例1中的支付方式,假設我們最多可設計有10種支付方式。

字段仍設為int整形,A支持支付寶、微信,則值為12(1100);B支持支付寶、微信、借條,則值為13(1101),表結構如下:

ID name pay_flag
1 A 12
2 B 13

如果增加了貨到付款,可再賦值給二進制的第五位,其它位還是保持不變。

這時候會涉及到數據庫查詢問題,比如上面的值12、13都支持支付寶、微信,還有14(1110)、15(1111)也支持,如果增加了二進制第五位,那么會有更多匹配值,如30(11110)、28(11100)等...
如果要查詢支持支付寶、微信的數據怎么辦?這時只需要通過“位”的與運算,就能簡單的查詢出想要數據:

select * from user_pay where pay_flag & b'1100';
# 或者:  
select * from user_pay where pay_flag & 12;

php簡單實現

class PayFlag {
    const ALIPAY = 8; //01000
    const WEIXIN = 4; //00100
    const UNION  = 2; //00010
    const IOU    = 1; //00001

    function addFlag($old_flag, $flag) {
        return $old_flag | $flag;
    }

    function delFlag($old_flag, $flag) {
        return $old_flag ^ $flag;
    } 
}

$old_flag = 6; //00110
$PayFlag = new PayFlag;

//原有值 - 輸出 6:110
echo($old_flag  . ":" . decbin($old_flag) . PHP_EOL);

//增加ALIPAY - 輸出 14:1110
$new_flag = $PayFlag->addFlag($old_flag, PayFlag::ALIPAY);
echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);

//移除ALIPAY - 輸出 6:110
$new_flag = $PayFlag->delFlag($new_flag, PayFlag::ALIPAY);
echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);

//移除UNION - 輸出 4:100
$new_flag = $PayFlag->delFlag($new_flag, PayFlag::UNION);
echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);

//增加IOU - 輸出 5:101
$new_flag = $PayFlag->delFlag($new_flag, PayFlag::IOU);
echo($new_flag . ":" . decbin($new_flag) . PHP_EOL);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM