文档首页
MySQL 9.0 参考手册
相关文档 下载本手册
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
信息 (Gzip) - 4.0Mb
信息 (Zip) - 4.0Mb


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

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 命令行客户端”

  • <<

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

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

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

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

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

    有关详细信息,请参阅本节的介绍性讨论。

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

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

  • >>

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

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

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

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

    移出值末尾的位将丢失,不会发出警告,无论参数类型如何。特别是,如果移位计数大于或等于位参数中的位数,则结果中的所有位都为 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 9.0 直接处理二进制字符串参数(不进行转换),并生成二进制字符串结果。非整数或二进制字符串的参数将转换为整数。

算作二进制字符串的参数包括列值、例程参数、局部变量和用户定义的变量,它们具有二进制字符串类型: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') ;

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

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

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

注意

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;

通过向左或向右移动全 1 地址来构造网络和主机掩码。为此,请从地址 :: 开始,它是所有零的简写,您可以通过将其转换为如下所示的二进制字符串来查看

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

要生成补码值(全 1),请使用 ~ 运算符反转位

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

向左或向右移动全 1 值以生成网络和主机掩码

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 |
+------------------+

前面的示例使用了以下位运算:取反(~)、左移(<<)和按位 AND(&)。

接下来的讨论将详细介绍每组位运算的参数处理,以及有关位运算中字面值处理的更多信息。

按位 AND、OR 和 XOR 运算

对于 &|^ 位运算,结果类型取决于参数是作为二进制字符串还是数字进行计算

  • 当参数具有二进制字符串类型,并且其中至少一个不是十六进制字面量、位字面量或 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 9.0 会在数字上下文中计算位运算。也就是说,如果所有位参数都是未加修饰的十六进制字面量、位字面量或 NULL 字面量,则对二进制字符串位参数的位运算不使用二进制字符串计算。(如果此类字面量是用 _binary 引导符、BINARY 运算符或其他明确将其指定为二进制字符串的方法编写的,则不适用。)

示例

  • 这些位运算在数字上下文中计算字面量,并生成 BIGINT 结果

    b'0001' | b'0010'
    X'0008' << 8
  • 这些位运算在数字上下文中计算 NULL,并生成值为 NULLBIGINT 结果

    NULL & NULL
    NULL >> 4

您可以通过明确指示至少一个参数是二进制字符串来使这些运算在二进制字符串上下文中计算参数

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

最后两个表达式的结果是 NULL,与没有 BINARY 运算符时相同,但结果的数据类型是二进制字符串类型而不是整数类型。