以下查询返回' 5'当使用MySql Workbench运行但使用PHP返回null时,针对同一个本地apache服务器:
SELECT @distance_in_km from branch where (@distance_in_km := 5) limit 1
另一方面,当查询
时SELECT 5 as distance_in_km from branch limit 1
workbench和PHP都返回5.
我知道我可以通过修改第一个查询来解决它(通过查询得到字段distance_in_km的值为5):
SELECT 5 as distance_in_km, @distance_in_km from branch where (@distance_in_km := 5) limit 1
在这种情况下,工作台返回' 5,5'和PHP返回' 5,null'这对我来说很好,因为我使用json得到了值,所以我可以找到字段' distance_in_km'而不是' @ distance_in_km'。
然而,我的真实查询要复杂得多,我想避免计算字段' distance_in_km'两次。
编辑1
看起来好像问题在于PHP评估用户变量' distance_in_km'的方式。在进一步测试中,我发现尽管PHP返回空值,但它确实知道它的真值,因为在添加WHERE测试时,PHP会正确评估:
SELECT @distance_in_km from branch where (@distance_in_km := 5) <= 4 limit 1
PHP返回0条记录,而在上述测试中将4改为5,PHP返回1条记录。
另一方面,在添加条款&#39; ORDER BY @ distance_in_km&#39;时,PHP没有正确排序。 (它返回按主键排序的记录,显示PHP使用&#39; @ distance_in_km&#39;的空值而不是它的实际值。
编辑2
PHP版本5.5.12,Apache版本2.4.9,MYSQL版本5.6.17(全部来自wampserver 2.5菜单)。
在同一个菜单中,我打开了MySQL控制台,并运行上面的查询并从PHP获得结果。这是会议
使用控制台:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 476
Server version: 5.6.17 MySQL Community Server (GPL)
Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> use q;
Database changed
mysql> SELECT @distance_in_km from branch where (@distance_in_km := 5) limit 1;
+-----------------+
| @distance_in_km |
+-----------------+
| NULL |
+-----------------+
1 row in set (0.00 sec)
mysql> SELECT @distance_in_km from branch where (@distance_in_km := 5) <= 4 limit 1;
Empty set (0.00 sec)
mysql> SELECT @distance_in_km from branch where (@distance_in_km := 5) <= 5 limit 1;
+-----------------+
| @distance_in_km |
+-----------------+
| 5 |
+-----------------+
1 row in set (0.00 sec)
mysql>
PHP代码
$query = "SELECT @distance_in_km from branch where (@distance_in_km := 5) <= 5 limit 1";
$result = $db->query($query) or die('Err: Table not found: ' . mysql_error());
echo json_encode($result->fetch_row());
编辑3
根据@Stan建议的修改后的SELECT语句,我尝试更改我的代码,但没有成功。可以看出distance_in_km没有从分支中获得正确的值。
mysql> SELECT @distance_in_km, latitude from branch, (SELECT @distance_in_km := latitude from branch) as uservar limit 3;
+-----------------+-----------+
| @distance_in_km | latitude |
+-----------------+-----------+
| 32.0616233 | 32.180644 |
| 32.0616233 | 32.195598 |
| 32.0616233 | 32.197176 |
+-----------------+-----------+
3 rows in set (0.00 sec)
编辑4
SELECT @distance_in_km, co.*, c.*
FROM `branch` c
LEFT JOIN open_hours co ON c.open = co.id,
(SELECT @distance_in_km := 111.1111 * DEGREES(ACOS(COS(RADIANS(latitude)) *
COS(RADIANS('32.177242')) * COS(RADIANS(longitude) - RADIANS('34.863834')) + SIN(RADIANS(latitude)) *
SIN(RADIANS('32.177242')))) from branch) as uservar
WHERE c.company='1' and @distance_in_km <= 20
ORDER BY @distance_in_km LIMIT 5 OFFSET 0;
编辑5
在更好的解决方案出现之前,我结束了将计算定义为UDF(用户定义的函数),并在相同的SELECT !!!中调用它3次。非常低效,但我没有别的办法。因此SELECT现在看起来:
SELECT distance_in_km(latitude, 32.177242, longitude, 34.863834) as km, c.latitude, c.longitude, c.id FROM `branch` c
WHERE c.company='1' and distance_in_km(latitude, 32.177242, longitude, 34.863834) <= 20
ORDER BY distance_in_km(latitude, 32.177242, longitude, 34.863834) LIMIT 5 OFFSET 0
在进一步测试时,如果我在ORDER BY中使用变量km,那么看起来它也可以工作,这样我在SELECT中有两次该函数
SELECT distance_in_km(latitude, 32.177242, longitude, 34.863834) as km, c.latitude, c.longitude, c.id FROM `branch` c
WHERE c.company='1' and distance_in_km(latitude, 32.177242, longitude, 34.863834) <= 20
ORDER BY km LIMIT 5 OFFSET 0
答案 0 :(得分:2)
你应该读这个:MySQL user variables guide
特别是:
作为一般规则,除了在SET语句中,您不应该为用户变量赋值并在同一语句中读取值。例如,要增加变量,这没关系:
SET @a = @a + 1;对于其他语句,例如SELECT,您可能会得到 你期望的结果,但这不能保证。在下面的 声明,您可能会认为MySQL会首先评估@a 做第二个任务:
SELECT @ a,@ a:= @ a + 1,...;但是,评估顺序为 涉及用户变量的表达式是未定义的。
短版本:变量在您的情况下执行查询后会被绑定,因此它没有任何值。尝试在同一个会话中执行两次作为此类&#34; undefined&#34;的证明。行为。
<强> UPD:强> 如果你真的想要绑定变量并在同一个语句中使用它,你可能想尝试从子查询中选择,如下所示:
SELECT @distance_in_km from branch, (SELECT @distance_in_km := 5) as uservar limit 1
我认为这是不好的做法,但是它有效并且我明白,有时候你没有选择权,所以我认为明智地使用它。
答案 1 :(得分:1)
现在从你的编辑#4看起来,好像你在这里使用用户变量的唯一理由是你不仅要选择计算的值,还要在WHERE子句中使用它??
在这种情况下,您应该尝试在WHERE子句中重复计算(正如已经指出的那样,因为当 WHERE子句被评估时,您不能使用动态计算的别名“列“那里的值。”
SELECT
co.*,
c.*,
(111.1111 * DEGREES(ACOS(COS(RADIANS(latitude)) * …) AS distance_in_km
FROM `branch` c
LEFT JOIN open_hours co ON c.open = co.id
WHERE
c.company='1'
AND
(111.1111 * DEGREES(ACOS(COS(RADIANS(latitude)) * …) <= 20
ORDER BY distance_in_km
LIMIT 5 OFFSET 0;
(再次使用ORDER BY子句中的别名列distance_in_km
很好,因为以后会对其进行评估。)
现在这可能声音起初非常低效,因为它看起来像两次相同的昂贵计算 - 但实际上,查询优化器应该能够识别出来,所以它实际上是只计算一次。
尝试一下,看看这是否能为您提供所需的结果 - 以及它的表现。