MySQL:@variable与变量。有什么不同?


500

在另一个问题中,我发布了一个人告诉我,两者之间是有区别的:

@variable

和:

variable

在MySQL中。他还提到了MSSQL如何具有批处理范围,而MySQL如何具有会话范围。有人可以为我详细说明吗?


1
我对MsSQL很熟悉,因此我从未想到问这样的问题。这里提供的答案使我陷入了我没有想法的事情!Thx ..
Ken

Answers:


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 2011年

13
这就给新产品带来了新问题……在您的示例中,“ var = var”和“ var:= var”之间有什么区别吗?
确认2012年

13
@confiq:没有。
Quassnoi 2012年

9
新人的另一个问题。建议何时使用@vs不使用?
pixelfreak 2012年

73
@ confiq,@ Quassnoi::=和之间有一个明显的区别=,那就是它:=在任何地方都可以用作变量赋值运算符,而=仅在SET语句中可以那样工作,而在其他地方则是比较运算符。这样SELECT @var = 1 + 1;会留下@var不变,并返回一个布尔值(1或0取决于@var的电流值),而SELECT @var := 1 + 1;将@var更改为2,然后返回2
迪尤·摩根

71

在MySQL中,@variable表示用户定义的变量。您可以定义自己的。

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

在存储程序之外variable,不带的@系统变量,您无法定义自己。

此变量的范围是整个会话。这意味着,尽管您与数据库的连接存在,但仍可以使用该变量。

这与MSSQL相反,在MSSQL中,变量仅在当前的查询批次(存储过程,脚本或其他)中可用。在同一会话中,将不能以其他批次使用它。


2
不要与会话变量混淆,后者具有速记SET @@a = 'test';cf。dev.mysql.com/doc/refman/5.1/en/set-statement.html
ROBM

@RobM,它们称为系统变量,而不是会话变量。
和平者

1
@Pacerier:我看错文档了吗?“”“要明确表示变量是会话变量,请在其名称前加上SESSION,@@ session。或@@。”“”
RobM 2015年

5
@RobM,您读错了。通读整个段落,而不仅仅是通篇内的段落。简而言之,有两种会话变量:1)用户定义的会话变量,和2)系统  定义的会话变量。您不能使用来设置用户定义的会话变量@@。例如set@@my_var=1set@@session.my_var=1set session my_var=1是行不通的,因为my_var不是一个系统变量,而我们能做的set@@big_tables=1set@@session.big_tables=1以及set session big_tables=1因为big_tables是一个系统变量。
和平者

1
@GovindRai:在Quassnoi的回答中,它var2是一个没有@前缀的变量,但它不是系统变量:它是一个过程变量。允许这样做,因为它位于存储过程(也称为存储程序)中。在存储过程之外,没有的变量@是系统变量。
LarsH

10

MSSQL要求过程中的变量为DECLAREd,人们使用@Variable语法(DECLARE @TEXT VARCHAR(25)='text')。而且,MS允许在过程的任何块中进行声明,这与mySQL要求在顶部的所有DECLARE不同。

虽然在命令行上不错,但我认为在mySQL的存储过程中使用“ set = @variable”是有风险的。没有作用域,变量跨越作用域边界。这类似于在JavaScript中声明的不带“ var”前缀的变量,它们随后是全局名称空间,并会产生意外的冲突和覆盖。

我希望mySQL的优秀人士将允许在存储过程的各个块级别使用DECLARE @Variable。注意@(在符号处)。@符号前缀有助于将变量名与表列名分开-因为它们通常是相同的。当然,总是可以添加“ v”或“ l_”前缀,但是@符号是一种方便且简洁的方法,可以使变量名与您要从中提取数据的列匹配而不会破坏数据。

MySQL是存储过程的新手,他们在第一个版本中做得很好。很高兴看到他们在这里采用什么形式,并观察该语言在服务器端的各个方面。


3

原则上,我在存储过程中使用UserDefinedVariables(以@开头)。这使工作变得更轻松,尤其是当我在两个或多个存储过程中需要这些变量时。只是当我仅需要一个存储过程中的变量时,我才使用系统变量(不带@)。

@Xybo:我不明白为什么在StoredProcedures中使用@variables应该会有风险。您能否更轻松地解释“范围”和“边界”(对我来说是新手)?


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.