我有一个名为warnings的bitfield存储为int。 我想获得每个人的警告列表
假设我们有一张桌子
NAME, WARNINGS
alex, 0
mike, 5
sarah, 2
其中整数的每个位对应一个警告#(位位置)。 目前这是在带有for循环的perl中完成的
for(my $i=0; $i < $warning_size;$i++ ){
if( (1 << $i ) & $warning != 0){
print "$name\t" . $i+1 ."\n";
}
}
有没有办法可以通过mysql查询处理这个问题。
对于上面的例子,我想要以下输出:
name, warning
-------------
mike 1
mike 3
sarah 2
我试图将其归结为一个选择语句,
由于
答案 0 :(得分:2)
试试这个 -
CREATE TABLE warn_bits(
b INT(11) NOT NULL
);
INSERT INTO warn_bits VALUES
(1),
(2),
(3),
(4),
(5),
(6),
(7),
(8);
SELECT w.name, wb.b FROM warnings w
JOIN warn_bits wb
ON ((w.WARNINGS >> wb.b - 1) & 1) > 0
ORDER BY w.name, wb.b;
+-------+---+
| name | b |
+-------+---+
| mike | 1 |
| mike | 3 |
| sarah | 2 |
+-------+---+
您可以扩展warn_bits
表以支持INT或BIGINT数字。
<强> EDIT2 强>
SELECT w.name, wb.b FROM warnings w
JOIN (
SELECT 1 b UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION
SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8
) wb
ON ((w.WARNINGS >> wb.b - 1) & 1) > 0
ORDER BY w.name, wb.b;
答案 1 :(得分:0)
制作临时表以进行压碎。
mysql> create table bitcrush( bit int );
Query OK, 0 rows affected (0.02 sec)
mysql> insert into bitcrush values (1),(2),(4),(8),(16),(32),(64),(128),(256);
Query OK, 8 rows affected (0.01 sec)
Records: 8 Duplicates: 0 Warnings: 0
mysql> select name, log2(bit)+1 as warn from c821885 join bitcrush on warn & bit order by name;
+-------+------+
| name | warn |
+-------+------+
| mike | 1 |
| mike | 3 |
| sarah | 2 |
+-------+------+
3 rows in set (0.00 sec)
答案 2 :(得分:0)
我认为你只是在寻找power(2, x);
,试试这个: -
mysql> select length(conv(0, 10, 2)); +------------------------+ | length(conv(0, 10, 2)) | +------------------------+ | 1 | +------------------------+ 1 row in set (0.00 sec) mysql> select length(conv(2, 10, 2)); +------------------------+ | length(conv(2, 10, 2)) | +------------------------+ | 2 | +------------------------+ 1 row in set (0.00 sec) mysql> select length(conv(5, 10, 2)); +------------------------+ | length(conv(5, 10, 2)) | +------------------------+ | 3 | +------------------------+ 1 row in set (0.00 sec)
答案 3 :(得分:0)
如果您确定每个警告都有一列,您还可以使用export_set()和substring()来分解这些位。
我假设您正在使用4位。
bit 1 = "fatal"
bit 2 = "warning"
bit 3 = "error"
bit 4 = "user error"
SELECT
name,
EXPORT_SET(warning,1,0,'',4) AS debugBits,
SUBSTRING(EXPORT_SET(warning,1,0,'',4),1,1) AS hasFatal,
SUBSTRING(EXPORT_SET(warning,1,0,'',4),2,1) AS hasWarning,
SUBSTRING(EXPORT_SET(warning,1,0,'',4),3,1) AS hasError,
SUBSTRING(EXPORT_SET(warning,1,0,'',4),4,1) AS hasUserError
FROM warnings;
应该输出如下内容:
------|----------|---------|-----------|---------|-------------|
name |debugBits | hasFatal| hasWarning| hasError| hasUserError|
alex | 0000| 0| 0| 0| 0|
mike | 1010| 1| 0| 1| 0|
sarah | 0010| 0| 0| 1| 0|
------|----------|---------|-----------|---------|-------------|
请注意,export_set()会在最左侧显示第1位。 http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_export-set
如果您对警告的CSV列没有问题,可以使用make_set()
SELECT
name,
MAKE_SET(warning,
'fatal',
'warning',
'error',
'userError') AS warningText
FROM warnings
这将为您提供一列警告,其中包含设置位标签的CSV列表。 http://dev.mysql.com/doc/refman/5.5/en/string-functions.html#function_make-set