通过HAVING按列描述中更改的变量值过滤SELECT行

时间:2012-12-11 19:09:29

标签: mysql variables select having

任何人都可以解释以下两个请求之间的差异:

SET @foundnow=0;
SELECT id, (@foundnow:=IF(`id`=3,1,0)) as ff
FROM `sometable` 
HAVING @foundnow=0
                                  result is
id  ff
1   0
2   0
3   1

SET @foundnow=0;
SELECT id, (@foundnow:=IF(`id`=3,1,0)) as ff
FROM `sometable` 
HAVING ff=0
                                  result is
id  ff
1   0
2   0
4   0
5   0
...

为什么首先给出所有行的id = 3(包括),第二行 - 所有行除了id = 3?

我猜这个问题与以下请求的“意外”行为相关

SET @tot=0;
SELECT @tot:=@tot+1 as `ff`
FROM `anytable`
HAVING (`ff`>10)

给出了ff = 12,14,16,18 ......

的行

1 个答案:

答案 0 :(得分:1)

@foundnow不是每行变量。它依然存在。创建列ff使其成为每行值。另外,来自the documentation

  

在SELECT语句中,仅在发送到客户端时评估每个select表达式。这意味着在HAVING,GROUP BY或ORDER BY子句中,引用一个在select表达式列表中赋值的变量不能按预期工作:

这意味着您的第一个示例如下:

  • 1:需要@foundrow,它是0,所以发送,将@foundrow设置为新值(0)
  • 2:有需要@foundrow,它是0,所以发送,将@foundrow设置为新值(0)
  • 3:需要@foundrow,它是0,所以发送,将@foundrow设置为新值(1)
  • 3:有需要@foundrow,它是1,不发送
  • 4:需要@foundrow,它是1,不发送
  • 5:需要@foundrow,它是1,不发送
  • 等...

你的第二个就像:

  • 1:需要ff,执行select,设置@foundrow,设置ff(=不再@foundrow)=发送
  • 2:需要ff,执行select,设置@foundrow,设置ff(=不再@foundrow)=发送
  • 3:需要ff,执行select,设置@foundrow,设置ff(=不再@foundrow)=不发送
  • 4:需要ff,执行select,设置@foundrow,设置ff(=不再@foundrow)=发送

因此,如果@foundrow!= 0,第一个示例不会评估表达式 ,因为@foundrow已知并且MySQL不关心该select表达式中的内容。第二个引用结果集中的一列,因此必须知道该结果,并执行select。

另外,如果可以使用HAVING,请避免使用WHERE条款。非常非常喜欢