Для конкретного процесса пользователь может определить локальные
переменные, которые в MySQL обозначаются как @variablename
. Имя локальной
переменной может состоять из буквенно-цифровых символов установленного в
данное время алфавита и символов `_', `$', and `.'. Тип кодировки по
умолчанию - ISO-8859-1 Latin1, он может быть изменен указанием иного типа
в аргументе параметра --default-character-set
mysqld
(see section 4.6.1 Набор символов, применяющийся для записи данных и сортировки).
Локальные переменные не требуют инициализации. Они содержат значение NULL
по умолчанию; в них могут храниться целые числа, вещественные числа или
строковые величины. При запуске конкретного процесса все объявленные в нем
локальные переменные автоматически активизируются.
Локальную переменную можно объявить, используя синтаксис команды SET
:
SET @variable= { integer expression | real expression | string expression } [,@variable= ...].
Можно также определить значение переменной иным способом, без команды SET
.
Однако в этом случае в качестве оператора присвоения более предпочтительно
использовать оператор `:=', чем оператор `=', так как последний
зарезервирован для сравнения выражений, не связанных с установкой
переменных:
mysql> SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3; +----------------------+------+------+------+ | @t1:=(@t2:=1)+@t3:=4 | @t1 | @t2 | @t3 | +----------------------+------+------+------+ | 5 | 5 | 1 | 4 | +----------------------+------+------+------+
Введенные пользователем переменные могут применяться только в составе
выражений и там, где выражения допустимы. Заметим, что в область их
применения в данное время не включается контекст, в котором явно требуется
число, например, условие LIMIT
в команде SELECT
или выражение IGNORE
number LINES
в команде LOAD DATA
.
Примечание: в команде SELECT
каждое выражение оценивается только при
отправлении клиенту. Это означает, что в условиях HAVING
, GROUP BY
, or
ORDER BY
не следует ссылаться на выражение, содержащее переменные,
которые введены в части SELECT
этой команды. Например, следующая команда
НЕ будет выполняться так, как ожидалось:
mysql> SELECT (@aa:=id) AS a, (@aa+3) AS b FROM table_name HAVING b=5;
Причина в том, что переменная @aa
не будет содержать значения текущей
строки, в то время как значение id
в предыдущем выражении является
строкой.
Действует правило никогда не создавать и не использовать
одну и ту же переменную в одном
и том же выражении SQL.
User Comments
Be aware that the following does NOT work:
SET @TABLENAME="db";
SELECT * FROM @TABLENAME;
Be warned that user variables also fail if they
are used in an aggregate function.
For example:
SELECT SUM(@myVal:=someDBfield * 2) AS field1,
SUM(@myVal * 2) AS field2 ...
will not return the answer that you are expecting!
Field2 will return with an incorrect value.
Would be it useful to add ability to store
lists
of values inside user variables, this could
then
be expanded within IN statements for example.
For example:
SELECT @list:=id FROM t1 WHERE ....
SELECT id FROM t2 WHERE id IN ( @list ) .....
Re: User variables in aggregate functions... I was
able to use user variables in aggregate functions if I
submitted query twice in the same session / thread.
Perhaps this isn't the most stable method to use
user variables but for the moment it seems to work.
Only time and load will tell if this method holds up
reliably.
You can get a cumulative total this way, like so:
SET @runningTotal:=0;
SELECT *,@runningTotal:=transaction_amount+@runningTotal AS running_total FROM customer_transaction
WOW, THIS IS GREAT!!! I just realized how powerful user variables are, especially when used with the IF command. Together, they basically give SQL some of the capabilities of a low-level procedural language! I'd used variables in MySQL before, but only for use on each row, not for use across multiple rows.
My mind's racing to come up with ways to apply this in my queries, but here's the first one I've come up with. We pull order data out of the database that has individual rows for each item ordered. The invoice number shows up on every row, but the client only wants it on the first line for each invoice. Till now I've had to dump the recordset into a file and process it with perl to take the duplicate invoice numbers out. But now, I can do that right in my SELECT statement:
SET @inv=0;
SELECT IF(@inv=invoice.id,'',@inv:=invoice.id), item.id, ...
FROM ...
WHERE ...
ORDER BY invoice.id, item.id;
Read the IF statement like this: IF the invoice number of the current line equals the variable value, THEN put an empty string in the field, ELSE put the invoice number in the field and set it as the new value for the variable. Note that the ORDER BY clause is important, as it assures that the rows will be processed in proper order - in this case, all the items for each invoice.
RE
SELECT @list:=id FROM t1 WHERE ....
SELECT id FROM t2 WHERE id IN ( @list ) .....
HOW ABOUT THIS:
set @list := ',';
select @list := CONCAT(@list, id, ',') from t1 where ....;
select id from t2 where @list LIKE CONCAT('%,', id,',%')
work perfectly
even though you cant pass variables to functions requiring numbers (ORDER BY etc), you can create an alias and pass that to the function instead.
eg,
SELECT id,@match:=(if($question = field,1,0)) AS matches FROM table ORDER BY matches DESC LIMIT 20;
note this query was written to basically return relevance on multiple field matches if that helps anyone :-)
select @a, table.*
from table
where (@a:=(IF(t_num1=1,10,0)+IF(t_num2=2,5,0))) >5
пЮАНРЮЕР!
Add your own comment.