您的位置:首页 > 数据库 > MySQL

mysql的串列类型之 set理解

2012-03-14 20:59 375 查看
最近对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)。

有不足之处希望各路高手指点,谢谢
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息