最近对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> showcreatetableusage_flags\G
*************************** 1. row ***************************
Table: usage_flags
CreateTable:CREATETABLE`usage_flags` (
`s`set('ls','tp','ns','nt','nb','np','nc','si','al','mr','e5','e4','no','ph')defaultNULL
) ENGINE=MyISAMDEFAULTCHARSET=latin1
1 rowinset(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>selects,s+0,bin(s+0)fromusage_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 |
+-------------+------+----------------+
14rowsinset(0.00 sec)
解释:
在这里,s+0列中的数值可以等价于s列中对应的值,我们来看一个例子:
以下所查出来的内容是完全相同的,这一点可以证明上述所叙
mysql>selects,s+0,bin(s+0)fromusage_flagswheres=8;
+------+------+----------+
| s | s+0 | bin(s+0) |
+------+------+----------+
| nt | 8 | 1000 |
+------+------+----------+
1 rowinset(0.00 sec)
mysql>selects,s+0,bin(s+0)fromusage_flagswheres='nt';
+------+------+----------+
| s | s+0 | bin(s+0) |
+------+------+----------+
| nt | 8 | 1000 |
+------+------+----------+
1 rowinset(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> showcreatetableuserinf\G
*************************** 1. row ***************************
Table: userinf
CreateTable:CREATETABLE`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')defaultNULL
) ENGINE=MyISAMDEFAULTCHARSET=latin1
1 rowinset(0.00 sec)
然后,我们再查看对应的十进制和二进制关系:
mysql>selectusertype,usertype+0,bin(usertype+0)fromuserinf;
+---------+------------+----------------------------------+
| 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 |
+---------+------------+----------------------------------+
32rowsinset(0.00 sec)
我们再回头看看这个例子的问题:
请问,(UserType & 2147483648)和(UserType & 1073741824)分别代表什么含义?
在这里有必要说一下这里的"&"的含义,很多朋友认为是连字符,其实不是的,这里的&属于位运算符,大概意思是:按位AND(与)如果两个操作数的对应位为1,则结果位为1,也就是说两个值相等则返回该对应的位,不等就不返回,意思有点类似于逻辑运算符"&&",和'&'一起的位运算符还有'|","<>"这些运算符的含义可以去google一下,我们再回到问题,来看下面结果:
mysql>selectusertype,usertype+0,bin(usertype+0)fromuserinfwhereusertype= 2147483648;
+----------+------------+----------------------------------+
| susertype| usertypes+0| bin(usertype+0) |
+----------+------------+----------------------------------+
| admin | 2147483648 | 10000000000000000000000000000000 |
+----------+------------+----------------------------------+
1 rowinset(0.00 sec)
看出来了吗?UserType & 2147483648 要找的其实是 admin,同样的UserType & 1073741824要找的是nostop(注意看我两种where的写法一个是=,一个是位运算符(&):
mysql>selectusertype,usertype+0,bin(usertype+0)fromuserinfwhereusertype&1073741824;
+--------+------------+---------------------------------+
| s | s+0 | bin(s+0) |
+--------+------------+---------------------------------+
| nostop | 1073741824 | 1000000000000000000000000000000 |
+--------+------------+---------------------------------+
1 rowinset(0.00 sec)
在这些值里面('general','a1','a2','a3'....)我们可以找很多只要这些值('general','a1','a2','a3')能组合起来的字符,比如说我们找usertype&108字符:
mysql>selectusertype,usertype+0,bin(usertype+0)fromuserinfwhereusertype&108;
| usertype | usertype+0 | bin(usertype+0) |
+-------------+-------------+-----------------+
| a2 | 4 | 100 |
| a3 | 8 | 1000 |
| a5 | 32 | 100000 |
| a6 | 64 | 1000000 |
+------+------+-------------------------------+
4rowsinset(0.00 sec)+-------------+-------------+--------------- -+
这样我们找到了a2+a3+a5+a6=108组合的字符了(a2,a3,a5,a6)。
有不足之处希望各路高手指点,谢谢