Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  Language Structure  /  User-Defined Variables

11.4 用户定义变量

您可以在一个语句中将值存储在用户定义变量中,然后在另一个语句中引用它。这使您可以从一个语句传递值到另一个语句。

用户变量写作为 @var_name,其中变量名 var_name 由字母数字字符、 ._$ 组成。用户变量名可以包含其他字符,如果您将其作为字符串或标识符引用(例如 @'my-var'@"my-var"@`my-var`)。

用户定义变量是会话特定的。一个客户端定义的用户变量不能被其他客户端看到或使用。(例外:具有 Performance Schema user_variables_by_thread 表访问权限的用户可以看到所有会话的用户变量。)所有变量在客户端会话退出时自动释放。

用户变量名不区分大小写。名称的最大长度为 64 个字符。

设置用户定义变量的一种方法是发出 SET 语句:

SET @var_name = expr [, @var_name = expr] ...

对于 SET,可以使用 =:= 作为赋值运算符。

用户变量可以从有限的数据类型中分配值:整数、十进制、浮点数、二进制或非二进制字符串或 NULL 值。赋值十进制和实数值时,不保留值的精度或刻度。其他类型的值将被转换为允许的类型。例如,时间或空间数据类型的值将被转换为二进制字符串。JSON 数据类型的值将被转换为字符集为 utf8mb4 和排序规则为 utf8mb4_bin 的字符串。

如果用户变量被分配了非二进制(字符)字符串值,它将具有相同的字符集和排序规则。用户变量的强制性是隐式的。(这与表列值的强制性相同。)

十六进制或位值被分配给用户变量时,将被视为二进制字符串。要将十六进制或位值作为数字分配给用户变量,请在数字上下文中使用它。例如,添加 0 或使用 CAST(... AS UNSIGNED)

mysql> SET @v1 = X'41';
mysql> SET @v2 = X'41'+0;
mysql> SET @v3 = CAST(X'41' AS UNSIGNED);
mysql> SELECT @v1, @v2, @v3;
+------+------+------+
| @v1  | @v2  | @v3  |
+------+------+------+
| A    |   65 |   65 |
+------+------+------+
mysql> SET @v1 = b'1000001';
mysql> SET @v2 = b'1000001'+0;
mysql> SET @v3 = CAST(b'1000001' AS UNSIGNED);
mysql> SELECT @v1, @v2, @v3;
+------+------+------+
| @v1  | @v2  | @v3  |
+------+------+------+
| A    |   65 |   65 |
+------+------+------+

如果用户变量的值在结果集中被选择,将被返回到客户端作为字符串。

如果您引用了未初始化的变量,它将具有 NULL 值和字符串类型。

在准备语句中引用用户变量时,其类型将在语句首次准备时确定,并在随后每次执行语句时保留该类型。类似地,在存储过程中的语句中使用用户变量时,其类型将在存储过程首次调用时确定,并在随后每次调用时保留该类型。

用户变量可以在大多数允许表达式的上下文中使用。这不包括需要文字值的上下文,例如 SELECT 语句的 LIMIT 子句或 LOAD DATA 语句的 IGNORE N LINES 子句。

MySQL 的早期版本允许在其他语句中分配用户变量的值,而不仅仅是 SET 语句。这种功能在 MySQL 8.3 中为了向后兼容而被支持,但可能在未来版本的 MySQL 中被删除。

在这种方式中,您必须使用 := 作为赋值运算符; = 将被视为比较运算符。

涉及用户变量的表达式的求值顺序未定义。例如,没有保证 SELECT @a, @a:=@a+1 首先计算 @a 然后执行赋值。

此外,变量的默认结果类型基于语句开始时的类型。这可能会在变量在语句中被赋予新值时产生意外的效果,如果变量在语句开始时持有一个类型的值,而在同一语句中又被赋予另一个类型的值。

为了避免这种行为的问题,不要在同一语句中为变量赋值和读取变量的值,或者在使用变量之前将其设置为 00.0'' 以定义其类型。

HAVINGGROUP BYORDER BY 在引用在选择表达式列表中赋值的变量时不能按预期工作,因为表达式是在客户端评估的,因此可以使用前一行的过时列值。

用户变量旨在提供数据值。它们不能直接在 SQL 语句中用作标识符或标识符的一部分,例如在期望表名或数据库名的上下文中,或者作为保留字,如 SELECT。即使变量被引号括起来,也是如此。

mysql> SELECT c1 FROM t;
+----+
| c1 |
+----+
|  0 |
+----+
|  1 |
+----+
2 rows in set (0.00 sec)

mysql> SET @col = "c1";
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @col FROM t;
+------+
| @col |
+------+
| c1   |
+------+
1 row in set (0.00 sec)

mysql> SELECT `@col` FROM t;
ERROR 1054 (42S22): Unknown column '@col' in 'field list'

mysql> SET @col = "`c1`";
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT @col FROM t;
+------+
| @col |
+------+
| `c1` |
+------+
1 row in set (0.00 sec)

用户变量不能用作标识符的唯一例外是,当您构建一个字符串以供后续执行的准备语句时。在这种情况下,用户变量可以提供语句的任何部分。下面的示例演示了如何实现这一点:

mysql> SET @c = "c1";
Query OK, 0 rows affected (0.00 sec)

mysql> SET @s = CONCAT("SELECT ", @c, " FROM t");
Query OK, 0 rows affected (0.00 sec)

mysql> PREPARE stmt FROM @s;
Query OK, 0 rows affected (0.04 sec)
Statement prepared

mysql> EXECUTE stmt;
+----+
| c1 |
+----+
|  0 |
+----+
|  1 |
+----+
2 rows in set (0.00 sec)

mysql> DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0.00 sec)

请参阅 第 15.5 节,“准备语句”,以获取更多信息。

应用程序也可以使用程序变量来构建 SQL 语句,如下所示,使用 PHP 5:

<?php
  $mysqli = new mysqli("localhost", "user", "pass", "test");

  if( mysqli_connect_errno() )
    die("Connection failed: %s\n", mysqli_connect_error());

  $col = "c1";

  $query = "SELECT $col FROM t";

  $result = $mysqli->query($query);

  while($row = $result->fetch_assoc())
  {
    echo "<p>" . $row["$col"] . "</p>\n";
  }

  $result->close();

  $mysqli->close();
?>

以这种方式组装 SQL 语句有时称为 动态 SQL