mySQL SELECT行,其中设置了整数的特定位

时间:2012-02-02 18:47:34

标签: mysql select integer bit

我必须在发布表中执行select查询,其中设置了整数的特定位。 整数表示位掩码中的一组类别: E.g。

1 => health
2 => marketing
3 => personal
4 => music
5 => video
6 => design
7 => fashion
8 => ......

数据示例:

id | categories | title
1  | 11         | bla bla
2  | 48         | blabla, too

我需要一个mysql查询来选择标记为特定类别的帖子。 让我们说“所有视频帖子” 这意味着我需要一个贴子结果集,其中设置了catgories列的第5位(例如16,17,48 ....)

SELECT * FROM postings WHERE ....????

有什么想法吗?

3 个答案:

答案 0 :(得分:11)

您可以像这样使用bitwise运算符。对于视频(第5位):

WHERE categories & 16 = 16

为每个位使用以下值替换值16

1 = 1
2 = 2
3 = 4
4 = 8
5 = 16
6 = 32
7 = 64
8 = 128

这从最低位到最高位,这与大多数程序员的想法相反。它们也从零开始。

答案 1 :(得分:3)

怎么样

SELECT * FROM postings WHERE (categories & 16) > 0; -- 16 is 5th bit over

这个问题的一个问题是你可能不会遇到索引,因此如果数据量很大,你可能会遇到性能问题。

某些数据库(例如PostgreSQL)允许您在这样的表达式上定义索引。我不确定mySQL是否具有此功能。如果这很重要,您可能需要考虑将这些分解为单独的布尔列或新表。

答案 2 :(得分:-2)

SQL(不仅仅是mySQL)不适合按位操作。如果你按位进行AND,你将强制进行表扫描,因为SQL将无法使用任何索引,并且必须一次检查每一行。

如果你创建一个单独的“Categories”表和一个正确索引的多对多PostingCategories表来连接这两个表会更好。

<强>更新

对于坚持认为位图字段不是问题的人来说,检查Joe Celko的BIT of a Problem是有帮助的。在文章的底部是由位图引起的严重问题列表。

关于全面陈述不正确的评论,注意#10 - 它打破了1NF所以是的,位图字段是坏的:

  1. 数据无法读取。 ...
  2. 约束是一个b ####来写....
  3. 每个字段限制为两个值。这是非常严格的;甚至ISO性别代码也不适合这样的专栏......
  4. 位掩码(或单个位标志)没有时间元素。例如,标志“is_legal_adult_flg”...出生日期的日期(仅3个字节)将保持完整的事实,让我们计算我们需要知道的东西;它也总是正确的。 ...
  5. 你会发现使用这些标志会倾向于将实体的状态分成多个表....
  6. 位标志邀请冗余。在我刚才提到的系统中,我们在同一个表中有“is_active_flg”和“is_completed_flg”。完成的拍卖不活跃,反之亦然。在两面旗帜中也是如此。人类心理学(和英语)更倾向于听到肯定的措辞(记住老歌“是的,我们今天没有香蕉!”)。 所有这些位标志和序列验证都被两组状态转换表替换,一组用于出价,一组用于出货。有关状态转换约束的详细信息。每次拍卖的历史现在都在一个地方,必须遵守商业规则。
  7. 当您反汇编位掩码列并丢弃不需要性能的字段时,不会比简单的数据类型改进。
  8. 对各个领域进行分组和排序真是一件痛苦的事。试试吧。
  9. 你必须为整个列编制索引,所以除非你运气好并按正确的顺序排列,否则你会遇到表扫描。
  10. 由于位掩码不在First Normal Form(1NF)中,因此您可以在RDBMS中避免我们想要避免的所有异常。
  11. 我还要补充一下,NULL怎么样? 缺少标志怎么样?如果某事既不是真的也不是假的呢?

    最后,关于压缩声明,大多数数据库在内部将位字段打包为字节和整数。在这种情况下,位图字段不提供任何类型的压缩。其他数据库(例如PostgreSQL)实际上有一个布尔类型,可以是true / false / unknown。它可能需要1个字节,但大量存储,如果表格太大,则可以使用透明压缩。

    事实上,如果一个表变大,位图字段问题会变得更加严重。如果您被迫使用表扫描,或者如果您失去分组能力,则在GB表中保存几MB是没有益处的