ビット関数と演算子
TiDB は、MySQL 8.0 で利用可能なビット関数と演算子のすべてをサポートします。
ビット関数と演算子:
| 名前 | 説明 | 
|---|---|
BIT_COUNT() | 1に設定されているビットの数を返す | 
& | ビットAND | 
~ | ビット反転 | 
| [` | `](#-bitwise-or) | 
^ | ビット単位のXOR | 
<< | 左シフト | 
>> | 右シフト | 
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進数形式である1ビットの数を11000100001010001カウントするため、7返します。
次の例は前の例と似ていますが、引数としてビットリテラルではなく16進リテラルを使用しています。1関数はCONV() 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)
~ (ビット反転)
~演算子は、与えられた値に対してビット反転(またはビット否定)演算を実行します。与えられた値の各ビットを反転します。つまり、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演算を実行します。2つの数値の対応するビットを比較します。対応するビットの少なくとも1つが1の場合、結果の対応するビットも1になります。
たとえば、 1010と1100ビット単位の OR 演算では1110返されます。これは、 2 つの数値の最初の 3 ビットのうち、対応するビットの少なくとも 1 つが 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)
^ (ビット単位のXOR)
^演算子はビット単位の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 とは異なります。