11.4 Переменные, определенные пользователем
Вы можете сохранить значение в переменной, определенной пользователем, в одном операторе и обратиться к нему позже в другом операторе. Это позволяет передавать значения из одного оператора в другой.
Переменные пользователя записываются как @, где имя переменной var_namevar_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, а тип — строка.
Ссылка на переменную пользователя в подготовленном операторе определяет её тип при первом подготовке оператора и сохраняет этот тип при каждом последующем выполнении оператора. Аналогично, тип переменной пользователя, используемой в операторе внутри хранимой процедуры, определяется при первом вызове хранимой процедуры и сохраняется при каждом последующем вызове.
Переменные пользователей могут быть использованы в большинстве контекстов, где разрешены выражения. Это не относится к контекстам, которые явно требуют литерального значения, например, в клаузе LIMIT оператора SELECT или в клаузе IGNORE оператора N LINESLOAD DATA.
В предыдущих версиях MySQL было возможно присвоить значение переменной пользователя в операторах, отличных от SET. Эта функциональность поддерживается в MySQL 9.2 для обратной совместимости, но может быть удалена в будущих выпусках MySQL.
При таком присваивании необходимо использовать := в качестве оператора присваивания; = обрабатывается как оператор сравнения в операторах, отличных от SET.
Порядок вычисления выражений, включающих переменные пользователя, не определен. Например, нет гарантии, что SELECT @a, @a:=@a+1 вычисляет @a в первую очередь, а затем выполняет присваивание.
Кроме того, тип результата по умолчанию для переменной зависит от её типа в начале оператора. Это может привести к непредвиденным последствиям, если переменная содержит значение одного типа в начале оператора, в котором ей также присваивается новое значение другого типа.
Чтобы избежать проблем с этим поведением, либо не присваивайте значение и не читайте значение одной и той же переменной в одном операторе, либо установите переменную в 0, 0.0 или '' для определения её типа до использования.
HAVING, GROUP BY и ORDER 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”.
© 2025 Oracle
Licensed under the GPLv2 License.