文档首页
MySQL 8.4 参考手册
相关文档 下载此手册
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
手册页 (TGZ) - 258.5Kb
手册页 (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 参考手册  /  函数和运算符  /  位函数和运算符

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 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”.

  • &

    按位与。

    结果类型取决于参数是作为二进制字符串还是数字进行计算

    • 当参数具有二进制字符串类型,并且至少其中一个不是十六进制字面量、位字面量或 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 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”.

  • ^

    按位异或。

    结果类型取决于参数是作为二进制字符串还是数字进行计算

    • 当参数具有二进制字符串类型,并且至少其中一个不是十六进制字面量、位字面量或 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 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”.

  • <<

    将 longlong (BIGINT) 数字或二进制字符串向左移动。

    结果类型取决于位参数是作为二进制字符串还是数字进行计算

    • 当位参数具有二进制字符串类型,并且不是十六进制字面量、位字面量或 NULL 字面量时,就会进行二进制字符串计算。否则,将进行数值计算,并根据需要将参数转换为无符号 64 位整数。

    • 二进制字符串计算将生成与位参数长度相同的二进制字符串。数值计算将生成无符号 64 位整数。

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

    有关更多信息,请参阅本节中的介绍性讨论。

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

    如果在 mysql 客户端中调用位移,则二进制字符串结果将使用十六进制表示法显示,具体取决于 --binary-as-hex 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”.

  • >>

    将 longlong (BIGINT) 数字或二进制字符串向右移动。

    结果类型取决于位参数是作为二进制字符串还是数字进行计算

    • 当位参数具有二进制字符串类型,并且不是十六进制字面量、位字面量或 NULL 字面量时,就会进行二进制字符串计算。否则,将进行数值计算,并根据需要将参数转换为无符号 64 位整数。

    • 二进制字符串计算将生成与位参数长度相同的二进制字符串。数值计算将生成无符号 64 位整数。

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

    有关更多信息,请参阅本节中的介绍性讨论。

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

    如果在 mysql 客户端中调用位移,则二进制字符串结果将使用十六进制表示法显示,具体取决于 --binary-as-hex 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”.

  • ~

    反转所有位。

    结果类型取决于位参数是作为二进制字符串还是数字进行计算

    • 当位参数具有二进制字符串类型,并且不是十六进制字面量、位字面量或 NULL 字面量时,就会进行二进制字符串计算。否则,将进行数值计算,并根据需要将参数转换为无符号 64 位整数。

    • 二进制字符串计算将生成与位参数长度相同的二进制字符串。数值计算将生成无符号 64 位整数。

    有关更多信息,请参阅本节中的介绍性讨论。

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

    如果在 mysql 客户端中调用按位取反,则二进制字符串结果将使用十六进制表示法显示,具体取决于 --binary-as-hex 的值。有关该选项的更多信息,请参阅 Section 6.5.1, “mysql — The MySQL Command-Line Client”.

  • 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() 聚合函数在 Section 14.19.1, “Aggregate Function Descriptions” 中有描述。)

位函数和运算符允许二进制字符串类型参数(BINARYVARBINARYBLOB 类型)并返回类似类型的返回值。非二进制字符串参数将转换为 BIGINT

位运算

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

作为二进制字符串的参数包括具有二进制字符串类型的列值、例程参数、局部变量和用户定义变量:BINARYVARBINARY 或其中一个 BLOB 类型。

您可以使用十六进制字面量或位字面量来指定位运算的参数,它们的目的是表示数字;当所有位参数都是十六进制字面量或位字面量时,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 的结果,但第二个语句是在二进制字符串上下文中进行的,其中 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 |
+----------------------------------+

为该值的 timestamp 和 node number 部分构建位掩码。timestamp 包含前三部分(64 位,第 0 到 63 位),node number 是最后一部分(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') ;

使用掩码来提取 timestamp 和 node number 部分

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

前面的示例使用了以下位运算:右移 (>>) 和按位与 (&).

注意

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;

通过将全一地址左移或右移来构建网络和主机掩码。为此,从地址 :: 开始,它是全零的简写,您可以通过将其转换为类似的二进制字符串来查看

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

要生成互补值(全一),请使用 ~ 运算符来反转位

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

将全一值左移或右移以生成网络和主机掩码

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。在这种情况下,结果是一个中性值,其长度与参数值的长度相同(对于 BIT_AND(),所有位都是 1;对于 BIT_OR(),所有位都是 0;对于 BIT_XOR(),所有位都是 0)。

示例

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 字面量的特殊处理

当所有位参数都是十六进制字面量、位字面量或 NULL 字面量时,MySQL 8.4 在数字上下文中评估位运算。也就是说,如果所有位参数都是未修饰的十六进制字面量、位字面量或 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 运算符一样,但结果的数据类型是二进制字符串类型而不是整数类型。