最近对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,先不要注意我的引擎和字符编码

 
  
  1. mysql> show create table usage_flags\G  
  2. *************************** 1. row ***************************  
  3.        Table: usage_flags  
  4. Create TableCREATE TABLE `usage_flags` (  
  5.   `s` set('ls','tp','ns','nt','nb','np','nc','si','al','mr','e5','e4','no','ph'default NULL 
  6. ) ENGINE=MyISAM DEFAULT CHARSET=latin1  
  7. 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值对应的二进制关系

 
  
  1. mysql> select s,s+0,bin(s+0) from usage_flags;  
  2. +-------------+------+----------------+  
  3. | s           | s+0  | bin(s+0)       |  
  4. +-------------+------+----------------+  
  5. | ls          |    1 | 1              |   
  6. | tp          |    2 | 10             |   
  7. | ns          |    4 | 100            |   
  8. | nt          |    8 | 1000           |   
  9. | nb          |   16 | 10000          |   
  10. | np          |   32 | 100000         |   
  11. | nc          |   64 | 1000000        |   
  12. | si          |  128 | 10000000       |   
  13. | al          |  256 | 100000000      |   
  14. | mr          |  512 | 1000000000     |   
  15. | e5          | 1024 | 10000000000    |   
  16. | e4          | 2048 | 100000000000   |   
  17. no          | 4096 | 1000000000000  |   
  18. | ph          | 8192 | 10000000000000 |      
  19. +-------------+------+----------------+  
  20. 14 rows in set (0.00 sec) 

解释:

在这里,s+0列中的数值可以等价于s列中对应的值,我们来看一个例子:

以下所查出来的内容是完全相同的,这一点可以证明上述所叙

 
  
  1.  
  2. mysql> select s,s+0,bin(s+0) from usage_flags where s=8;   
  3. +------+------+----------+  
  4. | s    | s+0  | bin(s+0) |  
  5. +------+------+----------+  
  6. | nt   |    8 | 1000     |   
  7. +------+------+----------+  
  8. 1 row in set (0.00 sec)  
  9.  
  10. mysql> select s,s+0,bin(s+0) from usage_flags where s='nt';  
  11. +------+------+----------+  
  12. | s    | s+0  | bin(s+0) |  
  13. +------+------+----------+  
  14. | nt   |    8 | 1000     |   
  15. +------+------+----------+  
  16. 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:

 
  
  1. mysql> show create table userinf\G  
  2. *************************** 1. row ***************************  
  3.        Table: userinf  
  4. Create TableCREATE TABLE `userinf` (  
  5.   `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 
  6. ) ENGINE=MyISAM DEFAULT CHARSET=latin1  
  7. 1 row in set (0.00 sec) 

然后,我们再查看对应的十进制和二进制关系:

 
  
  1. mysql> select usertype,usertype+0,bin(usertype+0) from userinf;  
  2. +---------+------------+----------------------------------+  
  3. | usertype| usertype+0 | bin(usertype+0)                  |  
  4. +---------+------------+----------------------------------+  
  5. | general |          1 | 1                                |   
  6. | a1      |          2 | 10                               |   
  7. | a2      |          4 | 100                              |   
  8. | a3      |          8 | 1000                             |   
  9. | a4      |         16 | 10000                            |   
  10. | a5      |         32 | 100000                           |   
  11. | a6      |         64 | 1000000                          |   
  12. | a7      |        128 | 10000000                         |   
  13. | b0      |        256 | 100000000                        |   
  14. | b1      |        512 | 1000000000                       |   
  15. | b2      |       1024 | 10000000000                      |   
  16. | b3      |       2048 | 100000000000                     |   
  17. | b4      |       4096 | 1000000000000                    |   
  18. | b5      |       8192 | 10000000000000                   |   
  19. | b6      |      16384 | 100000000000000                  |   
  20. | b7      |      32768 | 1000000000000000                 |   
  21. | c0      |      65536 | 10000000000000000                |   
  22. | c1      |     131072 | 100000000000000000               |   
  23. | c2      |     262144 | 1000000000000000000              |   
  24. | c3      |     524288 | 10000000000000000000             |   
  25. | c4      |    1048576 | 100000000000000000000            |   
  26. | c5      |    2097152 | 1000000000000000000000           |   
  27. | c6      |    4194304 | 10000000000000000000000          |   
  28. | c7      |    8388608 | 100000000000000000000000         |   
  29. | d0      |   16777216 | 1000000000000000000000000        |   
  30. | d1      |   33554432 | 10000000000000000000000000       |   
  31. | d2      |   67108864 | 100000000000000000000000000      |   
  32. | d3      |  134217728 | 1000000000000000000000000000     |   
  33. | d4      |  268435456 | 10000000000000000000000000000    |   
  34. | d5      |  536870912 | 100000000000000000000000000000   |   
  35. | nostop  | 1073741824 | 1000000000000000000000000000000  |   
  36. | admin   | 2147483648 | 10000000000000000000000000000000 |   
  37. +---------+------------+----------------------------------+  
  38. 32 rows in set (0.00 sec) 

我们再回头看看这个例子的问题:

请问,(UserType & 2147483648)和(UserType & 1073741824)分别代表什么含义?

在这里有必要说一下这里的"&"的含义,很多朋友认为是连字符,其实不是的,这里的&属于位运算符,大概意思是:按位AND(与)如果两个操作数的对应位为1,则结果位为1,也就是说两个值相等则返回该对应的位,不等就不返回,意思有点类似于逻辑运算符"&&",和'&'一起的位运算符还有'|","<<",">>"这些运算符的含义可以去google一下,我们再回到问题,来看下面结果:

 
  
  1. mysql> select usertype,usertype+0,bin(usertype+0) from userinf where usertype= 2147483648;  
  2. +----------+------------+----------------------------------+  
  3. | susertype| usertypes+0| bin(usertype+0)                  |  
  4. +----------+------------+----------------------------------+  
  5. | admin  | 2147483648 | 10000000000000000000000000000000 |   
  6. +----------+------------+----------------------------------+  
  7. 1 row in set (0.00 sec) 

看出来了吗?UserType & 2147483648 要找的其实是 admin,同样的UserType & 1073741824要找的是nostop(注意看我两种where的写法一个是=,一个是位运算符(&):

 
  
  1. mysql> select usertype,usertype+0,bin(usertype+0) from userinf where usertype&1073741824;  
  2. +--------+------------+---------------------------------+  
  3. | s      | s+0        | bin(s+0)                        |  
  4. +--------+------------+---------------------------------+  
  5. | nostop | 1073741824 | 1000000000000000000000000000000 |   
  6. +--------+------------+---------------------------------+  
  7. 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  |   
  • +------+------+-------------------------------+  
  • rows in set (0.00 sec) 
+ -------------+-------------+--------------- -+  

这样我们找到了a2+a3+a5+a6=108组合的字符了(a2,a3,a5,a6)。

有不足之处希望各路高手指点,谢谢