MySQL: @ варіабельна порівняно зі змінною. Яка різниця?


500

В іншому запитанні, який я розмістив, хтось сказав мені, що є різниця між:

@variable

і:

variable

в MySQL. Він також згадав, як MSSQL має пакетний обсяг, а MySQL - обсяг сеансу. Може хтось докладно розробить це для мене?


1
Я знайомий з MsSQL і тому мені ніколи не спадало на думку, щоб задати таке питання. Надані тут відповіді втягнули мене в те, про що я не мав ідеї !! Thx ..
Кен

Відповіді:


623

MySQLмає поняття визначених користувачем змінних .

Вони є типово зміненими змінними, які можуть бути ініціалізовані десь у сеансі і зберігати своє значення до закінчення сеансу.

Вони знаходяться перед цим @знаком:@var

Ви можете ініціалізувати цю змінну із SETзаявою або всередині запиту:

SET @var = 1

SELECT @var2 := 2

Коли ви розробляєте збережену процедуру в MySQL, ви можете передавати параметри вводу та оголошувати локальні змінні:

DELIMITER //

CREATE PROCEDURE prc_test (var INT)
BEGIN
    DECLARE  var2 INT;
    SET var2 = 1;
    SELECT  var2;
END;
//

DELIMITER ;

Ці змінні не претендують на будь-які префікси.

Різниця між змінною процедури та визначеною користувачем змінною полягає в тому, що змінна процедури повторно ініціалізується NULLщоразу, коли процедура викликається, тоді як змінна, що стосується сеансу, не є:

CREATE PROCEDURE prc_test ()
BEGIN
    DECLARE var2 INT DEFAULT 1;
    SET var2 = var2 + 1;
    SET @var2 = @var2 + 1;
    SELECT  var2, @var2;
END;

SET @var2 = 1;

CALL prc_test();

var2  @var2
---   ---
2     2


CALL prc_test();

var2  @var2
---   ---
2     3


CALL prc_test();

var2  @var2
---   ---
2     4

Як бачимо, var2(змінна процедура) повторно ініціалізується щоразу, коли процедура викликається, в той час@var2 (змінна для сеансу) - ні.

(Крім визначених користувачем змінних, MySQL також має деякі заздалегідь визначені "системні змінні", які можуть бути "глобальними змінними", такими як @@global.port"сесійні змінні", наприклад @@session.sql_mode; ці "сесійні змінні" не пов'язані з певними сеансом, визначеними користувачем. змінні.)


43
Також врахуйте, що доступні глобальні змінні: Див SELECT @@version;., Наприклад. Це також причина, чому використання DELIMITER @@насправді не є хорошою ідеєю.
Mchl

13
це ставить нові запитання щодо нових результатів ... чи є різниця між "var = var" та "var: = var", як у вашому прикладі?
confiq

13
@confiq: його немає.
Quassnoi

9
Ще одне питання для новачка. Коли рекомендується використовувати @vs ні?
pixelfreak

73
@confiq, @Quassnoi: є одна суттєва різниця між :=і =, і це те, що він :=працює як оператор присвоєння змінної скрізь, в той час як =тільки так працює в SETоператорах і є оператором порівняння скрізь. Тож SELECT @var = 1 + 1;залиште @var незмінним та повернемо булеве значення (1 або 0 залежно від поточного значення @var), тоді як SELECT @var := 1 + 1;змінимо @var на 2 та повернемося 2.
Dewi Morgan

71

У MySQL @variableвказує визначену користувачем змінну . Ви можете визначити своє.

SET @a = 'test';
SELECT @a;

Поза збереженими програмами variable, без @, це системна змінна , яку ви не можете самостійно визначити.

Обсяг цієї змінної - весь сеанс. Це означає, що хоча ваш зв’язок із базою даних існує, змінна все ще може бути використана.

Це на відміну від MSSQL, де змінна буде доступна лише в поточній партії запитів (збережена процедура, сценарій чи інше). Він не буде доступний в іншій партії в одному сеансі.


2
Не плутати з змінними сеансу, які мають скорочення SET @@a = 'test';, пор. dev.mysql.com/doc/refman/5.1/uk/set-statement.html
RobM

@RobM, Вони називаються системними змінними, а не змінними сеансами.
Pacerier

1
@Pacerier: Чи читаю я документи неправильно? "" "Щоб чітко вказати, що змінна є змінною сеансу, передуйте її імені SESSION, @@ session. Або @@." ""
RobM

5
@RobM, ти читаєш це неправильно. Прочитайте весь абзац, а не лише абзац у точці відбитка. Простіше кажучи, є два види змінних сеансів: 1) визначені користувачем змінні сеансу та 2) визначені системою  змінні сеансу. Не можна встановити визначену користувачем змінну сеансу за допомогою @@. Так , наприклад, set@@my_var=1, set@@session.my_var=1і set session my_var=1не працюватиме , тому що my_varне є система змінної, в той час як ми можемо зробити set@@big_tables=1, set@@session.big_tables=1і set session big_tables=1тому , що big_tablesце системна змінна.
Pacerier

1
@GovindRai: У відповіді Quassnoi var2- це змінна без @префікса, але це не системна змінна: це змінна процедура. Це дозволено, оскільки це знаходиться в збереженій процедурі (він же зберігається програма). Поза збереженими процедурами змінна без @- це системна змінна.
LarsH

10

MSSQL вимагає, щоб змінні в рамках процедур були DECLAREd, а люди використовують синтаксис @Variable (DECLARE @TEXT VARCHAR (25) = 'текст'). Крім того, MS дозволяє декларувати в будь-якому блоці процедури, на відміну від mySQL, який вимагає всіх DECLARE вгорі.

Хоча це добре в командному рядку, я вважаю, що використання "set = @variable" у збережених процедурах в mySQL є ризиковим. Немає сфери застосування і змінні живуть за межами меж області. Це схоже на те, що змінні в JavaScript оголошуються без префіксу "var", які потім є глобальним простором імен і створюють несподівані зіткнення та перезаписи.

Я сподіваюся, що хороші люди в mySQL дозволять DECLARE @Variable на різних рівнях блоку в межах збереженої процедури. Помітьте @ (на знак). Префікс знаку @ допомагає відокремити імена змінних від назв стовпців таблиці - оскільки вони часто однакові. Звичайно, завжди можна додати префікс "v" або "l_", але знак @ - це зручний і стислий спосіб, щоб ім'я змінної відповідало стовпцю, з якого ви могли б витягувати дані, не переробляючи їх.

MySQL є новим для збережених процедур, і вони зробили хорошу роботу для своєї першої версії. Буде закликом побачити, де вони приймають його форму тут, і спостерігати за тим, як серверні аспекти мови дозрівають.


3

В принципі, я використовую UserDefinedVariables (попередньо за допомогою @) в межах збережених процедур. Це полегшує життя, особливо коли мені потрібні ці змінні у двох чи більше збережених процедурах. Якраз тоді, коли мені потрібна змінна лише в межах однієї збереженої процедури, ніж я використовую системну змінну (без попереднього @).

@Xybo: Я не розумію, чому використання @variables у StoredProcedures має бути ризикованим. Не могли б ви пояснити "поле" та "межі" трохи простіше (для мене як для новачків)?


3
Це порушує основні принципи інженерії програмного забезпечення. Будь ласка, не пишіть рядок коду, поки ви точно не дізнаєтесь, що таке область, і чому використання глобальних змінних, як правило, страшна ідея. Коли я взяв 101 клас програмування, як я пам'ятаю, використання глобального для майже нічого не призвело б до автоматичного "F". Є особливі винятки, але, як правило, просто не робіть цього!
BuvinJ

Чому? - @Variables абсолютно поширені у всіх MySQL-книгах.
Пітер

Звичайно, у "плоскому" скрипті без викликів функцій, процедур, тригерів тощо, і якщо ви просто збираєтеся виконати простий скрипт або обмежений набір команд, а потім закінчите сеанс (тим самим знищуючи глобали). У такому випадку, продовжуйте користуватися ними, якщо хочете. Але НЕ використовуйте їх всередині функції! Якщо ви просто глобальні змінні чи сфера застосування Google, миттєво знайдете широку підтримку ідеї, що вони повсюдно нахмурені. Ось відправна точка: wiki.c2.com/?GlobalVariablesAreBad або для більш загального пояснення: en.wikipedia.org/wiki/Global_variable
BuvinJ

2
У MySQL @variables є глобальними. Це легко підтвердити. Встановіть одну поза функції, а потім оцініть її всередині однієї. І навпаки, встановіть одну внутрішню функцію та оцініть її поза нею. Ви побачите, що функція не захищає область таких. Вони наступають один на одного пальцями ніг.
BuvinJ

1
Використовуючи термінологію MySQL, @@GLOBALзмінні ще більш "глобальні" та підступні. Вони перетинають сесії! @variablesмають "сферу сеансу", тож принаймні вони залишаються обмеженими таким чином. Однак будь-якою нормальною мовою ви називаєте "глобальну" сферу (коли вони перетинають функції тощо). Поняття MySQL "глобального", можливо, слід назвати "універсальним", оскільки воно виходить за межі процесу, що його працює. "Глобальний" не може цього робити звичайною мовою, оскільки процеси не поділяють місця в пам'яті. Це випливає із стійкої (проти мінливої) тенденції SQL.
BuvinJ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.