MySQL 5.7参考手册/语言结构/用户定义的变量

9.4用户定义的变量

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

用户变量被写成@var_name,其中变量名var_name由字母数字字符组成,_,.如果将用户变量名作为字符串或标识符引用,则可以包含其他字符(例如,@“my-var”@“my-var”,或@“my-var”).

用户定义变量是特定于会话的。一个客户端定义的用户变量不能被其他客户端看到或使用。(例外:访问性能架构的用户user_variables_by_thread表可以看到所有会话的所有用户变量。)当客户端退出时,该客户端会话的所有变量将自动释放。

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

设置用户定义变量的一种方法是发出声明:

设置@var_nameexpr(@var_nameexpr)……

,要么:=可以用作赋值运算符。

用户变量可以从有限的一组数据类型中分配值:整数、十进制、浮点、二进制或非二进制字符串,或者价值。分配小数和实值不会保留值的精度或比例。非允许类型的值被转换为允许类型。例如,具有时间或空间数据类型的值被转换为二进制字符串。价值具有JSON数据类型转换为字符串,其字符集为utf8mb4和整理utf8mb4_bin

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

分配给用户变量的十六进制或位值被视为二进制字符串。若要将十六进制或位值作为数字分配给用户变量,请在数值上下文中使用它。例如,添加0或使用铸造(…无符号)

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

如果在结果集中选择了用户变量的值,它将作为字符串返回给客户机。

如果引用一个未初始化的变量,则它的值为和字符串的类型。

在允许表达式的大多数上下文中都可以使用用户变量。这目前不包括显式需要文字值的上下文,例如限制一个条款选择声明中,或忽略N一个条款加载数据声明。

也可以在其他语句中为用户变量赋值.(此功能在MySQL 8.0中已弃用,将在后续版本中删除。)当以这种方式进行赋值时,赋值操作符必须是:=而不是因为后者被视为比较运算符在声明中

SET @t1=1, @t2=2, @t3:=4;SELECT @t1, @t2, @t3, @t4:= @t1+@t2+@t3;+------+------+------+--------------------+ | @ t1 | @t2 | @t3 | @t4: = @t1 + @t2 + @t3  | +------+------+------+--------------------+ | 1 | 2 | 4 | 7  | +------+------+------+--------------------+

一般来说,除了在语句中,永远不要给用户变量赋值,然后在同一语句中读取该值。例如,增加一个变量,这是可以的:

SET @a = @a + 1;

对于其他语句,例如选择,您可能会得到您所期望的结果,但这并不保证。在下面的语句中,您可能认为MySQL计算@a然后再做一个赋值操作:

SELECT @a, @a:=@a+1,…;

然而,涉及用户变量的表达式的求值顺序是未定义的。

给变量赋值并在相同的非变量中读取值的另一个问题语句中,变量的默认结果类型基于其在语句开始处的类型。下面的例子说明了这一点:

mysql >设置@a = '测试';SELECT @a,(@a:=20) FROMtbl_name

对于这个选择语句,MySQL报告客户端列1是一个字符串,并转换所有的访问@a到字符串,即使@a被设置为第二行的数字。后选择语句执行时,@a被视为下一个语句的数字。

要避免这种行为带来的问题,要么不给同一个变量赋值,要么在单个语句中读取该变量的值,要么将该变量设置为00.0,或在使用它之前定义其类型。

在一个选择语句,每个选择表达式仅在发送到客户机时计算。这意味着在a集团,或命令子句中,引用在选择表达式列表中被赋值的变量时,则可以工作如预期:

mysql> SELECT (@aa:=id) AS a, (@aa+3) AS b FROMtbl_nameb = 5;

的引用b子句引用所使用的选择列表中表达式的别名@aa.这并没有像预期的那样工作:@aa包含的值id从上一个选定的行,而不是从当前行。

用户变量用于提供数据值。它们不能直接在SQL语句中作为标识符或标识符的一部分使用,例如在需要表或数据库名称的上下文中,或者作为保留字,例如选择.即使变量被引号括起来,这也是正确的,如下例所示:

SELECT c1 FROM t;+——+ | c1  | +----+ | 0  | +----+ | 1  | +----+ 2行集(0.00秒)mysql >设置@col =“c1”;查询OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t;+------+ | @ 上校  | +------+ | c1  | +------+ 1行组(0.00秒)mysql >选择“@col”从t;错误1054 (42S22): Unknown column '@col' in 'field list' mysql> SET @col = " ' c1 ' ";查询OK, 0 rows affected (0.00 sec) mysql> SELECT @col FROM t;+------+ | @ 上校  | +------+ | ` c1 ` | +------+ 1行集(0.00秒)

用户变量不能用于提供标识符,但这一原则的一个例外是,当您构造一个字符串以用作以后执行的预备语句时。在这种情况下,可以使用用户变量来提供语句的任何部分。下面的例子说明了如何做到这一点:

mysql> SET @c = "c1";查询OK, 0 rows affected (0.00 sec) mysql> SET @s = CONCAT("SELECT ", @c, " FROM t");查询OK, 0 rows affected (0.00 sec) mysql> PREPARE stmt FROM @s;查询OK, 0 rows affected (0.04 sec) Statement prepared mysql> EXECUTE stmt;+——+ | c1  | +----+ | 0  | +----+ | 1  | +----+ 2行集(0.00秒)mysql >释放准备支撑;查询OK, 0行受影响(0.00秒)

看到第13.5节“准备好的报表”,以查询更多资料。

类似的技术可以在应用程序中使用程序变量构造SQL语句,如使用PHP 5所示:

<?PHP $mysqli = new mysqli("localhost", "user", "pass", "test");if(mysqli_connect_errno()) die("Connection failed: %s\n", mysqli_connect_error());$坳=“c1”;$query = "SELECT $col FROM t";$ = $ mysqli结果- >查询(查询);而(行=结果美元- > fetch_assoc()){回声”< p > "。行美元(“$坳”)。" < / p > \ n”;}结果- > close (); $mysqli->close(); ?>

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