由于mysql是一种声明性语言,我无法找到强制赋值变量顺序的方法。
采取此查询:
SET @v1=0;
SET @v2=0;
SELECT @v1, @v2
FROM MyTable table
WHERE (@v1:=@v2) is not null
AND (@v2:=2) is not null;
结果是:
@v1 | @v2
---------
2 | 2
这是因为mysql引擎在@ v1之前解析了@ v2。
如何强制分配顺序才能获得此结果:
@v1 | @v2
---------
0 | 2
编辑:这与以下问题不同:Variable assignment with mysql
这是一个关于强制分配顺序的问题,而不是为什么结果不是预期的结果。
更新: 当你使用左外连接时,结果也很奇怪:
SET @v1=0;
SELECT @v1
FROM Account other
LEFT OUTER JOIN SimpleValue f_PC ON f_PC.accountId=other.id AND f_PC.refShortcut='PC'
WHERE CASE WHEN (other.context='44') THEN (@v1:=@v1+1) ELSE null END
ORDER BY @v1 ASC
在这种情况下,查询返回60个结果,但@ v1值为120。
如果我删除左外连接,则v1值为60.为什么?
答案 0 :(得分:1)
在select
语句中,该子句从LEFT变为RIGHT,TOP变为BOTTOM,因此它按预期工作(MS Access使用相同的策略)。但是,在WHERE子句中,所有投注均已关闭,并且选择了最佳过滤器。您可以利用CASE语句需要从左到右评估(保留演示顺序)这一事实来强制它。
WHERE CASE WHEN (@v1:=@v2) is not null THEN (@v2:=2) ELSE (@v2:=2) = 0 END
此力是在任一分支中评估(并将2分配给@ v2),但是对于第一次运行,@ v1:= @ v2返回null,@ v2变为2,将其与0进行整体{{ 1}}。第二次,FALSE
和@v1 := @v2 [= 2]
会产生2((@v2:=2)
)。
答案 1 :(得分:0)
正如您在其他问题的答案中所解释的那样,没有任何保证能够发挥作用。
在您的特定情况下,将分配移动到查询的SELECT部分似乎有效:
SET @v1=0;
SET @v2=0;
SELECT (@v1:=@v2), (@v2:=2)
FROM DUAL
答案 2 :(得分:0)
关于您的示例。
在WHERE子句中,逻辑操作符中的常量操作可能具有最高优先级。
SET @v1=10;
SET @v2=20;
SELECT @v1, @v2
FROM dual
WHERE (@v2:=2) is not NULL AND (@v1:=@v2) is not NULL;
=======
@v1 @v2
2 2
SET @v1=30;
SET @v2=40;
SELECT @v1, @v2
FROM dual
WHERE (@v1:=@v2) is not NULL AND (@v2:=2) is not NULL;
========
@v1 @v2
2 2
以下示例清楚地证明了这一点。建议不要从左到右执行OR语句。 OR运算符首先执行常量分配操作。
SET @v1=10;
SET @v2=20;
SELECT @v1, @v2
FROM dual
WHERE (@v2:=3) is not NULL OR (@v1:=@v2+1) is not NULL;
=========
@v1 @v2
10 3
SET @v1=30;
SET @v2=40;
SELECT @v1, @v2
FROM dual
WHERE (@v1:=@v2+2) is not NULL OR (@v2:=4) is not NULL;
=========
@v1 @v2
30 4
关于分配运算符和您的问题
在这种情况下,查询返回60个结果,但@ v1值为120。 删除左外部联接,v1值为60。为什么?
为查询中使用的数据集的每一行求出WHERE子句中的赋值运算符“:=”! 反之亦然,在SELECT子句中,为结果行计算了赋值运算符,并在JOIN和WHERE子句中对行进行了正面验证。
推荐。尝试在WHERE子句中不要使用赋值运算符“:=”。在SELECT子句中使用赋值运算符。