当前位置:嗨网首页>书籍在线阅读

29-用BIT GROUP FUNCTIONS做统计

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

在本小节,主要介绍如何共同使用GROUP BY语句和BIT_AND、BIT_OR函数完成统计工作。这两个函数的一般用途就是做数值之间的逻辑位运算,但是,当把它们与 GROUP BY子句联合使用的时候就可以做一些其他的任务。

假设现在有这样一个任务:一个超市需要记录每个用户每次来超市都购买了哪些商品。为了将问题简单化,假设该超市只有面包、牛奶、饼干、啤酒4种商品。那么通常该怎么做呢?一般先建立一个购物单表,里面记录购物发生的时间、顾客信息等;然后再建立一个购物单明细表,里面记录该顾客所购买的商品。这样设计表结构的优点是顾客所购买的商品的详细信息可以记录下来,比如数量、单价等,但是如果目前的这个任务只需要知道用户购买商品的种类和每次购物总价等信息,那么这种数据库结构的设计就显得太复杂了。一般还可能会想到用一个表实现这个功能,并且用一个字段以字符串的形式记录顾客所购买的所有商品的商品号,这也是一种方法,但是如果顾客一次购买商品比较多,需要很大的存储空间,而且将来做各种统计的时候也会捉襟见肘。

下面给出一种新的解决办法,类似于上面讲到的第二种方案,仍然用一个字段表示顾客购买商品的信息,但是这个字段是数值型的而不是字符型的,该字段存储一个十进制数字,当它转换成二进制的时候,那么每一位代表一种商品,而且如果所在位是“1”那么表示顾客购买了该种商品,“0”表示没有购买该种商品。比如数值的第1位代表面包(规定从右向左开始计算)、第2位代表牛奶、第3位代表饼干、第4位代表啤酒,这样如果一个用户购物单的商品列的数值为5,那么二进制表示为0101,这样从右向左第1位和第3位是1,那么就可以知道这个用户购买了面包和饼干,而如果这个客户有多个这样的购物单(在数据库中就是有多条记录),把这些购物单按用户分组做 BIT_OR()操作就可以知道这个用户都购买过什么商品。

下面举例说明一下这个操作,首先初始化一组数据:

mysql> create table order_rab (id int,customer_id int,kind int);

Query OK, 0 rows affected (0.05 sec)

mysql> insert into order_rab values (1,1,5),(2,1,4);

Query OK, 2 rows affected (0.00 sec)

mysql> insert into order_rab values (3,2,3),(4,2,4);

Query OK, 2 rows affected (0.00 sec)

mysql> select * from order_rab;

+------+-------------+------+

| id | customer_id | kind |

+------+-------------+------+

| 1 | 1 | 5 |

| 2 | 1 | 4 |

| 3 | 2 | 3 |

| 4| 2| 4|

+------+-------------+------+

4 rows in set (0.00 sec)

其中customerid是顾客编号,kind是所购买的商品,初始化了两个顾客1和2的数据,他们每人购物两次,前者购买的商品数值是5和4,转化为二进制分别为0101、0100,表示这个顾客第一次购买了牛奶和啤酒,第二次购买了牛奶;后者购买的商品数值是3和4,转化为二进制分别为0011、0100,表示这个顾客第一次购买了饼干和啤酒,第二次购买了牛奶。

下面用BIT_OR()函数与GROUP BY子句联合起来,统计一下这两个顾客在这个超市一共都购买过什么商品,如下例:

mysql> select customer_id,bit_or(kind) from order_rab group by customer_id;

+-------------+--------------+

| customer_id | bit_or(kind) |

+-------------+--------------+

| 1 | 5 |

| 2 | 7 |

+-------------+--------------+

2 rows in set (0.00 sec)

可以看到顾客1的BIT_OR()结果是5,即0101,表示这个顾客在本超市购买过牛奶和啤酒;顾客2的BIT_OR()结果是7,即0111,表示这个顾客在本超市购买过牛奶、饼干、啤酒。

下面解释一下数据库在处理这个逻辑时的计算过程,以第一个顾客举例,那么BIT_OR(kind)就相当于把kind的各个值做了一个“或”操作,最终结果是十进制的5。逻辑计算公式如下:

  ..0101

  ..0100

 OR ..0000

 ---------

  ..0101

同理,可以用BIT_AND()统计每个顾客每次来本超市都会购买的商品,具体如下:

mysql> select customer_id,bit_and(kind) from order_rab group by customer_id;

+-------------+---------------+

| customer_id | bit_and(kind) |

+-------------+---------------+

| 1 | 4 |

| 2 | 0 |

+-------------+---------------+

2 rows in set (0.01 sec)

顾客1的BIT_AND()结果是4,即0100,表示顾客1每次来本超市都会购买牛奶;顾客2的BIT_AND()结果是0,即0000,表示顾客2不是每次来本超市都会购买的商品。

数据库在处理BIT_AND()的时候就是把kind的各个值做了一个“与”操作,拿顾客1举例说明一下,逻辑计算公式如下:

  ..0101

  ..0100

 AND ..1111

 ----------

  ..0100

从上面的例子可以看出,这种数据库结构设计的好处就是能用很简洁的数据表示很丰富的信息,这种方法能够大大地节省存储空间,而且能够提高部分统计计算的速度。不过需要注意的是,这种设计其实损失了顾客购买商品的详细信息,比如购买商品的数量、当时单价、是否有折扣、是否有促销等,因此还要根据应用的实际情况有选择地考虑数据库的结构设计。