当mysql返回用户变量

时间:2015-10-02 15:56:02

标签: php mysql

以下查询返回' 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 

2 个答案:

答案 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很好,因为以后会对其进行评估。)

现在这可能声音起初非常低效,因为它看起来像两次相同的昂贵计算 - 但实际上,查询优化器应该能够识别出来,所以它实际上是只计算一次。

尝试一下,看看这是否能为您提供所需的结果 - 以及它的表现。