Skip to content
Merged
179 changes: 56 additions & 123 deletions user-defined-variables.md
Original file line number Diff line number Diff line change
@@ -1,102 +1,100 @@
---
title: 用户自定义变量
category: reference
summary: 本文介绍 TiDB 的用户自定义变量。
aliases: ['/docs-cn/dev/reference/sql/language-structure/user-defined-variables/']
---

# 用户自定义变量

用户自定义变量格式为 `@var_name`。`var_name` 目前只支持字母,数字,`_$`组成。用户自定义变量是大小写不敏感的
本文介绍 TiDB 的用户自定义变量的概念,以及设置和读取用户自定义变量的方法

用户自定义变量是跟 session 绑定的,也就是说只有当前连接可以看见设置的用户变量,其他客户端连接无法查看到
用户自定义变量格式为 `@var_name`。组成 `var_name` 的字符可以是任何能够组成标识符 (identifier) 的字符,包括数字 `0-9`、字母 `a-zA-Z`、下划线 `_`、美元符号 `$` 以及 UTF-8 字符。此外,还包括英文句号 `.`。用户自定义变量是大小写不敏感的

用 `SET` 语句可以设置用户自定义变量:
用户自定义变量跟 session 绑定,当前设置的用户变量只在当前连接中可见,其他客户端连接无法查看。

## 设置用户自定义变量

用 `SET` 语句可以设置用户自定义变量,语法为 `SET @var_name = expr [, @var_name = expr] ...;`。例如:

{{< copyable "sql" >}}

```sql
SET @var_name = expr [, @var_name = expr] ...;
SET @favorite_db = 'TiDB';
```


{{< copyable "sql" >}}

```sql
SET @var_name := expr;
SET @a = 'a', @b = 'b', @c = 'c';
```

对于 `SET` 语句,赋值操作符可以是 `=` 也可以是 `:=`

例:
其中赋值符号还可以使用 `:=`。例如:

{{< copyable "sql" >}}

```sql
SET @a1=1, @a2=2, @a3:=4;
SET @favorite_db := 'TiDB';
```

赋值符号右边的内容可以是任意合法的表达式。例如:

{{< copyable "sql" >}}

```sql
SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3;
SET @c = @a + @b;
```

```
+------+------+------+--------------------+
| @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 |
+------+------+------+--------------------+
| 1 | 2 | 4 | 7 |
+------+------+------+--------------------+
{{< copyable "sql" >}}

```sql
set @c = b'1000001' + b'1000001';
```

如果设置用户变量用了 `HEX` 或者 `BIT` 值,TiDB会把它当成二进制字符串。如果你要将其设置成数字,那么需要手动加上 `CAST转换`: `CAST(.. AS UNSIGNED)`:
## 读取用户自定义变量

要读取一个用户自定义变量,可以使用 `SELECT` 语句查询:

{{< copyable "sql" >}}

```sql
SELECT @v1, @v2, @v3;
SELECT @a1, @a2, @t3
```

```
+------+------+------+
| @v1 | @v2 | @v3 |
| @a1 | @a2 | @a3 |
+------+------+------+
| A | 65 | 65 |
| 1 | 2 | 4 |
+------+------+------+
1 row in set (0.00 sec)
```

{{< copyable "sql" >}}
还可以在 `SELECT` 语句中赋值:

```sql
SET @v1 = b'1000001';
SELECT @a1, @a2, @t3, @a4 := @a1+@a2+@a3;
```

```
Query OK, 0 rows affected (0.00 sec)
+------+------+------+--------------------+
| @a1 | @a2 | @a3 | @a4 := @a1+@a2+@a3 |
+------+------+------+--------------------+
| 1 | 2 | 4 | 7 |
+------+------+------+--------------------+
```

{{< copyable "sql" >}}
其中变量 `@a4` 在被修改或关闭连接之前,值始终为 `7`。

```sql
SET @v2 = b'1000001'+0;
```

```
Query OK, 0 rows affected (0.00 sec)
```
如果设置用户变量时用了十六进制字面量或者二进制字面量,TiDB 会把它当成二进制字符串。如果要将其设置成数字,那么可以手动加上 `CAST` 转换,或者在表达式中使用数字的运算符:

{{< copyable "sql" >}}

```sql
SET @v1 = b'1000001';
SET @v2 = b'1000001'+0;
SET @v3 = CAST(b'1000001' AS UNSIGNED);
```

```
Query OK, 0 rows affected (0.00 sec)
```

{{< copyable "sql" >}}

```sql
Expand All @@ -109,15 +107,14 @@ SELECT @v1, @v2, @v3;
+------+------+------+
| A | 65 | 65 |
+------+------+------+
1 row in set (0.00 sec)
```

如果获取一个没有设置过的变量,会返回一个 NULL:

{{< copyable "sql" >}}

```sql
select @not_exist;
SELECT @not_exist;
```

```
Expand All @@ -126,74 +123,48 @@ select @not_exist;
+------------+
| NULL |
+------------+
1 row in set (0.00 sec)
```

用户自定义变量不能直接在 SQL 语句中被当成 identifier,例
除了 `SELECT` 读取用户自定义变量以外,常见的用法还有 `PREPARE` 语句,例如

{{< copyable "sql" >}}

```sql
select * from t;
SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
PREPARE stmt FROM @s;
SET @a = 6;
SET @b = 8;
EXECUTE stmt USING @a, @b;
```

```
+------+
| a |
+------+
| 1 |
+------+
1 row in set (0.00 sec)
```

{{< copyable "sql" >}}

```sql
SET @col = "a";
```

```
Query OK, 0 rows affected (0.00 sec)
```

{{< copyable "sql" >}}

```sql
SELECT @col FROM t;
+------------+
| hypotenuse |
+------------+
| 10 |
+------------+
```

```
+------+
| @col |
+------+
| a |
+------+
1 row in set (0.00 sec)
```
用户自定义变量的内容不会在 SQL 语句中被当成标识符,例如:

{{< copyable "sql" >}}

```sql
SELECT `@col` FROM t;
SELECT * from t;
```

```
ERROR 1054 (42S22): Unknown column '@col' in 'field list'
+---+
| a |
+---+
| 1 |
+---+
```

{{< copyable "sql" >}}

```sql
SET @col = "`a`";
```

```
Query OK, 0 rows affected (0.00 sec)
```

{{< copyable "sql" >}}

```sql
SELECT @col FROM t;
```

Expand All @@ -203,44 +174,6 @@ SELECT @col FROM t;
+------+
| `a` |
+------+
1 row in set (0.01 sec)
```

但是在以下情况中,你可以在 PREPARE 语句中使用用户自定义变量:

{{< copyable "sql" >}}

```sql
PREPARE stmt FROM "SELECT @c FROM t";
```

```
Query OK, 0 rows affected (0.00 sec)
```

{{< copyable "sql" >}}

```sql
EXECUTE stmt;
```

```
+------+
| @c |
+------+
| a |
+------+
1 row in set (0.01 sec)
```

{{< copyable "sql" >}}

```sql
DEALLOCATE PREPARE stmt;
```

```
Query OK, 0 rows affected (0.00 sec)
```

更多[细节](https://dev.mysql.com/doc/refman/5.7/en/user-variables.html)。
更多细节,请参考 [MySQL 文档](https://dev.mysql.com/doc/refman/5.7/en/user-variables.html)。