MySQL: @variable vs variable. Quelle est la différence?

501

Dans une autre question que j'ai postée, quelqu'un m'a dit qu'il y avait une différence entre:

@variable

et:

variable

dans MySQL. Il a également mentionné comment MSSQL a une portée de lot et MySQL a une portée de session. Quelqu'un peut-il m'expliquer cela?

aarona
la source
1
Je connais MsSQL et donc l'idée ne m'est jamais venue à l'esprit de poser une telle question. Les réponses fournies ici m'ont permis de comprendre quelque chose dont je n'avais aucune idée !! Thx ..
Ken

Réponses:

624

MySQLa le concept de variables définies par l'utilisateur .

Ce sont des variables de type lâche qui peuvent être initialisées quelque part dans une session et conserver leur valeur jusqu'à la fin de la session.

Ils sont précédés d'un @signe, comme ceci:@var

Vous pouvez initialiser cette variable avec une SETinstruction ou à l'intérieur d'une requête:

SET @var = 1

SELECT @var2 := 2

Lorsque vous développez une procédure stockée dans MySQL, vous pouvez passer les paramètres d'entrée et déclarer les variables locales:

DELIMITER //

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

DELIMITER ;

Ces variables ne sont précédées d'aucun préfixe.

La différence entre une variable de procédure et une variable définie par l'utilisateur spécifique à la session est que la variable de procédure est réinitialisée à NULLchaque appel de la procédure, tandis que la variable spécifique à la session n'est pas:

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

Comme vous pouvez le voir, var2(variable de procédure) est réinitialisée à chaque appel de la procédure, tandis que@var2 contrairement à (variable propre à la session).

(En plus des variables définies par l'utilisateur, MySQL possède également des "variables système" prédéfinies, qui peuvent être des "variables globales" telles que @@global.portou des "variables de session" telles que @@session.sql_mode; ces "variables de session" ne sont pas liées aux définitions d'utilisateur spécifiques à la session variables.)

Quassnoi
la source
43
Notez également que des variables globales sont disponibles: voir SELECT @@version;par exemple. C'est aussi une raison pour laquelle l'utilisation DELIMITER @@n'est pas vraiment une bonne idée.
Mchl
13
cela pose de nouvelles questions pour les nouveaux venus ... y a-t-il une différence entre "var = var" et "var: = var" comme dans votre exemple?
confiq
13
@confiq: il n'y en a pas.
Quassnoi
10
Une autre question pour un nouveau venu. Quand est-il recommandé d'utiliser @vs non?
pixelfreak
73
@confiq, @Quassnoi: il y a une différence significative entre :=et =, et c'est que cela :=fonctionne comme un opérateur d'affectation de variable partout, alors qu'il =ne fonctionne que de cette façon dans les SETinstructions, et est un opérateur de comparaison partout ailleurs. Donc, SELECT @var = 1 + 1;va laisser @var inchangé et retourner un booléen (1 ou 0 selon la valeur actuelle de @var), tandis que SELECT @var := 1 + 1;changera @var à 2 et retournera 2.
Dewi Morgan
71

Dans MySQL, @variableindique une variable définie par l' utilisateur . Vous pouvez définir le vôtre.

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

En dehors des programmes stockés, a variable, sans @, est une variable système que vous ne pouvez pas définir vous-même.

La portée de cette variable est la session entière. Cela signifie que bien que votre connexion à la base de données existe, la variable peut toujours être utilisée.

Cela contraste avec MSSQL, où la variable ne sera disponible que dans le lot actuel de requêtes (procédure stockée, script ou autre). Il ne sera pas disponible dans un lot différent dans la même session.

molf
la source
2
Ne pas confondre avec les variables de session, qui ont le raccourci SET @@a = 'test';, cf. dev.mysql.com/doc/refman/5.1/en/set-statement.html
RobM
@RobM, elles sont appelées variables système , pas des variables de session.
Pacerier
1
@Pacerier: ai-je mal lu les documents? "" "Pour indiquer explicitement qu'une variable est une variable de session, faites précéder son nom de SESSION, @@ session. Ou @@." ""
RobM
5
@RobM, vous le lisez mal. Lisez le paragraphe entier, pas seulement le paragraphe dans la puce. En termes simples, il existe deux types de variables de session: 1) les variables de session définies par l'utilisateur et 2) les  variables de session définies par le système . Vous ne pouvez pas définir une variable de session définie par l'utilisateur à l'aide de @@. Par exemple, set@@my_var=1, set@@session.my_var=1et set session my_var=1ne fonctionnerait pas parce que my_varn'est pas un système variable alors que nous pouvons faire set@@big_tables=1, set@@session.big_tables=1et set session big_tables=1parce big_tablesest une variable système.
Pacerier
1
@GovindRai: Dans la réponse de Quassnoi, var2est une variable sans @préfixe, mais ce n'est pas une variable système: c'est une variable de procédure. Ceci est autorisé car il se trouve dans une procédure stockée (aka programme stocké). En dehors des procédures stockées, une variable sans @est une variable système.
LarsH
10

MSSQL requiert que les variables dans les procédures soient DECLAREd et les gens utilisent la syntaxe @Variable (DECLARE @TEXT VARCHAR (25) = 'text'). En outre, MS autorise les déclarations dans n'importe quel bloc de la procédure, contrairement à mySQL qui nécessite tous les DECLARE en haut.

Bien que bon sur la ligne de commande, je pense que l'utilisation de "set = @variable" dans les procédures stockées dans mySQL est risquée. Il n'y a pas de portée et les variables vivent à travers les limites de la portée. Ceci est similaire aux variables en JavaScript déclarées sans le préfixe "var", qui sont alors l'espace de noms global et créent des collisions et des écrasements inattendus.

J'espère que les bonnes personnes de mySQL permettront DECLARE @Variable à différents niveaux de bloc dans une procédure stockée. Remarquez le @ (au signe). Le préfixe @ sign permet de séparer les noms de variables des noms de colonnes de table - car ils sont souvent les mêmes. Bien sûr, on peut toujours ajouter un préfixe "v" ou "l_", mais le signe @ est un moyen pratique et succinct pour que le nom de la variable corresponde à la colonne dont vous pourriez extraire les données sans les encombrer.

MySQL est nouveau dans les procédures stockées et ils ont fait du bon travail pour leur première version. Ce sera un plaisir de voir où ils prennent forme ici et de regarder les aspects côté serveur de la langue mûrir.

Xybo
la source
3

En principe, j'utilise UserDefinedVariables (précédé de @) dans les procédures stockées. Cela rend la vie plus facile, surtout lorsque j'ai besoin de ces variables dans deux ou plusieurs procédures stockées. Juste au moment où j'ai besoin d'une variable uniquement dans UNE procédure stockée, j'utilise une variable système (sans @ ajouté).

@Xybo: Je ne comprends pas pourquoi l'utilisation de @variables dans StoredProcedures devrait être risquée. Pourriez-vous s'il vous plaît expliquer un peu plus facilement «portée» et «limites» (pour moi en tant que nouveau)?

Peter
la source
3
Cela viole les principes de base de l'ingénierie logicielle. Veuillez ne pas écrire une autre ligne de code tant que vous ne savez pas exactement quelle est la portée et pourquoi l'utilisation de variables globales est généralement une idée terrible. Lorsque j'ai suivi 101 cours de programmation, je me souviens que l'utilisation d'un global pour à peu près n'importe quoi se traduirait par un "F" automatique. Il existe des exceptions spéciales, mais en règle générale - ne le faites pas!
BuvinJ
Pourquoi? - Les @Variables sont absolument communes dans tous les livres MySQL.
Peter
Bien sûr, dans un script "plat" sans appels de fonction, procédures, déclencheurs, etc. et si vous allez simplement exécuter ce script simple, ou un ensemble limité de commandes, puis terminer la session (détruisant ainsi vos globaux). Dans ce cas, allez-y et utilisez-les si vous le souhaitez. Mais NE PAS les utiliser dans une fonction! Si vous utilisez simplement les variables globales ou la portée de Google, vous trouverez instantanément un large soutien à l'idée qu'elles sont universellement désapprouvées. Voici un point de départ: wiki.c2.com/?GlobalVariablesAreBad ou pour une explication plus générale: en.wikipedia.org/wiki/Global_variable
BuvinJ
2
Dans MySQL, les @variables sont globales. Cela se confirme facilement. Définissez-en une à l'extérieur d'une fonction, puis évaluez-la à l'intérieur d'une. Inversement, définissez-en une à l'intérieur d'une fonction et évaluez-la à l'extérieur. Vous verrez que la fonction ne protège pas la portée de tels. Ils marchent l'un sur l'autre.
BuvinJ
1
En utilisant la terminologie MySQL, les @@GLOBALvariables sont encore plus «globales» et insidieuses. Ils traversent les sessions! @variablesont "portée de session", donc au moins ils restent confinés de cette manière. Dans tout langage normal, c'est ce que vous appelez la portée "globale" (quand ils croisent des fonctions, etc.). Le concept MySQL de «global» devrait peut-être être appelé «universel», dans la mesure où il s'étend au-delà des limites du processus qui l'exécute. Un «global» ne peut normalement pas faire cela dans un langage standard, car les processus ne partagent pas l'espace mémoire. Cela découle de la tendance persistante (vs volatile) de SQL.
BuvinJ