Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  Functions and Operators  /  Bit Functions and Operators

14.12 位函数和操作符

表 14.17 位函数和操作符

名称 描述
& 按位与
>> 右移位
<< 左移位
^ 按位异或
BIT_COUNT() 返回设置的位数
| 按位或
~ 按位反转

以下列表描述了可用的位函数和操作符:

  • |

    按位或。

    结果类型取决于参数是否被评估为二进制字符串或数字:

    • 二进制字符串评估发生在参数具有二进制字符串类型,并且至少有一个不是十六进制文字、位文字或 NULL 文字时。数字评估发生在其他情况下,必要时将参数转换为无符号 64 位整数。

    • 二进制字符串评估产生与参数相同长度的二进制字符串。如果参数长度不相等,将发生 ER_INVALID_BITWISE_OPERANDS_SIZE 错误。数字评估产生无符号 64 位整数。

    有关更多信息,请参阅本节的引言讨论。

    mysql> SELECT 29 | 15;
            -> 31
    mysql> SELECT _binary X'40404040' | X'01020304';
            -> 'ABCD'

    如果从 mysql 客户端调用按位或操作符,二进制字符串结果将以十六进制表示法显示,取决于 --binary-as-hex 选项的值。有关该选项的更多信息,请参阅 第 6.5.1 节,“mysql — MySQL 命令行客户端”

  • &

    按位与。

    结果类型取决于参数是否被评估为二进制字符串或数字:

    • 当参数具有二进制字符串类型,并且至少有一个不是十六进制文字、位文字或NULL文字时,二进制字符串评估就会发生。否则,将进行数字评估,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估将生成与参数相同长度的二进制字符串。如果参数的长度不相等,将发生ER_INVALID_BITWISE_OPERANDS_SIZE错误。数字评估将生成无符号的64位整数。

    有关更多信息,请参阅本节的引言讨论。

    mysql> SELECT 29 & 15;
            -> 13
    mysql> SELECT HEX(_binary X'FF' & b'11110000');
            -> 'F0'

    如果从mysql客户端内部调用按位与操作,二进制字符串结果将使用十六进制表示法显示,取决于--binary-as-hex选项的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”

  • ^

    按位异或。

    结果类型取决于参数是否被评估为二进制字符串或数字:

    • 当参数具有二进制字符串类型,并且至少有一个不是十六进制文字、位文字或NULL文字时,二进制字符串评估就会发生。否则,将进行数字评估,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估将生成与参数相同长度的二进制字符串。如果参数的长度不相等,将发生ER_INVALID_BITWISE_OPERANDS_SIZE错误。数字评估将生成无符号的64位整数。

    有关更多信息,请参阅本节的引言讨论。

    mysql> SELECT 1 ^ 1;
            -> 0
    mysql> SELECT 1 ^ 0;
            -> 1
    mysql> SELECT 11 ^ 3;
            -> 8
    mysql> SELECT HEX(_binary X'FEDC' ^ X'1111');
            -> 'EFCD'

    如果从mysql客户端内部调用按位异或操作,二进制字符串结果将使用十六进制表示法显示,取决于--binary-as-hex选项的值。有关该选项的更多信息,请参阅第 6.5.1 节,“mysql — MySQL 命令行客户端”

  • <<

    将长整数(BIGINT)或二进制字符串左移。

    结果类型取决于位参数是否被评估为二进制字符串或数字:

    • 二进制字符串评估将发生,当位参数具有二进制字符串类型,并且不是十六进制文字、位文字或NULL文字时。否则,将进行数字评估,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估产生与位参数相同长度的二进制字符串。数字评估产生无符号的64位整数。

    超出值末端的位将被丢弃,不管参数类型如何。特别是,如果shift计数大于或等于位参数中的位数,则结果中的所有位都是0。

    有关更多信息,请参阅本节的引言讨论。

    mysql> SELECT 1 << 2;
            -> 4
    mysql> SELECT HEX(_binary X'00FF00FF00FF' << 8);
            -> 'FF00FF00FF00'

    如果从mysql客户端内部调用位移,二进制字符串结果将以十六进制表示法显示,取决于--binary-as-hex选项的值。有关该选项的更多信息,请参阅第6.5.1节,“mysql — MySQL命令行客户端”

  • >>

    将长整数(BIGINT)或二进制字符串向右移位。

    结果类型取决于位参数是否被评估为二进制字符串或数字:

    • 二进制字符串评估发生在位参数具有二进制字符串类型且不是十六进制文字、位文字或NULL文字时。数字评估发生在其他情况下,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估产生与位参数相同长度的二进制字符串。数字评估产生无符号的64位整数。

    超出值末端的位将被丢弃,不管参数类型如何。特别是,如果shift计数大于或等于位参数中的位数,则结果中的所有位都是0。

    有关更多信息,请参阅本节的引言讨论。

    mysql> SELECT 4 >> 2;
            -> 1
    mysql> SELECT HEX(_binary X'00FF00FF00FF' >> 8);
            -> '0000FF00FF00'

    如果从mysql客户端内部调用位移,二进制字符串结果将以十六进制表示法显示,取决于--binary-as-hex选项的值。有关该选项的更多信息,请参阅第6.5.1节,“mysql — MySQL命令行客户端”

  • ~

    反转所有位。

    结果类型取决于位参数是否被评估为二进制字符串或数字:

    • 二进制字符串评估发生在位参数具有二进制字符串类型且不是十六进制文字、位文字或NULL文字时。数字评估发生在其他情况下,必要时将参数转换为无符号的64位整数。

    • 二进制字符串评估产生与位参数相同长度的二进制字符串。数字评估产生无符号的64位整数。

    有关更多信息,请参阅本节的引言讨论。

    mysql> SELECT 5 & ~1;
            -> 4
    mysql> SELECT HEX(~X'0000FFFF1111EEEE');
            -> 'FFFF0000EEEE1111'

    如果从 mysql 客户端内部调用按位反转,则二进制字符串结果将以十六进制表示,取决于 --binary-as-hex 选项的值。有关该选项的更多信息,请参见 第 6.5.1 节,“mysql — MySQL 命令行客户端”

  • BIT_COUNT(N)

    返回参数 N 中设置的位数作为无符号 64 位整数,或者如果参数为 NULL 则返回 NULL

    mysql> SELECT BIT_COUNT(64), BIT_COUNT(BINARY 64);
            -> 1, 7
    mysql> SELECT BIT_COUNT('64'), BIT_COUNT(_binary '64');
            -> 1, 7
    mysql> SELECT BIT_COUNT(X'40'), BIT_COUNT(_binary X'40');
            -> 1, 1

位函数和操作符包括 BIT_COUNT()BIT_AND()BIT_OR()BIT_XOR()&|^~<<>>。(BIT_AND()BIT_OR()BIT_XOR() 聚合函数在 第 14.19.1 节,“聚合函数描述” 中描述。)

位函数和操作符允许二进制字符串类型参数(BINARYVARBINARYBLOB 类型),并返回相同类型的值。非二进制字符串参数将被转换为 BIGINT

位操作

MySQL 8.3 直接处理二进制字符串参数(不进行转换)并生成二进制字符串结果。不是整数或二进制字符串的参数将被转换为整数。

二进制字符串参数包括列值、routine 参数、本地变量和用户定义变量,这些变量具有二进制字符串类型:BINARYVARBINARYBLOB 类型。

您可以使用十六进制字面量或位字面量指定位操作的参数,以便它们表示数字;MySQL 在所有位参数都是十六进制字面量或位字面量时,在数字上下文中评估位操作。要将其评估为二进制字符串,请使用 _binary 引入符至少一个字面量值。

  • 这些位操作将十六进制字面量和位字面量评估为整数:

    mysql> SELECT X'40' | X'01', b'11110001' & b'01001111';
    +---------------+---------------------------+
    | X'40' | X'01' | b'11110001' & b'01001111' |
    +---------------+---------------------------+
    |            65 |                        65 |
    +---------------+---------------------------+
  • 这些位操作将十六进制字面量和位字面量评估为二进制字符串,因为 _binary 引入符的存在:

    mysql> SELECT _binary X'40' | X'01', b'11110001' & _binary b'01001111';
    +-----------------------+-----------------------------------+
    | _binary X'40' | X'01' | b'11110001' & _binary b'01001111' |
    +-----------------------+-----------------------------------+
    | A                     | A                                 |
    +-----------------------+-----------------------------------+

尽管这两个语句的位操作产生的结果都是数字值 65,但第二个语句在二进制字符串上下文中操作,对于 ASCII 字符 A

在数字评估上下文中,十六进制字面量和位字面量参数的最大值为 64 位,结果也是如此。相比之下,在二进制字符串评估上下文中,参数(和结果)可以超过 64 位:

mysql> SELECT _binary X'4040404040404040' | X'0102030405060708';
+---------------------------------------------------+
| _binary X'4040404040404040' | X'0102030405060708' |
+---------------------------------------------------+
| ABCDEFGH                                          |
+---------------------------------------------------+

有多种方式可以在位操作中引用十六进制字面量或位字面量,以便在二进制字符串上下文中评估:

_binary literal
BINARY literal
CAST(literal AS BINARY)

另一种方式是将十六进制字面量或位字面量分配给用户定义变量,这将生成具有二进制字符串类型的变量:

mysql> SET @v1 = X'40', @v2 = X'01', @v3 = b'11110001', @v4 = b'01001111';
mysql> SELECT @v1 | @v2, @v3 & @v4;
+-----------+-----------+
| @v1 | @v2 | @v3 & @v4 |
+-----------+-----------+
| A         | A         |
+-----------+-----------+

在二进制字符串上下文中,位操作参数必须具有相同的长度,否则将出现 ER_INVALID_BITWISE_OPERANDS_SIZE 错误:

mysql> SELECT _binary X'40' | X'0001';
ERROR 3513 (HY000): Binary operands of bitwise
operators must be of equal length

要满足相同长度的要求,可以使用前导零位填充较短的值,或者,如果较长的值以前导零位开始,并且较短的结果值是可接受的,可以剥离它们:

mysql> SELECT _binary X'0040' | X'0001';
+---------------------------+
| _binary X'0040' | X'0001' |
+---------------------------+
|  A                        |
+---------------------------+
mysql> SELECT _binary X'40' | X'01';
+-----------------------+
| _binary X'40' | X'01' |
+-----------------------+
| A                     |
+-----------------------+

填充或剥离也可以使用函数来实现,例如 LPAD(), RPAD(), SUBSTR(), 或 CAST()。在这种情况下,表达式参数不再都是文字,因此 _binary 变得不必要。示例:

mysql> SELECT LPAD(X'40', 2, X'00') | X'0001';
+---------------------------------+
| LPAD(X'40', 2, X'00') | X'0001' |
+---------------------------------+
|  A                              |
+---------------------------------+
mysql> SELECT X'40' | SUBSTR(X'0001', 2, 1);
+-------------------------------+
| X'40' | SUBSTR(X'0001', 2, 1) |
+-------------------------------+
| A                             |
+-------------------------------+

另见 十六进制文字、位文字和 NULL 文字的特殊处理

二进制字符串位操作示例

以下示例演示了使用位操作来提取 UUID 值的部分,例如时间戳和 IEEE 802 节点号。这种技术需要每个提取部分的位掩码。

将文本 UUID 转换为相应的 16 字节二进制值,以便在二进制字符串上下文中使用位操作:

mysql> SET @uuid = UUID_TO_BIN('6ccd780c-baba-1026-9564-5b8c656024db');
mysql> SELECT HEX(@uuid);
+----------------------------------+
| HEX(@uuid)                       |
+----------------------------------+
| 6CCD780CBABA102695645B8C656024DB |
+----------------------------------+

构建时间戳和节点号部分的位掩码。时间戳由前三个部分组成(64 位,位 0 到 63),节点号是最后一个部分(48 位,位 80 到 127):

mysql> SET @ts_mask = CAST(X'FFFFFFFFFFFFFFFF' AS BINARY(16));
mysql> SET @node_mask = CAST(X'FFFFFFFFFFFF' AS BINARY(16)) >> 80;
mysql> SELECT HEX(@ts_mask);
+----------------------------------+
| HEX(@ts_mask)                    |
+----------------------------------+
| FFFFFFFFFFFFFFFF0000000000000000 |
+----------------------------------+
mysql> SELECT HEX(@node_mask);
+----------------------------------+
| HEX(@node_mask)                  |
+----------------------------------+
| 00000000000000000000FFFFFFFFFFFF |
+----------------------------------+

这里使用 CAST(... AS BINARY(16)) 函数,因为掩码必须与 UUID 值相同长度。可以使用其他函数来填充掩码到所需的长度:

SET @ts_mask= RPAD(X'FFFFFFFFFFFFFFFF' , 16, X'00');
SET @node_mask = LPAD(X'FFFFFFFFFFFF', 16, X'00') ;

使用掩码来提取时间戳和节点号部分:

mysql> SELECT HEX(@uuid & @ts_mask) AS 'timestamp part';
+----------------------------------+
| timestamp part                   |
+----------------------------------+
| 6CCD780CBABA10260000000000000000 |
+----------------------------------+
mysql> SELECT HEX(@uuid & @node_mask) AS 'node part';
+----------------------------------+
| node part                        |
+----------------------------------+
| 000000000000000000005B8C656024DB |
+----------------------------------+

前面的示例使用了这些位操作:右移位(>>) 和按位与(&)。

Note

UUID_TO_BIN() 函数带有一个标志,导致生成的二进制 UUID 值中的某些位重新排列。如果您使用该标志,请相应地修改提取掩码。

下一个示例使用位操作来提取 IPv6 地址的网络和主机部分。假设网络部分的长度为 80 位。那么主机部分的长度为 128 - 80 = 48 位。要提取地址的网络和主机部分,请将其转换为二进制字符串,然后在二进制字符串上下文中使用位操作。

将文本 IPv6 地址转换为相应的二进制字符串:

mysql> SET @ip = INET6_ATON('fe80::219:d1ff:fe91:1a72');

定义网络长度(以位为单位):

mysql> SET @net_len = 80;

通过左移或右移所有 ones 地址来构建网络和主机掩码。为此,开始使用地址 ::,它是所有零的简写,如下所示:

mysql> SELECT HEX(INET6_ATON('::')) AS 'all zeros';
+----------------------------------+
| all zeros                        |
+----------------------------------+
| 00000000000000000000000000000000 |
+----------------------------------+

要生成补充值(所有 ones),请使用 ~ 运算符来反转位:

mysql> SELECT HEX(~INET6_ATON('::')) AS 'all ones';
+----------------------------------+
| all ones                         |
+----------------------------------+
| FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
+----------------------------------+

将所有 ones 值左移或右移以生成网络和主机掩码:

mysql> SET @net_mask = ~INET6_ATON('::') << (128 - @net_len);
mysql> SET @host_mask = ~INET6_ATON('::') >> @net_len;

显示掩码以验证它们是否涵盖了地址的正确部分:

mysql> SELECT INET6_NTOA(@net_mask) AS 'network mask';
+----------------------------+
| network mask               |
+----------------------------+
| ffff:ffff:ffff:ffff:ffff:: |
+----------------------------+
mysql> SELECT INET6_NTOA(@host_mask) AS 'host mask';
+------------------------+
| host mask              |
+------------------------+
| ::ffff:255.255.255.255 |
+------------------------+

提取和显示地址的网络和主机部分:

mysql> SET @net_part = @ip & @net_mask;
mysql> SET @host_part = @ip & @host_mask;
mysql> SELECT INET6_NTOA(@net_part) AS 'network part';
+-----------------+
| network part    |
+-----------------+
| fe80::219:0:0:0 |
+-----------------+
mysql> SELECT INET6_NTOA(@host_part) AS 'host part';
+------------------+
| host part        |
+------------------+
| ::d1ff:fe91:1a72 |
+------------------+

前面的示例使用了这些位操作:补码 (~), 左移 (<<), 和按位与 (&).

剩下的讨论提供了每组位操作的参数处理详细信息,以及位操作中的文字值处理信息。

按位与、或和异或操作

对于 &, |, 和 ^ 位操作,结果类型取决于参数是否被评估为二进制字符串或数字:

  • 二进制字符串评估发生在参数具有二进制字符串类型,并且至少有一个参数不是十六进制文字、位文字或 NULL 文字时。数字评估发生在其他情况下,必要时将参数转换为无符号 64 位整数。

  • 二进制字符串评估产生与参数相同长度的二进制字符串。如果参数的长度不相等,将发生 ER_INVALID_BITWISE_OPERANDS_SIZE 错误。数字评估产生无符号 64 位整数。

数字评估示例:

mysql> SELECT 64 | 1, X'40' | X'01';
+--------+---------------+
| 64 | 1 | X'40' | X'01' |
+--------+---------------+
|     65 |            65 |
+--------+---------------+

二进制字符串评估示例:

mysql> SELECT _binary X'40' | X'01';
+-----------------------+
| _binary X'40' | X'01' |
+-----------------------+
| A                     |
+-----------------------+
mysql> SET @var1 = X'40', @var2 = X'01';
mysql> SELECT @var1 | @var2;
+---------------+
| @var1 | @var2 |
+---------------+
| A             |
+---------------+

按位补码和移位操作

对于 ~, <<, 和 >> 位操作,结果类型取决于位参数是否被评估为二进制字符串或数字:

  • 二进制字符串评估发生在位参数具有二进制字符串类型,并且不是十六进制文字、位文字或 NULL 文字时。数字评估发生在其他情况下,必要时将参数转换为无符号 64 位整数。

  • 二进制字符串评估产生与位参数相同长度的二进制字符串。数字评估产生无符号 64 位整数。

对于移位操作,超出值末端的位将被丢弃,不会发出警告,无论参数类型如何。特别是,如果移位计数大于或等于位参数的位数,则结果中的所有位都是 0。

数字评估示例:

mysql> SELECT ~0, 64 << 2, X'40' << 2;
+----------------------+---------+------------+
| ~0                   | 64 << 2 | X'40' << 2 |
+----------------------+---------+------------+
| 18446744073709551615 |     256 |        256 |
+----------------------+---------+------------+

二进制字符串评估示例:

mysql> SELECT HEX(_binary X'1111000022220000' >> 16);
+----------------------------------------+
| HEX(_binary X'1111000022220000' >> 16) |
+----------------------------------------+
| 0000111100002222                       |
+----------------------------------------+
mysql> SELECT HEX(_binary X'1111000022220000' << 16);
+----------------------------------------+
| HEX(_binary X'1111000022220000' << 16) |
+----------------------------------------+
| 0000222200000000                       |
+----------------------------------------+
mysql> SET @var1 = X'F0F0F0F0';
mysql> SELECT HEX(~@var1);
+-------------+
| HEX(~@var1) |
+-------------+
| 0F0F0F0F    |
+-------------+

BIT_COUNT() 操作

BIT_COUNT() 函数总是返回无符号的 64 位整数,或者如果参数为 NULL 则返回 NULL

mysql> SELECT BIT_COUNT(127);
+----------------+
| BIT_COUNT(127) |
+----------------+
|              7 |
+----------------+
mysql> SELECT BIT_COUNT(b'010101'), BIT_COUNT(_binary b'010101');
+----------------------+------------------------------+
| BIT_COUNT(b'010101') | BIT_COUNT(_binary b'010101') |
+----------------------+------------------------------+
|                    3 |                            3 |
+----------------------+------------------------------+

BIT_AND()、BIT_OR() 和 BIT_XOR() 操作

对于 BIT_AND()BIT_OR()BIT_XOR() 位函数,结果类型取决于函数参数值是否被评估为二进制字符串或数字:

  • 当参数值具有二进制字符串类型且参数不是十六进制文字、位文字或 NULL 文字时,发生二进制字符串评估。否则,发生数字评估,必要时将参数值转换为无符号 64 位整数。

  • 二进制字符串评估产生与参数值相同长度的二进制字符串。如果参数值的长度不相等,将发生 ER_INVALID_BITWISE_OPERANDS_SIZE 错误。如果参数大小超过 511 字节,将发生 ER_INVALID_BITWISE_AGGREGATE_OPERANDS_SIZE 错误。数字评估产生无符号 64 位整数。

NULL 值不会影响结果,除非所有值都是 NULL。在那种情况下,结果是一个中立值,长度与参数值的长度相同(所有位为 1 的 BIT_AND(),所有位为 0 的 BIT_OR(),和 BIT_XOR())。

示例:

mysql> CREATE TABLE t (group_id INT, a VARBINARY(6));
mysql> INSERT INTO t VALUES (1, NULL);
mysql> INSERT INTO t VALUES (1, NULL);
mysql> INSERT INTO t VALUES (2, NULL);
mysql> INSERT INTO t VALUES (2, X'1234');
mysql> INSERT INTO t VALUES (2, X'FF34');
mysql> SELECT HEX(BIT_AND(a)), HEX(BIT_OR(a)), HEX(BIT_XOR(a))
       FROM t GROUP BY group_id;
+-----------------+----------------+-----------------+
| HEX(BIT_AND(a)) | HEX(BIT_OR(a)) | HEX(BIT_XOR(a)) |
+-----------------+----------------+-----------------+
| FFFFFFFFFFFF    | 000000000000   | 000000000000    |
| 1234            | FF34           | ED00            |
+-----------------+----------------+-----------------+

十六进制文字、位文字和 NULL 文字的特殊处理

MySQL 8.3 在数字上下文中评估位操作,当所有位参数都是十六进制文字、位文字或 NULL 文字时。这意味着,位操作在二进制字符串位参数上不使用二进制字符串评估,如果所有位参数都是未修饰的十六进制文字、位文字或 NULL 文字。(这不适用于使用 _binary 介绍符、BINARY 运算符或其他方式明确指定它们为二进制字符串的文字。)

示例:

  • 这些位操作在数值上下文中评估文字并产生一个 BIGINT 结果:

    b'0001' | b'0010'
    X'0008' << 8
  • 这些位操作在数值上下文中评估 NULL 并产生一个 BIGINT 结果,该结果的值为 NULL

    NULL & NULL
    NULL >> 4

您可以通过明确指示至少一个参数是二进制字符串来使这些操作在二进制字符串上下文中评估参数:

_binary b'0001' | b'0010'
_binary X'0008' << 8
BINARY NULL & NULL
BINARY NULL >> 4

最后两个表达式的结果是 NULL,就像不使用 BINARY 运算符一样,但是结果的数据类型是二进制字符串类型,而不是整数类型。