文件首頁
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 參考手冊  /  ...  /  JavaScript 儲存程式範例

27.3.9 JavaScript 儲存程式範例

本節包含一些範例,說明在各種情況下使用 JavaScript 程式的不同方面。

以下範例示範如何將 JavaScript 儲存函數與資料表欄值搭配使用。首先,我們定義一個儲存函數 gcd(),它會找出兩個整數的最大公因數,如下所示

mysql> CREATE FUNCTION gcd(a INT, b INT) 
    -> RETURNS INT NO SQL LANGUAGE JAVASCRIPT AS
    -> $mle$
    $>   let x = Math.abs(a)
    $>   let y = Math.abs(b)
    $>   while(y) {
    $>     var t = y
    $>     y = x % y
    $>     x = t
    $>   }
    $>   return x
    $> $mle$
    -> ;
Query OK, 0 rows affected (0.01 sec)

我們可以像這樣測試儲存函數

mysql> SELECT gcd(75, 220), gcd(75, 225);
+--------------+--------------+
| gcd(75, 220) | gcd(75, 225) |
+--------------+--------------+
|            5 |           75 |
+--------------+--------------+
1 row in set (0.00 sec)

接下來,我們建立一個具有兩個整數欄位的資料表 t1,並使用一些資料列填入它,如下所示

mysql> CREATE TABLE t1 (c1 INT, c2 INT);
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO t1 VALUES ROW(12,70), ROW(17,3), ROW(81,9);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql> TABLE t1;
+------+------+
| c1   | c2   |
+------+------+
|   12 |   70 |
|   17 |    3 |
|   81 |    9 |
+------+------+
3 rows in set (0.00 sec)

現在,我們可以從 t1 中選取,並使用 gcd() 函數,其中欄位值在函數呼叫中用作引數值,如下所示

mysql> SELECT c1, c2, gcd(c1, c2) AS G
    -> FROM t1
    -> WHERE gcd(c1, c2) > 1
    -> ORDER BY gcd(c1, c2);
+----+----+---+
| c1 | c2 | G |
+----+----+---+
| 12 | 70 | 2 |
| 81 |  9 | 9 |
+----+----+---+
8 rows in set (0.01 sec)

當引數值不是指定的類型時,如果可以,會強制轉換為正確的類型,如下所示

mysql> SELECT gcd(500.3, 600), gcd(500.5, 600);
+-----------------+-----------------+
| gcd(500.3, 600) | gcd(500.5, 600) |
+-----------------+-----------------+
|             100 |               3 |
+-----------------+-----------------+
1 row in set (0.01 sec)

使用 Math.round() 完成浮點數值到整數的捨入;在本例中,500.3 會向下捨入為 500,而 500.5 會向上捨入為 501。

接下來,我們使用 CREATE PROCEDURE 陳述式建立一個簡單的 JavaScript 儲存程序,其中包含一個 OUT 參數,以將目前日期和時間以人類可讀的格式傳遞至使用者變數。由於我們不確定此表示法的長度,因此我們對參數的類型使用 VARCHAR(25)。

mysql> CREATE PROCEDURE d1 (OUT res VARCHAR(25))
    -> LANGUAGE JAVASCRIPT
    -> AS
    -> $$
    $>   let d = new Date().toString()
    $>   res = d
    $> $$
    -> ;
Query OK, 0 rows affected (0.01 sec)

我們現在可以測試儲存程序,首先驗證使用者變數 @today 尚未設定為任何值,如下所示

mysql> SELECT @today;
+----------------------+
| @today               |
+----------------------+
| NULL                 |
+----------------------+
1 row in set (0.01 sec)

mysql> CALL d1(@today);
ERROR 1406 (22001): Data too long for column 'res' at row 1

此程序在語法上有效,但是 INOUT 參數 (res) 的資料類型不允許足夠的字元數;儲存程式會拒絕它,而不是截斷值。由於無法就地變更程序程式碼,因此我們必須捨棄程序並重新建立它;這次我們嘗試將為 INOUT 參數指定的長度加倍

mysql> DROP PROCEDURE d1;
Query OK, 0 rows affected (0.02 sec)

mysql> CREATE PROCEDURE d1 (OUT res VARCHAR(50))
    -> LANGUAGE JAVASCRIPT
    -> AS
    -> $$
    $>   let d = new Date().toString()
    $>   res = d
    $> $$
    -> ;
Query OK, 0 rows affected (0.01 sec)

現在我們可以重複測試,如下所示

mysql> SELECT @today;
+----------------------+
| @today               |
+----------------------+
| NULL                 |
+----------------------+
1 row in set (0.01 sec)

在使用 CALL 叫用更新的程序之前,@today 的值仍未設定,因為 d1() 的原始版本未成功執行。更新的版本執行成功,並且我們稍後看到,這次使用者變數的值已如預期般設定

mysql> CALL d1(@today);
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @today;
+-----------------------------------------+
| @today                                  |
+-----------------------------------------+
| Mon Oct 30 2023 20:47:29 GMT+0000 (GMT) |
+-----------------------------------------+
1 row in set (0.00 sec)
注意

您從執行此範例獲得的值很可能與此處顯示的值有所不同,因為日期的確切表示法取決於您的系統地區設定,以及其他可能設定。如需更多資訊,請參閱 JavaScript Date 物件的文件。

下一個範例示範如何在觸發程序中使用 JavaScript 儲存函數。

首先,我們建立一個包含三個整數欄位的資料表 t2,如下所示

mysql> CREATE TABLE t2 (c1 INT, c2 INT, c3 INT);
Query OK, 0 rows affected (0.04 sec)

現在,我們可以在這個資料表上建立一個觸發程序。這必須使用以一般方式使用 SQL 撰寫的 CREATE TRIGGER 陳述式來完成(請參閱第 27.4 節,「使用觸發程序」),但它可以利用以 JavaScript 撰寫的儲存常式,例如本節稍早所示的 js_pow() 函數。

mysql> delimiter //
mysql> CREATE TRIGGER jst BEFORE INSERT ON t2
    -> FOR EACH ROW
    -> BEGIN
    ->   SET NEW.c2 = js_pow(NEW.c1, 2);
    ->   SET NEW.c3 = js_pow(NEW.c1, 3);
    -> END;
    -> //
Query OK, 0 rows affected (0.02 sec)

mysql> delimiter ;
mysql>

此觸發程序會在將資料列插入 t2 時執行,它會取用插入第一個欄位的值,並將此值的平方插入第二個欄位,並將其立方插入第三個欄位。我們藉由將一些資料列插入資料表來測試觸發程序;由於唯一未捨棄的值是我們為欄位 c1 提供的值,因此我們可以針對其餘兩個欄位簡單地使用 NULL,如下所示

mysql> INSERT INTO t2 
    -> VALUES 
    ->   ROW(1, NULL, NULL), 
    ->   ROW(2.49, NULL, NULL), 
    ->   ROW(-3, NULL, NULL),
    ->   ROW(4.725, NULL, NULL);
Query OK, 4 rows affected (0.01 sec)
Records: 4  Duplicates: 0  Warnings: 0

由於觸發程序叫用的函數是以 JavaScript 撰寫,因此會套用 JavaScript 捨入規則,因此 2.49 會向下捨入為 2,而 4.75 會向上捨入為 5。當我們使用 TABLE 陳述式檢查結果時,可以看到事實確實如此

mysql> TABLE t2;
+------+------+------+
| c1   | c2   | c3   |
+------+------+------+
|    1 |    1 |    1 |
|    2 |    4 |    8 |
|   -3 |    9 |  -27 |
|    5 |   25 |  125 |
+------+------+------+
4 rows in set (0.00 sec)