最近对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)。
有不足之处希望各路高手指点,谢谢
转载于:https://blog.51cto.com/58582786/806141