文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  函式與運算子  /  位元函式與運算子

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)

    以無符號 64 位元整數傳回引數 N 中已設定的位元數,如果引數為 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 8.4 直接處理二進制字串引數(不進行轉換),並產生二進制字串結果。不是整數或二進制字串的引數會轉換為整數。

視為二進制字串的引數包括具有二進制字串類型的資料行值、常式參數、區域變數和使用者定義的變數:BINARYVARBINARY 或其中一種 BLOB 類型。

您可以使用十六進位文字或位元文字來指定位元運算的引數,其目的為表示數字;當所有位元引數為十六進位或位元文字時,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;

透過將全一的位址向左或向右位移,來建構網路和主機遮罩。若要執行此動作,請從位址 :: 開始,這是所有零的簡寫,您可以在像這樣將其轉換為二進制字串時看到

mysql> SELECT HEX(INET6_ATON('::')) AS 'all zeros';
+----------------------------------+
| all zeros                        |
+----------------------------------+
| 00000000000000000000000000000000 |
+----------------------------------+

若要產生互補值(全一),請使用 ~ 運算符來反轉位元

mysql> SELECT HEX(~INET6_ATON('::')) AS 'all ones';
+----------------------------------+
| all ones                         |
+----------------------------------+
| FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF |
+----------------------------------+

將全一的值向左或向右位移,以產生網路和主機遮罩

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 8.4 會在數值上下文中評估位元運算。也就是說,如果所有位元運算的參數都是未修飾的十六進位字面值、位元字面值或 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 運算符一樣,但結果的資料類型是二進制字串類型,而不是整數類型。