MySQL: @variable vs. variable. Was ist der Unterschied?

501

In einer anderen Frage, die ich gestellt habe, hat mir jemand gesagt, dass es einen Unterschied gibt zwischen:

@variable

und:

variable

in MySQL. Er erwähnte auch, wie MSSQL einen Batch-Bereich und MySQL einen Sitzungsbereich hat. Kann mir jemand das näher erläutern?

aarona
quelle
1
Ich bin mit MsSQL vertraut und so kam mir nie der Gedanke, eine solche Frage zu stellen. Die hier gegebenen Antworten haben mich auf etwas hingewiesen, von dem ich keine Ahnung hatte !! Thx ..
Ken

Antworten:

624

MySQLhat das Konzept von benutzerdefinierten Variablen .

Es handelt sich um lose typisierte Variablen, die möglicherweise irgendwo in einer Sitzung initialisiert werden und ihren Wert bis zum Ende der Sitzung beibehalten.

Ihnen ist ein @Schild wie folgt vorangestellt :@var

Sie können diese Variable mit einer SETAnweisung oder in einer Abfrage initialisieren :

SET @var = 1

SELECT @var2 := 2

Wenn Sie eine gespeicherte Prozedur in entwickeln MySQL, können Sie die Eingabeparameter übergeben und die lokalen Variablen deklarieren:

DELIMITER //

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

DELIMITER ;

Diesen Variablen werden keine Präfixe vorangestellt.

Der Unterschied zwischen einer Prozedurvariablen und einer sitzungsspezifischen benutzerdefinierten Variablen besteht darin, dass die Prozedurvariable bei NULLjedem Aufruf der Prozedur neu initialisiert wird, während die sitzungsspezifische Variable nicht:

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

Wie Sie sehen können, wird var2(Prozedurvariable) bei jedem Aufruf der Prozedur neu initialisiert, während dies bei @var2(sitzungsspezifischer Variable) nicht der Fall ist.

(Zusätzlich zu benutzerdefinierten Variablen verfügt MySQL auch über einige vordefinierte "Systemvariablen", bei denen es sich um "globale Variablen" @@global.portoder "Sitzungsvariablen" handeln kann @@session.sql_mode. Diese "Sitzungsvariablen" stehen in keinem Zusammenhang mit sitzungsspezifischen benutzerdefinierten Variablen Variablen.)

Quassnoi
quelle
43
Beachten Sie auch, dass globale Variablen verfügbar sind: Siehe SELECT @@version;zum Beispiel. Dies ist auch ein Grund, warum die Verwendung DELIMITER @@keine wirklich gute Idee ist.
Mchl
13
es stellt neue Fragen für Newcomes ... gibt es einen Unterschied zwischen "var = var" und "var: = var" wie in Ihrem Beispiel?
Confiq
13
@confiq: Es gibt keine.
Quassnoi
10
Eine andere Frage für einen Neuling. Wann wird empfohlen, @vs nicht zu verwenden?
Pixelfreak
73
@confiq, @Quassnoi: Es gibt einen signifikanten Unterschied zwischen :=und =, und zwar, dass er :=überall als Operator für die Zuweisung von Variablen =funktioniert , während er nur in SETAnweisungen so funktioniert und überall ein Vergleichsoperator ist. So SELECT @var = 1 + 1;wird @var unverändert lassen und einen boolean zurückgeben (1 oder 0 auf dem aktuellen Wert von @var abhängig), während SELECT @var := 1 + 1;wird @var bis 2 ändern, und zurück 2.
Dewi Morgan
71

Gibt in MySQL @variableeine benutzerdefinierte Variable an . Sie können Ihre eigenen definieren.

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

Außerhalb gespeicherter Programme ist a variableohne @eine Systemvariable , die Sie nicht selbst definieren können.

Der Umfang dieser Variablen ist die gesamte Sitzung. Das heißt, während Ihre Verbindung mit der Datenbank besteht, kann die Variable weiterhin verwendet werden.

Dies steht im Gegensatz zu MSSQL, wo die Variable nur im aktuellen Stapel von Abfragen (gespeicherte Prozedur, Skript oder auf andere Weise) verfügbar ist. Es wird in derselben Sitzung nicht in einem anderen Stapel verfügbar sein.

molf
quelle
2
Nicht zu verwechseln mit Sitzungsvariablen, die die Kurzform haben SET @@a = 'test';, vgl. dev.mysql.com/doc/refman/5.1/en/set-statement.html
RobM
@RobM, Sie werden Systemvariablen genannt , keine Sitzungsvariablen.
Pacerier
1
@ Pacerier: Lese ich die Dokumente falsch? "" Um explizit anzugeben, dass eine Variable eine Sitzungsvariable ist, stellen Sie vor ihrem Namen SESSION, @@ session. Oder @@. ""
RobM
5
@RobM, du liest es falsch. Lesen Sie den gesamten Absatz durch, nicht nur den Absatz innerhalb des Aufzählungspunkts. Einfach gesagt, zwei Arten von Session - Variablen sind: 1) Benutzerdefinierte Sitzungsvariablen und 2) System  -defined Session - Variablen. Sie können mit nicht eine benutzerdefinierte Sitzungsvariable festlegen @@. Zum Beispiel set@@my_var=1, set@@session.my_var=1und set session my_var=1arbeitet nicht , weil ich my_varnicht um eine Systemvariable, während wir tun können set@@big_tables=1, set@@session.big_tables=1und set session big_tables=1da big_tablesist eine Systemvariable.
Pacerier
1
@GovindRai: In Quassnois Antwort var2ist eine Variable ohne @Präfix, aber keine Systemvariable: Es ist eine Prozedurvariable. Dies ist zulässig, da es sich um eine gespeicherte Prozedur (auch als gespeichertes Programm bezeichnet) handelt. Außerhalb gespeicherter Prozeduren ist eine Variable ohne @eine Systemvariable.
LarsH
10

MSSQL erfordert, dass Variablen in Prozeduren DECLAREd sind und die Benutzer die @ Variable-Syntax verwenden (DECLARE @TEXT VARCHAR (25) = 'text'). Außerdem erlaubt MS Deklarationen innerhalb eines beliebigen Blocks in der Prozedur, im Gegensatz zu mySQL, für das alle DECLAREs oben erforderlich sind.

Obwohl ich gut in der Befehlszeile bin, halte ich die Verwendung von "set = @variable" in gespeicherten Prozeduren in mySQL für riskant. Es gibt keinen Bereich und Variablen leben über Bereichsgrenzen hinweg. Dies ähnelt Variablen, die in JavaScript ohne das Präfix "var" deklariert werden. Dies ist dann der globale Namespace und führt zu unerwarteten Kollisionen und Überschreibungen.

Ich hoffe, dass die guten Leute bei mySQL DECLARE @Variable auf verschiedenen Blockebenen innerhalb einer gespeicherten Prozedur zulassen. Beachten Sie das @ (am Zeichen). Das @ -Zeichenpräfix hilft dabei, Variablennamen von Tabellenspaltennamen zu trennen, da diese häufig identisch sind. Natürlich kann man immer ein "v" - oder "l_" -Präfix hinzufügen, aber das @ -Zeichen ist eine praktische und prägnante Möglichkeit, den Variablennamen mit der Spalte abzugleichen, aus der Sie möglicherweise die Daten extrahieren, ohne sie zu beschädigen.

MySQL ist neu in gespeicherten Prozeduren und sie haben für ihre erste Version gute Arbeit geleistet. Es wird ein Vergnügen sein zu sehen, wo sie hier Gestalt annehmen und die serverseitigen Aspekte der Sprache reifen zu sehen.

Xybo
quelle
3

Im Prinzip verwende ich UserDefinedVariables (mit @ vorangestellt) in gespeicherten Prozeduren. Dies erleichtert das Leben, insbesondere wenn ich diese Variablen in zwei oder mehr gespeicherten Prozeduren benötige. Nur wenn ich eine Variable nur innerhalb EINER gespeicherten Prozedur benötige, verwende ich eine Systemvariable (ohne vorangestelltes @).

@Xybo: Ich verstehe nicht, warum die Verwendung von @variables in StoredProcedures riskant sein sollte. Könnten Sie bitte "Umfang" und "Grenzen" etwas einfacher erklären (für mich als Neuling)?

Peter
quelle
3
Dies verstößt gegen grundlegende Prinzipien der Softwareentwicklung. Bitte schreiben Sie keine weitere Codezeile, bis Sie genau wissen, was der Bereich ist und warum die Verwendung globaler Variablen im Allgemeinen eine schreckliche Idee ist. Wenn ich 101 Programmierkurse belegte, würde, wie ich mich erinnere, die Verwendung eines Global für so ziemlich alles zu einem automatischen "F" führen. Es gibt spezielle Ausnahmen, aber in der Regel - tun Sie es einfach nicht!
BuvinJ
Warum? - @Variablen sind in jedem MySQL-Buch absolut üblich.
Peter
Sicher, in einem "flachen" Skript ohne Funktionsaufrufe, Prozeduren, Trigger usw. und wenn Sie nur dieses einfache Skript oder einen begrenzten Satz von Befehlen ausführen und dann die Sitzung beenden (wodurch Ihre globalen Elemente zerstört werden). In diesem Fall können Sie sie verwenden, wenn Sie möchten. Aber NICHT in einer Funktion verwenden! Wenn Sie einfach globale Variablen oder Bereiche von Google verwenden, werden Sie sofort große Unterstützung für die Idee finden, dass sie allgemein verpönt sind. Hier ist ein Ausgangspunkt: wiki.c2.com/?GlobalVariablesAreBad oder für eine allgemeinere Erklärung: en.wikipedia.org/wiki/Global_variable
BuvinJ
2
In MySQL sind @variables global. Dies ist leicht zu bestätigen. Stellen Sie eine außerhalb einer Funktion ein und werten Sie sie dann innerhalb einer aus. Stellen Sie umgekehrt eine innerhalb einer Funktion ein und werten Sie sie außerhalb aus. Sie werden sehen, dass die Funktion den Umfang solcher nicht schützt. Sie treten sich gegenseitig auf die Zehen.
BuvinJ
1
Mit der MySQL-Terminologie sind @@GLOBALVariablen noch "globaler" und heimtückischer. Sie kreuzen Sitzungen! @variableshaben "Sitzungsumfang", so dass sie zumindest auf diese Weise beschränkt bleiben. In jeder normalen Sprache wird dies jedoch als "globaler" Bereich bezeichnet (wenn sie Funktionen usw. kreuzen). Das MySQL-Konzept von "global" sollte vielleicht als "universell" bezeichnet werden, da es über die Grenzen des Prozesses hinausgeht, in dem es ausgeführt wird. Ein "globaler" Benutzer kann dies normalerweise nicht in einer Standardsprache tun, da Prozesse keinen gemeinsamen Speicherplatz nutzen. Dies ist auf die anhaltende (vs volatile) Tendenz von SQL zurückzuführen.
BuvinJ