给出以下示例数据:
mysql> select * from test2;
+-------+--------+
| name | status |
+-------+--------+
| bob | 0 |
| jim | 2 |
| karen | 5 |
| jane | 1 |
| roy | 7 |
+-------+--------+
我想提出一个查询,它会将状态列的值拆分为整数的每个位的伪布尔值列。
我现在要做的是让应用程序生成一个查询,该查询使用case语句和每列的按位和运算符来获取结果,如下所示:
mysql> select
-> name,
-> (case when (status & 1) then 'yes' else 'no' end) as bit1,
-> (case when (status & 2) then 'yes' else 'no' end) as bit2,
-> (case when (status & 4) then 'yes' else 'no' end) as bit4,
-> (case when (status & 8) then 'yes' else 'no' end) as bit8
-> from test2;
+-------+------+------+------+------+
| name | bit1 | bit2 | bit4 | bit8 |
+-------+------+------+------+------+
| bob | no | no | no | no |
| jim | no | yes | no | no |
| karen | yes | no | yes | no |
| jane | yes | no | no | no |
| roy | yes | yes | yes | no |
+-------+------+------+------+------+
5 rows in set (0.00 sec)
现在这种方法很有效,并且因为没有子查询或连接而有效,但它不是很优雅。
我想要一个更优雅的解决方案来动态地执行此操作,而无需创建case语句并测试每一位。
这是只有几位的示例数据,但在实现中,将会有数万行,还有更多可以设置的位。
加成:
将列的生成(列名和测试)基于包含每个位定义的表,如下所示:
mysql> select * from bit_spec;
+-----+------+
| bit | desc |
+-----+------+
| 1 | bit1 |
| 2 | bit2 |
| 4 | bit3 |
| 8 | bit4 |
+-----+------+
目前,应用程序处理这个问题,并不是要求MySQL服务器完成此处理的硬性要求,但如果是的话,这将是有利的。
这里是包含示例数据的SQL Fiddle,示例位定义表和我当前的解决方案。
答案 0 :(得分:2)
这可以通过将每个用户/位/值组合检索到行中然后将这些行旋转到列中来实现。
select
name,
`desc`,
((status & bit) > 0) value
from test2, bit_spec
上述查询以下列格式生成结果
name | desc | value
bob | bit1 | 0
bob | bit2 | 0
从这里我们可以将结果转换为所需的格式,其中每个desc
/ value
对转换为名为desc
的列,其值为value
。
使用以下帖子https://stackoverflow.com/a/12005676/3574819
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT
CONCAT(
'SUM(case when `desc` = ''',
`desc`,
''' then value end) AS ',
replace(`desc`, ' ', '')
)
) INTO @sql
from bit_spec;
SET @sql = CONCAT('SELECT t1.name, ', @sql, ' from
(select
name,
`desc`,
((status & bit) > 0) value
from test2, bit_spec) t1
group by t1.name
order by t1.name');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
http://sqlfiddle.com/#!2/5f6d0/22
NAME BIT1 BIT2 BIT3 BIT4
bob 0 0 0 0
jane 1 0 0 0
jim 0 1 0 0
karen 1 0 1 0
roy 1 1 1 0
<强>旁注强>
如果你需要按权限搜索(即显示所有拥有bit1&amp; bit2但不是bit3的用户),那么我不建议将你的权限存储为一个整数中的位,因为db不能索引结果。在这种情况下,由列(user_id,permission_id)组成的索引连接表将产生更快的结果。