Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/78.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用MySQL存储和修改位图/位集?_Mysql_Sql_Bit Manipulation_Rdbms_Bitset - Fatal编程技术网

如何使用MySQL存储和修改位图/位集?

如何使用MySQL存储和修改位图/位集?,mysql,sql,bit-manipulation,rdbms,bitset,Mysql,Sql,Bit Manipulation,Rdbms,Bitset,我想创建一个表列,用于存储500字节位图500字节*8位/字节=4000位,并对位图中某些索引处设置为1或0的位进行变异操作 然而,这只剩下我作为唯一的向导。如何在MySQL中创建、计数、读取和更改位图作为列类型 使用bin和lpad,您可以将64位数字打印为二进制字符串 LPAD(BIN(34), 64, '0') 0000000000000000000000000000000000000000000000000000000000100010 但是,如何打印可能有4000位长的二进制/blo

我想创建一个表列,用于存储500字节位图500字节*8位/字节=4000位,并对位图中某些索引处设置为1或0的位进行变异操作

然而,这只剩下我作为唯一的向导。如何在MySQL中创建、计数、读取和更改位图作为列类型

使用bin和lpad,您可以将64位数字打印为二进制字符串

LPAD(BIN(34), 64, '0')
0000000000000000000000000000000000000000000000000000000000100010
但是,如何打印可能有4000位长的二进制/blob/varbinary字符串


注意:先不要谈论位图索引,升级到MySQL 8.0。这在早期版本的MySQL上不起作用

根据要存储的位字段的长度,应该使用BINARY、VARBINARY或BLOB

mysql> create table mytable ( bits binary(500) );
ERROR 1074 (42000): Column length too big for column 'bits' (max = 255); use BLOB or TEXT instead

mysql> create table mytable ( bits blob(500) );
Query OK, 0 rows affected (0.02 sec)
使用UNHEX从十六进制字符串形成位字段。直接使用二进制字节太难了

mysql> insert into mytable set bits = unhex(repeat('00', 500));
Query OK, 1 row affected (0.00 sec)
可以对位字段使用|、&、^和~等位运算符。但是字符串的长度必须相同

mysql> update mytable set bits = bits | b'01000';
ERROR 3513 (HY000): Binary operands of bitwise operators must be of equal length
这很不方便,但必须使用CONCAT形成长度正确的字符串:

mysql> update mytable set bits = bits | unhex(concat(repeat('00', 498), 'ffff'));
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0
读取位字符串时,我已将其缩短为此显示:

mysql> select hex(bits) from mytable\G
*************************** 1. row ***************************
hex(bits): 000...000FFFF
BIT_COUNT函数的工作原理是:

mysql> select bit_count(bits) from mytable;
+-----------------+
| bit_count(bits) |
+-----------------+
|              16 |
+-----------------+

mysql> select bit_count(~bits) from mytable;
+------------------+
| bit_count(~bits) |
+------------------+
|             3984 |
+------------------+

此时,您应该坐下来考虑SQL是否是完成此任务的最佳工具,即使有MySQL 8.0的功能。您会发现在大多数其他编程语言中按位工作更灵活、更强大。

使用BLOB作为数据类型,并编写一个函数,该函数将:

提取需要更新的字节 更改字节中的位 将更改后的字节插入blob的原始位置 以下是一个实现:

delimiter //
create function set_bit(b blob, pos int, val int) returns blob reads sql data
comment 'changes the bit at position <pos> (0: right most bit) to <val> in the blob <b>'
begin
    declare len int;      -- byte length of the blob
    declare byte_pos int; -- position of the affected byte (1: left most byte)
    declare bit_pos  int; -- position within the affected byte (0: right most bit)
    declare byte_val int; -- value of the affected byte

    set len = length(b);
    set byte_pos = len - (pos div 8);
    set bit_pos = pos mod 8;
    set byte_val = ord(substring(b, byte_pos, 1)); -- read the byte
    set byte_val = byte_val & (~(1 << bit_pos));   -- set the bit to 0
    set byte_val = byte_val | (val << bit_pos);    -- set the bit to <val>

    return insert(b, byte_pos, 1, char(byte_val)); -- replace the byte and return
end //
delimiter ;
我们有两个blob位掩码,每个3字节-一个满0,一个满1。在这两种情况下,我们将位从右至1的第11位设置为位置10,将位从右至0的第12位设置为位置11

结果:

| id  | hex(b) | to_base2(b)                |
| --- | ------ | -------------------------- |
| 1   | 000400 | 00000000 00000100 00000000 |
| 2   | FFF7FF | 11111111 11110111 11111111 |
注意:to_base2是一个自定义函数,它返回一个带有BLOB位表示的字符串,仅用于表示目的

这适用于MySQL 5.x和8.0

可以在单个表达式中内联实现它,而不需要函数-但这是不可读的:

update test t
cross join (select 10 as pos, 1 as val) i -- input
set t.b = insert(
  t.b,
  length(t.b) - (i.pos div 8),
  1,
  char(ord(
    substring(t.b, length(t.b) - (i.pos div 8), 1))
    & ~(1 << (i.pos mod 8))
    | (i.val << (i.pos mod 8)
  ))
);
在MySQL 8.0中更简单一些,因为我们不需要提取字节,可以对blob使用位操作。但我们需要确保Operand的长度相同:

update test t
cross join (select 10 as pos, 1 as val) i -- input
set t.b = t.b
  & (~(concat(repeat(0x00,length(t.b)-1),char(1)) << i.pos))
  | (concat(repeat(0x00,length(t.b)-1),char(i.val)) << i.pos) 
另一种方式:

update test t
cross join (select 10 as pos, 1 as val) i -- input
set t.b = 
  case when i.val = 1
    then t.b | concat(repeat(0x00,length(t.b)-1),char(1)) << i.pos
    else t.b & ~(concat(repeat(0x00,length(t.b)-1),char(1)) << i.pos)
  end

我认为您需要使用varbinary或blob数据类型,没有公开的位图数据类型。将位图另存为blob,使用php和tp转换并编辑nitmaps和fd,然后再次保存有什么意义?您也可以更改一个图像,并将其与文件内容一起保存。@nbk这个问题与图像或PHP无关。我在系统的其余部分使用RDBMS,因此让MySQL处理位图/位集/位数组将使我不必为了设置/取消设置一个位而缩减500字节。显然,对于MariaDB/MySQL来说,这比我最初想象的要困难得多。我不确定我是否准备好只为这一个字段使用键/值存储。我理解您不愿意让堆栈更复杂,但这并不能改变MySQL没有好的函数来完成您想要做的事情的事实。@Xeoncross update mytable set bits=bits | b'01000'有什么问题;按照建议?你不必用这个来拉取500字节,我已经尝试过了,它在数千条记录上用SELECT和UPDATE都能很好地工作。我甚至让它与BLOB数据类型和SQLite一起工作。错误消息解释了这一点。两个操作数的长度必须相同,但在本例中,位的长度为500字节,右侧操作数的长度为1字节。感谢您的详细回答。我最近有点忙,错过了。我会开始第二次悬赏来奖励你。
update test t
cross join (select 10 as pos, 1 as val) i -- input
set t.b = t.b
  & (~(concat(repeat(0x00,length(t.b)-1),char(1)) << i.pos))
  | (concat(repeat(0x00,length(t.b)-1),char(i.val)) << i.pos) 
update test t
cross join (select 10 as pos, 1 as val) i -- input
set t.b = 
  case when i.val = 1
    then t.b | concat(repeat(0x00,length(t.b)-1),char(1)) << i.pos
    else t.b & ~(concat(repeat(0x00,length(t.b)-1),char(1)) << i.pos)
  end