文档首页
MySQL 9.0 参考手册
相关文档 下载此手册
PDF (美国信纸) - 40.0Mb
PDF (A4) - 40.1Mb
手册页 (TGZ) - 258.2Kb
手册页 (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 参考手册  /  ...  /  JavaScript 存储程序示例

27.3.9 JavaScript 存储程序示例

本节包含一些示例,说明在各种情况下使用 JavaScript 程序的多个不同方面。

以下示例演示了在不同情况下使用 JavaScript 存储程序的多个不同方面。

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)

以下示例演示了如何使用 JavaScript 存储函数和表列值。 首先,我们定义一个存储函数 gcd(),它用于查找两个整数的最大公约数,如下所示

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

我们可以像这样测试存储函数:

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,它有两个整型列,并用几行数据填充它,如下所示

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)

现在,我们可以从 t1 中进行选择,使用 gcd() 函数,并将列值作为函数调用中的参数值,如下所示

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。

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)

接下来,我们使用一个 CREATE PROCEDURE 语句创建一个简单的 JavaScript 存储过程,该语句包含一个 OUT 参数,用于将当前日期和时间以人类可读的格式传递给用户变量。 由于我们不确定此表示形式的长度,因此我们使用 VARCHAR(25) 作为参数的类型。

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

现在,我们可以测试存储过程,首先验证用户变量 @today 是否尚未设置任何值,如下所示

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)

该过程在语法上是有效的,但 INOUT 参数 (res) 的数据类型不允许使用足够数量的字符;存储程序不会截断该值,而是拒绝它。 由于无法就地更改过程代码,因此我们必须删除该过程并重新创建它;这次,我们尝试将 INOUT 参数指定的长度加倍

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

现在,我们可以重复测试,如下所示

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)
在使用 CALL 调用更新后的过程之前,@today 的值仍然未设置,因为 d1() 的原始版本未成功执行。 更新后的版本运行成功,我们之后可以看到,这次用户变量的值按预期设置了

注意

运行此示例获得的值可能与这里显示的值有所不同,因为日期的精确表示取决于您的系统区域设置,以及可能的其他设置。 有关更多信息,请参阅 JavaScript Date 对象的文档。

下一个示例演示了如何在触发器中使用 JavaScript 存储函数。

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

首先,我们创建一个表 t2,它包含三个整型列,如下所示

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>

现在,我们可以为此表创建一个触发器。 这必须使用 CREATE TRIGGER 语句以通常的方式使用 SQL 编写(请参阅 第 27.4 节“使用触发器”),但它可以使用用 JavaScript 编写的存储例程,例如本节前面显示的 js_pow() 函数。

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

此触发器在将行插入 t2 时生效,它获取插入到第一列的值,并将该值的平方插入到第二列,并将该值的立方插入到第三列。 我们通过将几行插入到表中来测试触发器;由于唯一没有被丢弃的值是我们为 c1 列提供的那个值,因此我们可以为其余两个列简单地使用 NULL,如下所示

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)

由于触发器调用的函数是用 JavaScript 编写的,因此会应用 JavaScript 四舍五入规则,因此 2.49 向下舍入为 2,而 4.75 向上舍入为 5。 当我们使用 TABLE 语句检查结果时,我们可以看到情况确实如此