ビット関数と演算子
TiDB は、MySQL 8.0 で利用可能なビット関数と演算子のすべてをサポートします。
ビット関数と演算子:
名前 | 説明 |
---|---|
BIT_COUNT() | 1に設定されているビットの数を返します |
& | ビットAND |
~ | ビット反転 |
[` | `](#-bitwise-or) |
^ | ビット単位の排他的論理和 |
<< | 左シフト |
>> | 右シフト |
BIT_COUNT()
BIT_COUNT(expr)
関数は、 expr
のうち 1 に設定されているビットの数を返します。
SELECT BIT_COUNT(b'00101001');
+------------------------+
| BIT_COUNT(b'00101001') |
+------------------------+
| 3 |
+------------------------+
1 row in set (0.00 sec)
注記:
引数
expr
が 2 進数の場合、b'00101001'
のように数値の前にb
明示的に指定する必要があります。そうしないと、この関数はそれを文字列として扱い、異なる結果を返します。たとえば、BIT_COUNT('00101001')
文字列'00101001'
10 進数101001
に変換し、その 2 進形式11000100001010001
で1
ビットの数をカウントするため、7
返します。
次の例は前の例と似ていますが、引数としてビットリテラルではなくCONV()
進リテラルを使用しています。1 関数は0x29
16 進数 (基数 16) から 2 進数 (基数 2) に変換し、2 進数では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)
&
(ビットAND)
&
演算子はビット単位の AND 演算を実行します。2 つの数値の対応するビットを比較します。対応するビットが両方とも 1 の場合、結果の対応するビットは 1 になります。それ以外の場合は 0 になります。
たとえば、 1010
と1100
ビット単位の AND 演算では、両方の数値で左端のビットのみが 1 に設定されているため、 1000
が返されます。
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 アドレスとネットワーク マスクに対してビット単位の AND 演算を実行し、ネットワーク アドレスを取得できます。これは、複数の IP アドレスが同じネットワークに属しているかどうかを判断するのに役立ちます。
次の 2 つの例では、 IP アドレス192.168.1.1
と192.168.1.2
255.255.255.0
でマスクされている場合、同じネットワーク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)
~
(ビット反転)
~
演算子は、指定された値に対してビット単位の反転 (またはビット単位の NOT) 演算を実行します。指定された値の各ビットを反転します。つまり、0 のビットは 1 になり、1 のビットは 0 になります。
操作の前に、値は 64 ビットに拡張されます。
2 進数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)
|
(ビットOR)
|
演算子はビット単位の OR 演算を実行します。2 つの数値の対応するビットを比較します。対応するビットの少なくとも 1 つが 1 の場合、結果の対応するビットは 1 になります。
たとえば、 1010
と1100
ビット単位の OR 演算では、 2 つの数値の最初の 3 ビットのうち、対応するビットの少なくとも 1 つが 1 に設定されているため、 1110
が返されます。
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)
^
(ビット単位の排他的論理和)
^
演算子はビット単位の XOR (排他的論理和) 演算を実行します。2 つの数値の対応するビットを比較します。対応するビットが異なる場合、結果の対応するビットは 1 になります。
たとえば、 1010
と1100
ビット単位の XOR 演算では、 2 つの数値の 2 番目と 3 番目のビットが異なるため、 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)
先頭のゼロが削除されているため、結果は0110
ではなく110
として表示されることに注意してください。
<<
(左シフト)
<<
演算子は左シフト演算を実行し、数値のビットを指定された位置数だけ左にシフトし、右側の空いたビットをゼロで埋めます。
たとえば、次のステートメントでは、 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
(2 進数では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 とは異なります。