例如,某个房间可从[灯,床,桌,椅,杯子,饮水机……]这些器具中挑选,从而组成这个房间的装潢。我们可能会设计一个房间表,再设计一个器具表,再设计一个关系表,通过这个关系表来保存它们之间的对应关系。但是这样的效率明显是比较差的,需要同时查询三张表才能完成。
为了不适用关系表,我们还可以在房间表中设计一个字段,通过一个有规律的字符串来保存器具表的器具ID,例如:
1,2,3,7
下面,我们提供一种通过一个值来计算即可获得这一器具组合的结果,方法如下:
array(
'1' => '灯'
'2' => '床',
'4' => '桌',
'8' => '椅子',
'16' => '饮水机',
……
);
如果我们将5保存到数据库中,我们可以立马知道,这个房间有“灯”和“桌”,而如果保存的是23,则一定有“灯”“床”“桌”和“饮水机”。
给每一个器具一个给定的值,这个值一定是2的n次方(n>=0),这样就可以保证相加之后的值可以反解。这个情况的核心原理在于,给定任何数值的前面数值相加和,一定小于当前数值。如何进行反解呢?
例如我们拿到一个值为N,那么我们可以首先找到最大的2^n,确定2^n是一定有的,如果没有2^n,就不可能相加得到N。
接下来我们获得M = N - 2^n,找到最大的2^m,再进行M - 2^m,如此推论下去,直到减完为止。
那么怎获得最大的2^n呢?
$n = (int)log(N,2);
log函数在PHP4+之后内置,用于取对数,返回值为float类型,但我们仅需要整数部分,因此前面加(int)。
例如N=22,那么$n=4,再去计算2^4,就是16。
通过这个方法,我们可以非常顺利的在一个数据表中用一个值保存多种情况。但是,这也有一定的适用范围,比如这些情况最好是固定不变的,2n值不能太大等等。通过这种方法可以用该值进行权重设计,进行排序,但是不能用于条件检索,比如你想检索数据库中包含“床”的房间,你就不好进行检索,因为大部分房间的该值可能都大于2.所以,在使用这种方法时,应该根据实际需要进行考虑。
更新:
在数据库中,我们可以使用一种序列化的类二进制字符串来保存多个值,当这个二进制值是以01组成时,实际上就可以换算成为一个十进制数