Spec-Zone.ru › MySQL 5.7

9.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, а тип — строка.

Переменные, определённые пользователем, могут использоваться в большинстве контекстов, где разрешены выражения. Это не включает контексты, которые явно требуют буквального значения, например, в предложении LIMIT оператора SELECT или в предложении IGNORE N LINES оператора LOAD DATA.

Также возможно присвоить значение переменной пользователя в операторах, отличных от SET. (Эта функциональность устарела в MySQL 8.0 и может быть удалена в последующем выпуске.) При выполнении присваивания таким образом, оператор присваивания должен быть :=, а не =, так как последний рассматривается как оператор сравнения = в операторах, отличных от SET:

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

В общем случае, кроме операторов SET, вы никогда не должны присваивать значение переменной пользователя и считывать это значение в одном и том же операторе. Например, для инкремента переменной это допустимо:

SET @a = @a + 1;

Для других операторов, таких как SELECT, вы можете получить ожидаемые результаты, но это не гарантировано. В следующем операторе вы можете подумать, что MySQL вычисляет @a сначала, а затем выполняет присваивание во второй раз:

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

Однако порядок вычисления выражений, включающих переменные пользователя, не определён.

Ещё одна проблема с присвоением значения переменной и чтением значения в одном операторе, не являющемся SET, заключается в том, что тип результата по умолчанию для переменной основан на её типе в начале оператора. Следующий пример иллюстрирует это:

mysql> SET @a='test';
mysql> SELECT @a,(@a:=20) FROM tbl_name;

Для этого оператора SELECT, MySQL сообщает клиенту, что столбец один — строка, и преобразует все обращения к @a в строки, даже если @a задано числом для второй строки. После выполнения оператора SELECT, @a рассматривается как число для следующего оператора.

Чтобы избежать проблем с этим поведением, либо не присваивайте значение и не считывайте значение одной и той же переменной в одном операторе, либо задайте переменной 0, 0.0 или '', чтобы определить её тип до использования.

В операторе SELECT каждое выражение select вычисляется только при отправке клиенту. Это означает, что в предложении HAVING, GROUP BY или ORDER BY ссылка на переменную, которой присвоено значение в списке выражений select, не работает так, как ожидается:

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

Ссылка на b в предложении HAVING относится к псевдониму для выражения в списке select, который использует @aa. Это не работает так, как ожидается: @aa содержит значение id из предыдущей выбранной строки, а не из текущей.

Переменные, определённые пользователем, предназначены для предоставления значений данных. Их нельзя напрямую использовать в операторе 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)

См. Раздел 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());

  $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.
https://docs.oracle.com/cd/E17952_01/mysql-5.7-en/user-variables.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API