ビット関数と演算子

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 進形式110001000010100011ビットの数をカウントするため、 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 になります。

たとえば、 10101100ビット単位の 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.1192.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 になります。

たとえば、 10101100ビット単位の 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 になります。

たとえば、 10101100ビット単位の 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 とは異なります。

  • バイナリ引数を使用したビット演算。詳細については、 #30637参照してください。
  • BIT_COUNT()関数の結果。詳細については、 #44621参照してください。

このページは役に立ちましたか?