基于三个数据库表的查询始终返回零结果

时间:2014-12-07 16:04:06

标签: php mysql

我有一个包含三个表的数据库:

地方:

id    |  name  |  latitude  | longitude  |
------|--------|------------|------------|
1     | place1 | 11.123456  | 76.123456  |
------|--------|------------|------------|
2     | place2 | 23.123456  | 65.123456  |
etc ...

categorized_places:

id    | place_id | cat_id |
------|----------|--------|
1     |    1     |   2    |
------|----------|--------|
2     |    2     |   1    |
etc ...

places_visited:

id    | user_name | user_email | place_id |
------|-----------|------------|----------|
1     |   user_1  | x@mail.com |    2     |
------|-----------|------------|----------|
2     |   user_2  | y@mail.com |    2     |

还有第四个命名的类别,但它并不重要。

我正在尝试过滤place-table中的地点,以向用户显示他/她尚未访问过的最近的地方。

$ cur_cat在上一页设置,用户可以选择他/她想要访问的地点。

$ cur_user和$ cur_user_email基于$ _SESSION变量

$ max_lat,$ max_lon,$ min_lat和$ min_lon基于用户当前位置

我在php(使用PDO)中使用此代码,但它总是返回零结果:

$get_places = $db->prepare("
    SELECT
        places.id,
        places.name,
        places.latitude,
        places.longitude
    FROM
        places,
        categorized_places,
        places_visited
    WHERE
        places.id = categorized_places.place_id
        AND categorized_places.cat_id = '$cur_cat'
        AND places.latitude <= '$max_lat'
        AND places.latitude >= '$min_lat'
        AND places.longitude <= '$max_lon'
        AND places.longitude >= '$min_lon'
        AND places_visited.user_name = '$cur_user'
        AND places_visited.user_email = '$cur_user_email'
        AND places.id != places_visited.place_id
");
$get_places->execute();

代码始终显示0结果并且不会引发错误。我也确定,这些地方不在place_visited表中。

我已经盯着这看了很长时间,而我却无法弄清楚错误。 任何帮助将非常感谢!

1 个答案:

答案 0 :(得分:0)

您的查询正在进行内部联接。因此,它只能返回用户访问过的地方。它无法返回用户未访问过的地方。在继续之前,这里有一个简单的规则:从不from子句中使用逗号。 ANSI标准显式JOIN语法已经存在了二十多年,您应该使用它。事实上,在这种情况下,你需要它,因为你需要一个外连接:

SELECT p.id, p.name, p.latitude, p.longitude
FROM places p INNER JOIN
     categorized_places cp
     ON p.id = cp.place_id LEFT JOIN
     places_visited pv
     ON pv.place_id = p.id AND
        pv.user_name = '$cur_user' AND
        pv.user_email = '$cur_user_email'          
WHERE cp.cat_id = '$cur_cat' AND
      p.latitude <= '$max_lat' AND
      p.latitude >= '$min_lat' AND
      p.longitude <= '$max_lon' AND
      p.longitude >= '$min_lon' AND
      pv.place_id IS NULL;

这样做是为了使用外部联接匹配所有访问过的地方的条件。然后条件pv.place_id IS NULL选择那些尚未访问过的条件。请注意places_visited表中的条件位于ON子句中。其他两个表的条​​件仍保留在WHERE子句中。通常,使用LEFT OUTER JOIN时,第一个表上的过滤器会保留在WHERE子句中。第二个表中的过滤器位于ON子句中。

我还介绍了表别名。这些有助于使查询更容易编写和阅读。