【问题标题】:MySQL: @variable vs. variable. What's the difference?MySQL:@variable 与变量。有什么不同?
【发布时间】:2010-11-03 20:12:53
【问题描述】:

在我发布的另一个问题中,有人告诉我:

@variable

和:

variable

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

【问题讨论】:

  • 我对 MsSQL 很熟悉,所以我从未想过要问这样的问题。这里提供的答案让我知道了一些我不知道的事情!谢谢..

标签: mysql sql variables


【解决方案1】:

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

虽然在命令行上很好,但我觉得在 MySQL 的存储过程中使用 set = @variable 是有风险的。没有范围,变量跨越范围边界。这类似于在 JavaScript 中声明的变量没有 var 前缀,然后是全局命名空间并会产生意外的冲突和覆盖。

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

MySQL 是存储过程的新手,他们的第一个版本做得很好。很高兴看到他们在这里采取的形式,并看到语言在服务器端方面的成熟。

【讨论】:

    【解决方案2】:

    @variable 如果从用 Java、Python 等编写的应用程序调用 存储过程 非常有用。 在某些情况下,变量值在第一次调用中创建,而在后续调用的函数中需要。

    关于 PL/SQL (Oracle) 的旁注

    优势可以在 Oracle PL/SQL 中看到,其中这些变量有 3 个不同的范围:

    • 函数变量,函数退出时作用域结束。
    • 包体变量定义在包的顶部和所有范围为会话且可见性为包的函数之外。
    • 包变量,其变量为会话,可见性为全局。

    我的 PL/SQL 经验

    我开发了一个架构,其中完整的代码是用 PL/SQL 编写的。这些是从用 Java 编写的中间件调用的。有两种类型的中间件。一种用于满足客户端的调用,该客户端也是用 Java 编写的。另一个用于满足来自浏览器的调用。 客户端工具 100% 用 Ja​​vaScript 实现。使用命令集代替 HTML 和 JavaScript 在 PL/SQL 中编写应用程序。

    我一直在寻找相同的工具将 PL/SQL 编写的代码移植到另一个数据库。我发现最近的一个是 Postgres。但是所有的变量都有函数作用域。

    对 MySQL 中 @ 的看法

    我很高兴看到至少这个@ 设施存在于MySQL 中。我认为 Oracle 不会在 PL/SQL 中为 MySQL 存储过程构建相同的设施,因为它可能会影响 Oracle 数据库的销售。

    【讨论】:

    • PLSQL (Oracle) 毫无疑问。您能否更多地关注这个问题并在 MS-SQL 或 MySQL 的上下文中详细说明 @variable,拜托!
    【解决方案3】:

    MySQL 有一个概念user-defined variables

    它们是松散类型的变量,可以在会话中的某处初始化并保持其值直到会话结束。

    它们前面带有 @ 符号,如下所示:@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或“会话变量”如@987654332 @;这些“会话变量”与特定于会话的用户定义变量无关。)

    【讨论】:

    • 另请注意,有可用的全局变量:例如,请参阅SELECT @@version;。这也是为什么使用DELIMITER @@ 并不是一个好主意的原因。
    • 它为新人提出了新的问题......您的示例中的“var = var”和“var := var”之间有什么区别吗?
    • 新人的另一个问题。什么时候推荐使用@而不是?
    • @Quassnoi 如果将用户变量定义为会话变量并设置一个值,它不会污染下一个恰好使用相同变量名的存储过程调用吗?
    • @confiq, @Quassnoi::== 之间有一个显着的区别,那就是:= 在任何地方都可以作为变量赋值运算符,而= 只能工作SET 语句中的这种方式,并且在其他任何地方都是比较运算符。所以SELECT @var = 1 + 1; 将保持@var 不变并返回一个布尔值(1 或0 取决于@var 的当前值),而SELECT @var := 1 + 1; 将@var 更改为2,并返回2。
    【解决方案4】:

    在 MySQL 中,@variable 表示 user-defined variable。你可以自己定义。

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

    在存储程序之外,没有@variablesystem variable,您无法自行定义。

    这个变量的作用域是整个会话。这意味着当您与数据库的连接存在时,该变量仍然可以使用。

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

    【讨论】:

    • 不要与会话变量混淆,会话变量的缩写为SET @@a = 'test';,参见。 dev.mysql.com/doc/refman/5.1/en/set-statement.html
    • @RobM,它们被称为系统变量,而不是会话变量。
    • @Pacerier:我读错文档了吗? """要明确指出变量是会话变量,请在其名称前加上 SESSION、@@session. 或 @@。"""
    • @RobM,你读错了。通读整个段落,而不仅仅是要点中的段落。简单来说,有两种会话变量:1)用户自定义会话变量,2)系统 自定义会话变量。您不能使用@@ 设置用户定义的会话变量。例如,set@@my_var=1set@@session.my_var=1set session my_var=1 不起作用,因为 my_var 不是 system 变量,而我们可以使用 set@@big_tables=1set@@session.big_tables=1 和 @ 987654336@ 因为big_tables 是系统变量。
    • @GovindRai:在 Quassnoi 的回答中,var2 是一个没有 @ 前缀的变量,但它不是系统变量:它是一个过程变量。这是允许的,因为它位于存储过程(也称为存储程序)中。在存储过程之外,没有@ 的变量是系统变量。
    【解决方案5】:

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

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

    【讨论】:

    • 这违反了基本的软件工程原则。在您确切知道范围是什么以及为什么使用全局变量通常是一个糟糕的想法之前,请不要编写另一行代码。当我参加 101 节编程课时,我记得几乎所有事情都使用全局变量会导致自动“F”。有特殊的例外,但作为一般规则 - 不要这样做!
    • 为什么? - @Variables 在每本 MySQL 书籍中都非常常见。
    • 当然,在没有函数调用、过程、触发器等的“平面”脚本中,如果您只是要执行那个简单的脚本或一组有限的命令,然后结束会话(从而破坏你的全局变量)。在这种情况下,如果需要,请继续使用它们。但不要在函数中使用它们!如果您只是简单地使用 Google 全局变量或范围,您会立即找到对它们普遍不赞成的想法的广泛支持。这是一个起点:wiki.c2.com/?GlobalVariablesAreBad 或更一般的解释:en.wikipedia.org/wiki/Global_variable
    • 在 MySQL 中,@variables 是全局的。这很容易证实。在函数外部设置一个,然后在一个函数内部对其进行评估。相反,在函数内部设置一个并在函数外部对其进行评估。你会看到这个函数没有保护范围之类的。他们踩着对方的脚趾。
    • 使用 MySQL 术语,@@GLOBAL 变量更加“全局”和阴险。他们跨越会议! @variables 具有“会话范围”,因此至少他们以这种方式受到限制。但是,在您所谓的“全局”范围内的任何普通语言中(当它们跨函数等时)。 MySQL 的“全局”概念或许应该被称为“通用”,因为它超越了运行它的进程的边界。 “全局”通常不能用标准语言做到这一点,因为进程不共享内存空间。这源于 SQL 的持久(相对易变)趋势。
    猜你喜欢
    • 2010-11-03
    • 2013-03-12
    • 1970-01-01
    • 2022-10-14
    • 2011-11-17
    • 1970-01-01
    • 2015-03-20
    相关资源
    最近更新 更多