MvG*_*MvG 6 mysql sql variables user-variables
我经常在这里找到答案,建议使用用户变量对某些事物进行编号.也许最明显的例子是从给定结果集中选择每隔一行的查询.(这个问题和查询类似于这个答案,但是这个答案实际上引发了这个问题).
SELECT *
FROM (SELECT *, (@row := @row + 1) AS rownum
FROM (SELECT @row := 0) AS init, tablename
ORDER BY tablename.ordercol
) sub
WHERE rownum % 2 = 1
Run Code Online (Sandbox Code Playgroud)
这种方法似乎通常有效.
另一方面,MySQ文档指出:
作为一般规则,您不应该为用户变量赋值并在同一语句中读取值.您可能会得到您期望的结果,但这不能保证.涉及用户变量的表达式的评估顺序是未定义的,可能会根据给定语句中包含的元素进行更改; 此外,MySQL服务器版本之间的订单不保证相同.
所以我的问题不是如何使用当前服务器实现这样的排序,而是使用用户变量的建议解决方案是否保证在所有(合理)环境下以及所有未来版本的MySQL中都能正常工作.
通过"保证"我的意思是像MySQL文档或者一些标准的MySQL声称一致性与权威来源.缺乏这样的权威答案,可能会引用其他来源,如经常使用的教程或MySQL源代码的部分内容.通过"作品"我的意思是分配会按顺序执行,每个结果行一次,并在由产生的顺序的事实ORDER BY一致.
举个例子说明事情是否容易失败:
SELECT *
FROM (SELECT *, (@row := @row + 1) AS rownum
FROM (SELECT @row := 0) AS init, tablename
HAVING rownum > 0
ORDER BY tablename.ordercol
) sub
WHERE rownum % 2 = 1
Run Code Online (Sandbox Code Playgroud)
将在当前安装在SQL Fiddle上的MySQL 5.5.27上产生一个空结果.原因似乎是HAVING条件导致rownum表达式被评估两次,因此最终结果将只有偶数.我知道幕后发生了什么,而且我并没有声称使用它的查询HAVING很有意义.我只想证明代码之间有一个很好的界限,代码看起来非常相似但是中断.
Ric*_*iwi 10
你误解了这个陈述.它与使用多个变量时SELECT列表中的表达式顺序有关.
如上所述,此单变量语句上的ORDER BY具有保证的顺序,直到当前版本的MySQL,并且该文本中没有任何内容表明它将发生变化.
但保证未来?谁知道.
关于破解查询,你再次误解了MySQL是如何工作的.让我们分解您的查询.请注意手册中的此声明
在SELECT语句中,仅在发送到客户端时评估每个select表达式.这意味着在HAVING,GROUP BY或ORDER BY子句中,引用在select表达式列表中赋值的变量不能按预期工作
查询的处理顺序大致如下
FROM / JOIN
WHERE / ON
GROUP BY / ROLLUP
HAVING
UNION
SELECT
ORDER BY
@variable resolution
Run Code Online (Sandbox Code Playgroud)
您的"损坏"查询尝试使用相同级别的变量WITHIN,这与对列别名使用WHERE/HAVING子句一样有罪.这就是为什么你永远不会在相同的查询级别上使用变量看到基于MySQL变量的row_numbering解决方案,它总是在子查询中.外部查询可以被视为client内部查询的变量/占位符表达式在哪个阶段呈现.通过你的论证,你可以直接使用涉及@row的WHERE子句轻松打破它(是的,它会运行!).