MySQL中以下变量初始化样式有何不同?

naw*_*fal 6 mysql sql select variable-initialization variable-declaration

我对涉及MySQL中的变量声明的查询相当新.我见过各种风格,我并不完全清楚这些实际上是做什么的.我对这些实际上做了什么有疑问.

1)

set @row:=0;
SELECT name, @row:=@row + 1 AS rownum
FROM animal
Run Code Online (Sandbox Code Playgroud)

2)

SELECT name, @row:=@row + 1 AS rownum
FROM (SELECT @row:= 0) c, animal
Run Code Online (Sandbox Code Playgroud)

两者都返回相同:

  name rownum
|| cat || 1 ||
|| cat || 2 ||
|| dog || 3 ||
|| dog || 4 ||
|| dog || 5 ||
|| ant || 6 ||
Run Code Online (Sandbox Code Playgroud)

上述两个查询有哪些不同之处,两者中的哪一个在范围,效率,编码习惯,用例方面采用了哪些?

3)现在如果我这样做:

set @row:=0;
SELECT name, @row:=@row + 1 AS rownum
FROM (SELECT @row:= 123) c, animal
Run Code Online (Sandbox Code Playgroud)

我明白了

  name  rownum
|| cat || 124 ||
|| cat || 125 ||
|| dog || 126 ||
|| dog || 127 ||
|| dog || 128 ||
|| ant || 129 ||
Run Code Online (Sandbox Code Playgroud)

那么这是不是意味着内部变量初始化会覆盖外部初始化并使后者变得多余(因此它总是更好的做法来初始化SELECT

4)如果我只是这样做:

SELECT name, @row:=@row + 1 AS rownum
FROM animal
Run Code Online (Sandbox Code Playgroud)

我明白了

   name  rownum
|| cat || NULL ||
|| cat || NULL ||
|| dog || NULL ||
|| dog || NULL ||
|| dog || NULL ||
|| ant || NULL ||
Run Code Online (Sandbox Code Playgroud)

我可以理解,因为row没有初始化.但是,如果我运行任何其他查询(可能是变量row正在初始化?)我看到row每次运行上述查询时该变量都会递增.那是它给我第一次运行的结果:

  name rownum
|| cat || 1 ||
|| cat || 2 ||
|| dog || 3 ||
|| dog || 4 ||
|| dog || 5 ||
|| ant || 6 ||
Run Code Online (Sandbox Code Playgroud)

然后在重新运行时它会产生

  name rownum
|| cat || 7  ||
|| cat || 8  ||
|| dog || 9  ||
|| dog || 10 ||
|| dog || 11 ||
|| ant || 12 ||
Run Code Online (Sandbox Code Playgroud)

所以row存储在某个地方?它的范围和寿命是多少?

5)如果我有这样的查询:

SELECT (CASE WHEN @name <> name THEN @row:=1 ELSE @row:=@row + 1 END) AS rownum, 
       @name:=name AS name
FROM animal
Run Code Online (Sandbox Code Playgroud)

这总能产生正确的结果:

rownum  name
|| 1 || cat ||
|| 2 || cat ||
|| 1 || dog ||
|| 2 || dog ||
|| 3 || dog ||
|| 1 || ant ||
Run Code Online (Sandbox Code Playgroud)

那么这是不是意味着它并不总是需要在顶部或SELECT依赖于查询初始化变量?

MvG*_*MvG 11

请务必阅读有关用户变量手册部分.

上述两个查询有哪些不同之处,两者中的哪一个在范围,效率,编码习惯,用例方面采用了哪些?

查询1)使用多个语句.因此,它可以依赖于执行这些语句的顺序,确保在变量增加之前设置变量.
另一方面,查询2)在嵌套子查询中进行初始化.这将整个事件转变为单个查询.您不会忘记忘记初始化.但是代码更依赖于mysql服务器的内部工作,特别是在它开始计算外部查询的结果之前它将执行子查询.

那么这是不是意味着内部变量初始化会覆盖外部初始化并使后者变得多余(因此它总是更好的做法来初始化SELECT

这不是关于内部和外部,而是关于顺序顺序:子查询在执行之后执行SET,因此它将简单地覆盖旧值.

行存储在哪里?它的范围和寿命是多少?

用户变量是服务器连接的本地变量.因此任何其他过程都不受设置的影响.即使是相同的进程也可以通过用户变量的独立设置来维护多个连接.关闭连接后,所有变量设置都将丢失.

那么这是不是意味着它并不总是需要在顶部或SELECT中初始化变量,具体取决于查询?

引自手册:

如果引用尚未初始化的变量,则其值为NULL和字符串类型.

因此,您可以在初始化之前使用变量,但必须小心,您可以NULL以合理的方式实际处理结果值.但请注意,您的查询5)遇到手册中明确说明的另一个问题:

作为一般规则,您不应该为用户变量赋值并在同一语句中读取值.您可能会得到您期望的结果,但这不能保证.涉及用户变量的表达式的评估顺序是未定义的,可能会根据给定语句中包含的元素进行更改; 此外,MySQL服务器版本之间的订单不保证相同.在SELECT @a, @a:=@a+1, ...,您可能认为MySQL将@a首先进行评估,然后再进行一次分配.然而,改变的声明(例如,通过添加GROUP BY,HAVINGORDER BY子句)可能引起的MySQL顺序不同的评价,选择的执行计划.

因此,在您的情况下,@name:=name部件可以在@name <> name检查之前执行,导致您的所有rownum值都相同.因此,即使它现在有效,也无法保证它将来会起作用.

请注意,我一直对以这种方式使用用户变量持怀疑态度.我已经在评论手册中引用了上述警告,并提到了几个答案.当使用用户变量对行进行编号时,我也问了一些关于保证的问题.其他用户更务实,因此更愿意使用似乎工作的代码,而没有明确保证事情将继续按预期工作.

  • @nawfal,在当前的服务器实现上,没有办法获得不同的输出.我的观点是开发人员可能会在不破坏任何规范的情况下改变它,使查询2被破坏.不确定是否可能,但我在这些方面非常小心,因为我刚刚编辑到我的答案中的注释表明. (3认同)