最近對mysql的 set 串列類型有點了解,拿出來分享,有不足之處歡迎各位拍磚
首先引入set的含義:
對於 SET 類型,SET 列的集合成員不是順序編號的,而是每個成員對應 SET 值中的一個二進制位。
第一個集合成員對應於 0 位,第二個成員對應於 1 位,以此類推。
數值 SET 值 0 對應於空串,SET 成員以位值保存。
每個字節的 8 個集合值可按此方式存放,因此 SET 列的存儲大小是由集合成員的數目決定的,最多 64 個成員。
對於大小爲 1 到 8、9 到 16、17 到 24、25 到 32、33 到 64 個成員的集合,
其 SET 值分別佔用 1、2、3、4 或 8 個字節。
SET 定義中的值順序決定了在顯示由多個集合成員組成的 SET 列值時,子串出現的順序。
光看理論是不行的,還得以例子來說明:例如
我在本機建立了一個表:usage_flags(詳細信息如下)
這裏重點是set,先不要注意我的引擎和字符編碼
- mysql> show create table usage_flags\G
- *************************** 1. row ***************************
- Table: usage_flags
- Create Table: CREATE TABLE `usage_flags` (
- `s` set('ls','tp','ns','nt','nb','np','nc','si','al','mr','e5','e4','no','ph') default NULL
- ) ENGINE=MyISAM DEFAULT CHARSET=latin1
- 1 row in set (0.00 sec)
解釋:
s 字段的類型是set,包括的值有 'ls ', 'tp ', 'ns ', 'nt ', 'nb ', 'np ', 'nc ', 'si ', 'al ', 'mr ', 'e5 ', 'e4 ', 'no ', 'ph ' (這些就是所謂的成員了);
我們來回看set的含義中一點:而是每個成員對應 SET 值中的一個二進制位
這句話的理解是:剛剛建立的s字段中包括的值(也就是'ls''ls','tp','nt'......)對應set值中的一個二進制,我們來看以下內容:
爲了方便查看以下貼出來s列的十進制和二進制的形式,這樣可以看出set值對應的二進制關係
- mysql> select s,s+0,bin(s+0) from usage_flags;
- +-------------+------+----------------+
- | s | s+0 | bin(s+0) |
- +-------------+------+----------------+
- | ls | 1 | 1 |
- | tp | 2 | 10 |
- | ns | 4 | 100 |
- | nt | 8 | 1000 |
- | nb | 16 | 10000 |
- | np | 32 | 100000 |
- | nc | 64 | 1000000 |
- | si | 128 | 10000000 |
- | al | 256 | 100000000 |
- | mr | 512 | 1000000000 |
- | e5 | 1024 | 10000000000 |
- | e4 | 2048 | 100000000000 |
- | no | 4096 | 1000000000000 |
- | ph | 8192 | 10000000000000 |
- +-------------+------+----------------+
- 14 rows in set (0.00 sec)
解釋:
在這裏,s+0列中的數值可以等價於s列中對應的值,我們來看一個例子:
以下所查出來的內容是完全相同的,這一點可以證明上述所敘
- mysql> select s,s+0,bin(s+0) from usage_flags where s=8;
- +------+------+----------+
- | s | s+0 | bin(s+0) |
- +------+------+----------+
- | nt | 8 | 1000 |
- +------+------+----------+
- 1 row in set (0.00 sec)
- mysql> select s,s+0,bin(s+0) from usage_flags where s='nt';
- +------+------+----------+
- | s | s+0 | bin(s+0) |
- +------+------+----------+
- | nt | 8 | 1000 |
- +------+------+----------+
- 1 row in set (0.00 sec)
當然,這些需要運用到實際開發中才能更加深入的理解,我們再來看一個例子:
數據庫已連接
if (preg_match("/admin/i",$FORM_userid)) { $sql = "SELECT * FROM userinf
WHERE UserId='$FORM_userid'
AND Password=password('$FORM_psd')
AND (UserType & 2147483648)";
} else {
$sql = "SELECT * FROM userinf
WHERE UserId='$FORM_userid'
AND Password='$FORM_psd'
AND (UserType & 1073741824)";
}
這是身份驗證的一段程序。$FORM_userid和$FORM_psd'分別是上一Web頁登錄窗口提交的的用戶名和密碼。userinf表中的UserType列類型爲SET,其中的值分別爲:'general','a1','a2','a3','a4','a5','a6','a7','b0','b1','b2','b3',
'b4','b5','b6','b7','c0','c1','c2','c3','c4','c5','c6','c7','d0','d1','d2','d3','d4',
'd5','nostop','admin'。
請問,(UserType & 2147483648)和(UserType & 1073741824)分別代表什麼含義,爲什麼?
爲了解答這個例子,我們按照上面所說的步驟來做;
首先,我們來建立一個userinf表和usertype字段並且該類型爲set:
- mysql> show create table userinf\G
- *************************** 1. row ***************************
- Table: userinf
- Create Table: CREATE TABLE `userinf` (
- `usertype` set('general','a1','a2','a3','a4','a5','a6','a7','b0','b1','b2','b3','b4','b5','b6','b7','c0','c1','c2','c3','c4','c5','c6','c7','d0','d1','d2','d3','d4','d5','nostop','admin') default NULL
- ) ENGINE=MyISAM DEFAULT CHARSET=latin1
- 1 row in set (0.00 sec)
然後,我們再查看對應的十進制和二進制關係:
- mysql> select usertype,usertype+0,bin(usertype+0) from userinf;
- +---------+------------+----------------------------------+
- | usertype| usertype+0 | bin(usertype+0) |
- +---------+------------+----------------------------------+
- | general | 1 | 1 |
- | a1 | 2 | 10 |
- | a2 | 4 | 100 |
- | a3 | 8 | 1000 |
- | a4 | 16 | 10000 |
- | a5 | 32 | 100000 |
- | a6 | 64 | 1000000 |
- | a7 | 128 | 10000000 |
- | b0 | 256 | 100000000 |
- | b1 | 512 | 1000000000 |
- | b2 | 1024 | 10000000000 |
- | b3 | 2048 | 100000000000 |
- | b4 | 4096 | 1000000000000 |
- | b5 | 8192 | 10000000000000 |
- | b6 | 16384 | 100000000000000 |
- | b7 | 32768 | 1000000000000000 |
- | c0 | 65536 | 10000000000000000 |
- | c1 | 131072 | 100000000000000000 |
- | c2 | 262144 | 1000000000000000000 |
- | c3 | 524288 | 10000000000000000000 |
- | c4 | 1048576 | 100000000000000000000 |
- | c5 | 2097152 | 1000000000000000000000 |
- | c6 | 4194304 | 10000000000000000000000 |
- | c7 | 8388608 | 100000000000000000000000 |
- | d0 | 16777216 | 1000000000000000000000000 |
- | d1 | 33554432 | 10000000000000000000000000 |
- | d2 | 67108864 | 100000000000000000000000000 |
- | d3 | 134217728 | 1000000000000000000000000000 |
- | d4 | 268435456 | 10000000000000000000000000000 |
- | d5 | 536870912 | 100000000000000000000000000000 |
- | nostop | 1073741824 | 1000000000000000000000000000000 |
- | admin | 2147483648 | 10000000000000000000000000000000 |
- +---------+------------+----------------------------------+
- 32 rows in set (0.00 sec)
我們再回頭看看這個例子的問題:
請問,(UserType & 2147483648)和(UserType & 1073741824)分別代表什麼含義?
在這裏有必要說一下這裏的"&"的含義,很多朋友認爲是連字符,其實不是的,這裏的&屬於位運算符,大概意思是:按位AND(與)如果兩個操作數的對應位爲1,則結果位爲1,也就是說兩個值相等則返回該對應的位,不等就不返回,意思有點類似於邏輯運算符"&&",和'&'一起的位運算符還有'|","<<",">>"這些運算符的含義可以去google一下,我們再回到問題,來看下面結果:
- mysql> select usertype,usertype+0,bin(usertype+0) from userinf where usertype= 2147483648;
- +----------+------------+----------------------------------+
- | susertype| usertypes+0| bin(usertype+0) |
- +----------+------------+----------------------------------+
- | admin | 2147483648 | 10000000000000000000000000000000 |
- +----------+------------+----------------------------------+
- 1 row in set (0.00 sec)
看出來了嗎?UserType & 2147483648 要找的其實是 admin,同樣的UserType & 1073741824要找的是nostop(注意看我兩種where的寫法一個是=,一個是位運算符(&):
- mysql> select usertype,usertype+0,bin(usertype+0) from userinf where usertype&1073741824;
- +--------+------------+---------------------------------+
- | s | s+0 | bin(s+0) |
- +--------+------------+---------------------------------+
- | nostop | 1073741824 | 1000000000000000000000000000000 |
- +--------+------------+---------------------------------+
- 1 row in set (0.00 sec)
在這些值裏面('general','a1','a2','a3'....)我們可以找很多隻要這些值('general','a1','a2','a3')能組合起來的字符,比如說我們找usertype&108字符:
+-------------+-------------+--------------- -+
- mysql> select usertype,usertype+0,bin(usertype+0) from userinf where usertype&108;
- | usertype | usertype+0 | bin(usertype+0) |
- +-------------+-------------+-----------------+
- | a2 | 4 | 100 |
- | a3 | 8 | 1000 |
- | a5 | 32 | 100000 |
- | a6 | 64 | 1000000 |
- +------+------+-------------------------------+
- 4 rows in set (0.00 sec)
這樣我們找到了a2+a3+a5+a6=108組合的字符了(a2,a3,a5,a6)。
有不足之處希望各路高手指點,謝謝