文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  函數與運算子  /  位元函數與運算子

14.12 位元函數與運算子

表 14.17 位元函數與運算子

名稱 描述
& 位元 AND
>> 右移
<< 左移
^ 位元 XOR
BIT_COUNT() 傳回已設定的位元數
| 位元 OR
~ 位元反轉

以下清單描述可用的位元函數與運算子

  • |

    位元 OR。

    結果類型取決於是否將引數評估為二進位字串或數字。

    • 當引數具有二進位字串類型,且至少其中一個不是十六進位文字、位元文字或 NULL 文字時,會發生二進位字串評估。否則會發生數值評估,並視需要將引數轉換為不帶正負號的 64 位元整數。

    • 二進位字串評估會產生與引數長度相同的二進位字串。如果引數長度不相等,則會發生 ER_INVALID_BITWISE_OPERANDS_SIZE 錯誤。數值評估會產生不帶正負號的 64 位元整數。

    如需更多資訊,請參閱本節的介紹討論。

    mysql> SELECT 29 | 15;
            -> 31
    mysql> SELECT _binary X'40404040' | X'01020304';
            -> 'ABCD'

    如果從 mysql 用戶端內叫用位元 OR,二進位字串結果會使用十六進位表示法顯示,具體取決於 --binary-as-hex 的值。如需該選項的更多資訊,請參閱 第 6.5.1 節,「mysql — MySQL 命令列用戶端」

  • &

    位元 AND。

    結果類型取決於是否將引數評估為二進位字串或數字。

    • 當引數具有二進位字串類型,且至少其中一個不是十六進位文字、位元文字或 NULL 文字時,會發生二進位字串評估。否則會發生數值評估,並視需要將引數轉換為不帶正負號的 64 位元整數。

    • 二進位字串評估會產生與引數長度相同的二進位字串。如果引數長度不相等,則會發生 ER_INVALID_BITWISE_OPERANDS_SIZE 錯誤。數值評估會產生不帶正負號的 64 位元整數。

    如需更多資訊,請參閱本節的介紹討論。

    mysql> SELECT 29 & 15;
            -> 13
    mysql> SELECT HEX(_binary X'FF' & b'11110000');
            -> 'F0'

    如果從 mysql 用戶端內叫用位元 AND,二進位字串結果會使用十六進位表示法顯示,具體取決於 --binary-as-hex 的值。如需該選項的更多資訊,請參閱 第 6.5.1 節,「mysql — MySQL 命令列用戶端」

  • ^

    位元 XOR。

    結果類型取決於是否將引數評估為二進位字串或數字。

    • 當引數具有二進位字串類型,且至少其中一個不是十六進位文字、位元文字或 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 用戶端內叫用位元 XOR,二進位字串結果會使用十六進位表示法顯示,具體取決於 --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 直接處理二進位字串引數(不進行轉換)並產生二進位字串結果。不是整數或二進位字串的引數會轉換為整數。

可視為二進位字串的引數包括具有二進位字串類型的欄位值、常式參數、區域變數和使用者定義變數:BINARYVARBINARYBLOB 類型之一。

您可以使用十六進位文字或位元文字指定位元運算的引數,並意圖將它們表示為數字;當所有位元引數都是十六進位或位元文字時,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 |
+----------------------------------+

建構時間戳記和節點編號部分值的位元遮罩。時間戳記包含前三個部分(64 位元,位元 0 到 63),節點編號是最後一個部分(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())。

範例

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,並產生一個具有 NULL 值的 BIGINT 結果

    NULL & NULL
    NULL >> 4

您可以透過明確指出至少有一個引數是二進位字串,來使這些運算在二進位字串上下文中評估引數

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

最後兩個表達式的結果為 NULL,就像沒有 BINARY 運算子一樣,但結果的資料類型是二進位字串類型,而不是整數類型。