Skip to content

Latest commit

 

History

History
310 lines (241 loc) · 11.1 KB

bit-functions-and-operators.md

File metadata and controls

310 lines (241 loc) · 11.1 KB
title aliases summary
位函数和操作符
/docs-cn/dev/functions-and-operators/bit-functions-and-operators/
/docs-cn/dev/reference/sql/functions-and-operators/bit-functions-and-operators/
TiDB 支持 MySQL 8.0 中的所有位函数和操作符。

位函数和操作符

TiDB 支持使用 MySQL 8.0 中提供的所有位函数和操作符

位函数和操作符表

函数和操作符名 功能描述
BIT_COUNT() 返回参数二进制表示中为 1 的个数
& 按位与
~ 按位取反
| 按位或
^ 按位异或
<< 左移
>> 右移

BIT_COUNT(expr) 函数返回 expr 中为 1 的位数。

SELECT BIT_COUNT(b'00101001');
+------------------------+
| BIT_COUNT(b'00101001') |
+------------------------+
|                      3 |
+------------------------+
1 row in set (0.00 sec)

注意:

当输入的 expr 参数是一个二进制数时,你需要在这个数之前显式地指定 b,比如 b'00101001'。否则,该函数会将其视为字符串处理而返回不同的结果。例如,BIT_COUNT('00101001') 会返回 7,因为它会将字符串 '00101001' 转换为十进制数 101001,并计算 101001 的二进制表示 110001000010100011 的位数。

下面的示例与前面的类似,但使用的参数是十六进制数而非二进制数。CONV() 函数用于将 0x29 从十六进制转换为二进制,可以看到 0x29 等价于二进制的 00101001

SELECT BIT_COUNT(0x29), CONV(0x29,16,2);
+-----------------+-----------------+
| BIT_COUNT(0x29) | CONV(0x29,16,2) |
+-----------------+-----------------+
|               3 | 101001          |
+-----------------+-----------------+
1 row in set (0.01 sec)

BIT_COUNT(expr) 函数的一个常见用法是将子网掩码转换为 CIDR 表示法。在下面的示例中,子网掩码 255.255.255.0 被转换为其 CIDR 表示形式 24

SELECT BIT_COUNT(INET_ATON('255.255.255.0'));
+---------------------------------------+
| BIT_COUNT(INET_ATON('255.255.255.0')) |
+---------------------------------------+
|                                    24 |
+---------------------------------------+
1 row in set (0.00 sec)

& 操作符用于执行按位与 (bitwise AND) 操作。它会比较两个数中的对应位,如果两个对应位都是 1,则结果中的对应位为 1,否则为 0。

例如,对 10101100 进行按位与操作会返回 1000,因为在这两个数中只有最左边的第一位都是 1。

  1010
& 1100
  ----
  1000

在 SQL 中,可以这样使用 & 操作符:

SELECT CONV(b'1010' & b'1000',10,2);
+------------------------------+
| CONV(b'1010' & b'1000',10,2) |
+------------------------------+
| 1000                         |
+------------------------------+
1 row in set (0.00 sec)

你可以将 & 操作符与 INET_NTOA()INET_ATON() 函数结合在一起使用,对 IP 地址和网络掩码进行按位与操作,以获取网络地址。这对于判断多个 IP 地址是否属于同一网络非常有用。

在以下示例中,使用掩码 255.255.255.0 时,IP 地址 192.168.1.1192.168.1.2 都属于同一网络 192.168.1.0/24

SELECT INET_NTOA(INET_ATON('192.168.1.1') & INET_ATON('255.255.255.0'));
+------------------------------------------------------------------+
| INET_NTOA(INET_ATON('192.168.1.1') & INET_ATON('255.255.255.0')) |
+------------------------------------------------------------------+
| 192.168.1.0                                                      |
+------------------------------------------------------------------+
1 row in set (0.00 sec)
SELECT INET_NTOA(INET_ATON('192.168.1.2') & INET_ATON('255.255.255.0'));
+------------------------------------------------------------------+
| INET_NTOA(INET_ATON('192.168.1.2') & INET_ATON('255.255.255.0')) |
+------------------------------------------------------------------+
| 192.168.1.0                                                      |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

~ 操作符用于对给定的值进行按位取反(bitwise NOT)操作。它会对给定值中的每一位进行取反:0 的位变为 1,1 的位变为 0。

在进行取反操作之前,它会先将给定的值扩展到 64 位。

以二进制数 1111000011110000 为例。当扩展到 64 位并进行取反后,其结果如下:

Original (16 bits):                                                                 1111000011110000
Expanded and inverted (64 bits):    1111111111111111111111111111111111111111111111110000111100001111

在 SQL 中,可以这样使用 ~ 操作符:

SELECT CONV(~ b'1111000011110000',10,2);
+------------------------------------------------------------------+
| CONV(~ b'1111000011110000',10,2)                                 |
+------------------------------------------------------------------+
| 1111111111111111111111111111111111111111111111110000111100001111 |
+------------------------------------------------------------------+
1 row in set (0.00 sec)

如果需要对取反后的结果再次取反,可以再次应用 ~ 操作符。

SELECT CONV(~ b'1111111111111111111111111111111111111111111111110000111100001111',10,2);
+----------------------------------------------------------------------------------+
| CONV(~ b'1111111111111111111111111111111111111111111111110000111100001111',10,2) |
+----------------------------------------------------------------------------------+
| 1111000011110000                                                                 |
+----------------------------------------------------------------------------------+
1 row in set (0.00 sec)

| 操作符用于执行按位或 (bitwise OR) 操作。它会比较两个数中的对应位,如果至少有一个对应位为 1,则结果中的对应位为 1。

例如,对 10101100 进行按位或操作会返回 1110,因为在这两个数的前三位中,至少有一个数的对应位为 1。

  1010
| 1100
  ----
  1110

在 SQL 中,可以这样使用 | 操作符:

SELECT CONV(b'1010' | b'1100',10,2);
+------------------------------+
| CONV(b'1010' | b'1100',10,2) |
+------------------------------+
| 1110                         |
+------------------------------+
1 row in set (0.00 sec)

^ 操作符用于执行按位异或 (bitwise XOR) 操作。它会比较两个数中的对应位,如果对应位不同,则结果中的对应位为 1。

例如,对 10101100 进行按位异或操作会返回 0110,因为这两个数中的第二位和第三位都不同。

  1010
^ 1100
  ----
  0110

在 SQL 中,可以这样使用 ^ 操作符:

SELECT CONV(b'1010' ^ b'1100',10,2);
+------------------------------+
| CONV(b'1010' ^ b'1100',10,2) |
+------------------------------+
| 110                          |
+------------------------------+
1 row in set (0.00 sec)

需要注意的是,由于省略了前导零,结果会显示为 110 而不是 0110

<< 操作符用于执行左移操作。它会将一个数中的所有位向左移动指定的位数,并用零填充右侧空出的位。

例如,下面的语句使用了 1<<n 将二进制数 1 向左移动了 n 位:

WITH RECURSIVE cte(n) AS (
    SELECT 0 AS n
    UNION ALL
    SELECT 1+n FROM cte WHERE n<10
)
SELECT n,1<<n,LPAD(CONV(1<<n,10,2),11,0) FROM cte;
+------+------+----------------------------+
| n    | 1<<n | LPAD(CONV(1<<n,10,2),11,0) |
+------+------+----------------------------+
|    0 |    1 | 00000000001                |
|    1 |    2 | 00000000010                |
|    2 |    4 | 00000000100                |
|    3 |    8 | 00000001000                |
|    4 |   16 | 00000010000                |
|    5 |   32 | 00000100000                |
|    6 |   64 | 00001000000                |
|    7 |  128 | 00010000000                |
|    8 |  256 | 00100000000                |
|    9 |  512 | 01000000000                |
|   10 | 1024 | 10000000000                |
+------+------+----------------------------+
11 rows in set (0.00 sec)

>> 操作符用于执行右移操作。它会将数中的所有位向右移动指定的位数,并用零填充左侧空出的位。

例如,下面的语句使用了 1024>>n 将数字 1024(二进制为 10000000000)向右移动了 n 位:

WITH RECURSIVE cte(n) AS (
    SELECT 0 AS n
    UNION ALL
    SELECT n+1 FROM cte WHERE n<11
)
SELECT n,1024>>n,LPAD(CONV(1024>>n,10,2),11,0) FROM cte;
+------+---------+-------------------------------+
| n    | 1024>>n | LPAD(CONV(1024>>n,10,2),11,0) |
+------+---------+-------------------------------+
|    0 |    1024 | 10000000000                   |
|    1 |     512 | 01000000000                   |
|    2 |     256 | 00100000000                   |
|    3 |     128 | 00010000000                   |
|    4 |      64 | 00001000000                   |
|    5 |      32 | 00000100000                   |
|    6 |      16 | 00000010000                   |
|    7 |       8 | 00000001000                   |
|    8 |       4 | 00000000100                   |
|    9 |       2 | 00000000010                   |
|   10 |       1 | 00000000001                   |
|   11 |       0 | 00000000000                   |
+------+---------+-------------------------------+
12 rows in set (0.00 sec)

>> 操作符还可以用于提取一个大数中的特定部分,例如从 TiDB TSO 时间戳中提取 UNIX 时间戳。

MySQL 兼容性

在处理位函数和操作符时,MySQL 8.0 与之前版本的 MySQL 之间存在一些差异。TiDB 旨在遵循 MySQL 8.0 的行为。

已知问题

在以下情况中,TiDB 中的查询结果与 MySQL 5.7 相同,但与 MySQL 8.0 不同。

  • 二进制参数的位操作。更多信息,请参考 #30637
  • BIT_COUNT() 函数的结果。更多信息,请参考 #44621