将此DB称为Employees:
+--+----------------+
|ID|Ability_required|
+--+----------------+
|1 | 0000000111 |
|2 | 0000001111 |
|3 | 0000000111 |
|4 | 0000001101 |
|5 | 0000001111 |
+--+----------------+
这个SQL查询:
SELECT ID FROM `Employees`
WHERE `Ability_required` & b'0000001111' = b'0000001111'
为什么我的MYSQL会返回第1行和第3行?我在这里做错了什么?
检查图片以获取示例:
答案 0 :(得分:4)
您的Especialidad_Nails
列似乎是一个字符串数据类型,其中包含0
和1
字符的字符串。
尝试对这些字符串执行数字运算(例如按位AND)将首先导致MySQL将这些字符串转换为数字:'0000000111'
被强制转换为十进制111
,即b'1101111'
-it是这个值然后经历按位运算(并且成功!)。
如果确实想要使用位字段,则应考虑MySQL的SET
数据类型 - 它是作为表面下的位字段实现的(实际上,您可以使用按位运算)正如你试图做的那样),但也通过提供一个人性化的名称来公开一个更易于访问的界面,这个名称可以非常有效地用于FIND_IN_SET()
等操作。
也就是说,位操作不是可以理解的,并且位字段不承认关系数据库提供的许多优点。有时最好将每个位存储在自己的BOOLEAN
列中。
如果您别无选择,只能将这些位存储为字符串类型列中的字符,则可以(如@SalmanA points out)使用MySQL的CONV()
函数转换为二进制文件。
答案 1 :(得分:3)
当bitwise and对整数进行操作时,您将数字存储为字符串。 MySQL将执行隐式转换,但是,它假定字符串表示十进制数。
使用MySQL CONV
函数手动转换字符串:
SELECT * FROM `Employees`
WHERE CONV(`Ability_required`, 2, 10) & b'0000001111' = b'0000001111';
ID Ability_required
2 0000001111
5 0000001111
我建议使用INT
字段。或者如果可能,将表格标准化。
答案 2 :(得分:1)
您的ability_required列的数据类型有误。你有它们作为VARCHAR(10),它们需要是整数类型或位(x)类型。 B' 001111'只看起来像一个字符串,但它实际上是二进制表示的整数。
b'001111' = 15
b'000111' = 7
b'001101' = 13
如果您将desired_ability的列更改为INT或BIT(8)或TINYINT,那么您的查询将按预期工作。
要测试结果,请尝试
SELECT ID, (`Ability_required` & b'0000001111') FROM `Employees` WHERE `Ability_required` & b'0000001111' = b'0000001111'
你会看到你得到的不是bit_和你期望的。
这是我的测试:
CREATE TABLE `employees` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ability` int(11) DEFAULT '0',
`b_ability` bit(8) DEFAULT NULL,
`v_ability` VARCHAR(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
delete from employees;
insert into employees (ability, b_ability, v_ability) values (7, b'000111', '000111');
insert into employees (ability, b_ability, v_ability) values (15, b'001111', '001111');
insert into employees (ability, b_ability, v_ability) values (7, b'000111', '000111');
insert into employees (ability, b_ability, v_ability) values (13, b'001101', '001101');
insert into employees (ability, b_ability, v_ability) values (15, b'001111', '001111');
select *, (b'001111' & v_ability) from employees where v_ability & b'001111' = b'001111';
如果您已经拥有要保留在这些列中的数据,您可以使用函数转换它们(mysql不是我的强项,可能效率不高但函数有效):
CREATE FUNCTION `vcharbit_to_int`(bitdata varchar(16)) RETURNS int(11)
DETERMINISTIC
BEGIN
declare i INT DEFAULT length(bitdata);
declare v INT default 0;
declare b VARCHAR(1);
declare ip INT default 1;
while i > 0 do
set b := SUBSTR(bitdata, i, 1);
if b = '1' then
set v := v + ip;
END IF;
set i := i - 1;
set ip := ip * 2;
end while;
RETURN v;
END
查询:
select id, v_ability from employees where vcharbit_to_int(v_ability) & b'001111' = b'001111';
会为您提供您期望的结果。